blob: 1af541d6587b65c1594b44c450f102df92b58a9c [file] [log] [blame]
Mårten Kongstadeabc9e92015-12-15 16:40:23 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.om;
18
19import static android.app.AppGlobals.getPackageManager;
20import static android.content.Intent.ACTION_PACKAGE_ADDED;
21import static android.content.Intent.ACTION_PACKAGE_CHANGED;
22import static android.content.Intent.ACTION_PACKAGE_REMOVED;
23import static android.content.Intent.ACTION_USER_REMOVED;
24import static android.content.pm.PackageManager.SIGNATURE_MATCH;
25
26import android.annotation.NonNull;
27import android.annotation.Nullable;
28import android.app.ActivityManager;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010029import android.app.IActivityManager;
30import android.content.BroadcastReceiver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.IntentFilter;
34import android.content.om.IOverlayManager;
35import android.content.om.OverlayInfo;
36import android.content.pm.IPackageManager;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManagerInternal;
39import android.content.pm.UserInfo;
40import android.net.Uri;
41import android.os.Binder;
42import android.os.Environment;
43import android.os.IBinder;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010044import android.os.RemoteException;
45import android.os.ResultReceiver;
46import android.os.ShellCallback;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080047import android.os.SystemProperties;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010048import android.os.UserHandle;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080049import android.text.TextUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010050import android.util.ArrayMap;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080051import android.util.ArraySet;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010052import android.util.AtomicFile;
53import android.util.Slog;
54import android.util.SparseArray;
55
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080056import com.android.internal.util.ConcurrentUtils;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010057import com.android.server.FgThread;
58import com.android.server.IoThread;
59import com.android.server.LocalServices;
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080060import com.android.server.SystemServerInitThreadPool;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010061import com.android.server.SystemService;
62import com.android.server.pm.Installer;
63import com.android.server.pm.UserManagerService;
64
65import org.xmlpull.v1.XmlPullParserException;
66
67import java.io.File;
68import java.io.FileDescriptor;
69import java.io.FileInputStream;
70import java.io.FileOutputStream;
71import java.io.IOException;
72import java.io.PrintWriter;
73import java.util.ArrayList;
74import java.util.Collections;
75import java.util.HashMap;
76import java.util.List;
77import java.util.Map;
Adam Lesinskia5ca6242017-03-01 15:45:12 -080078import java.util.Set;
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -080079import java.util.concurrent.Future;
Mårten Kongstadeabc9e92015-12-15 16:40:23 +010080import java.util.concurrent.atomic.AtomicBoolean;
81
82/**
83 * Service to manage asset overlays.
84 *
85 * <p>Asset overlays are additional resources that come from apks loaded
86 * alongside the system and app apks. This service, the OverlayManagerService
87 * (OMS), tracks which installed overlays to use and provides methods to change
88 * this. Changes propagate to running applications as part of the Activity
89 * lifecycle. This allows Activities to reread their resources at a well
90 * defined point.</p>
91 *
92 * <p>By itself, the OMS will not change what overlays should be active.
93 * Instead, it is only responsible for making sure that overlays *can* be used
94 * from a technical and security point of view and to activate overlays in
95 * response to external requests. The responsibility to toggle overlays on and
96 * off lies within components that implement different use-cases such as themes
97 * or dynamic customization.</p>
98 *
99 * <p>The OMS receives input from three sources:</p>
100 *
101 * <ul>
102 * <li>Callbacks from the SystemService class, specifically when the
103 * Android framework is booting and when the end user switches Android
104 * users.</li>
105 *
106 * <li>Intents from the PackageManagerService (PMS). Overlays are regular
107 * apks, and whenever a package is installed (or removed, or has a
108 * component enabled or disabled), the PMS broadcasts this as an intent.
109 * When the OMS receives one of these intents, it updates its internal
110 * representation of the available overlays and, if there was a visible
111 * change, triggers an asset refresh in the affected apps.</li>
112 *
113 * <li>External requests via the {@link IOverlayManager AIDL interface}.
114 * The interface allows clients to read information about the currently
115 * available overlays, change whether an overlay should be used or not, and
116 * change the relative order in which overlay packages are loaded.
117 * Read-access is granted if the request targets the same Android user as
118 * the caller runs as, or if the caller holds the
119 * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
120 * caller is granted read-access and additionaly holds the
121 * CHANGE_OVERLAY_PACKAGES permission.</li>
122 * </ul>
123 *
124 * <p>The AIDL interface works with String package names, int user IDs, and
125 * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
126 * specific pair of target and overlay packages and include information such as
127 * the current state of the overlay. OverlayInfo objects are immutable.</p>
128 *
129 * <p>Internally, OverlayInfo objects are maintained by the
130 * OverlayManagerSettings class. The OMS and its helper classes are notified of
131 * changes to the settings by the OverlayManagerSettings.ChangeListener
132 * callback interface. The file /data/system/overlays.xml is used to persist
133 * the settings.</p>
134 *
135 * <p>Creation and deletion of idmap files are handled by the IdmapManager
136 * class.</p>
137 *
138 * <p>The following is an overview of OMS and its related classes. Note how box
139 * (2) does the heavy lifting, box (1) interacts with the Android framework,
140 * and box (3) replaces box (1) during unit testing.</p>
141 *
142 * <pre>
143 * Android framework
144 * | ^
145 * . . . | . . . . | . . . .
146 * . | | .
147 * . AIDL, broadcasts .
148 * . intents | .
149 * . | | . . . . . . . . . . . .
150 * . v | . .
151 * . OverlayManagerService . OverlayManagerTests .
152 * . \ . / .
153 * . (1) \ . / (3) .
154 * . . . . . . . . . . \ . . . / . . . . . . . . .
155 * . \ / .
156 * . (2) \ / .
157 * . OverlayManagerServiceImpl .
158 * . | | .
159 * . | | .
160 * . OverlayManagerSettings IdmapManager .
161 * . .
162 * . . . . . . . . . . . . . . . . . . . . . .
163 * </pre>
164 *
165 * <p>Finally, here is a list of keywords used in the OMS context.</p>
166 *
167 * <ul>
168 * <li><b>target [package]</b> -- A regular apk that may have its resource
169 * pool extended by zero or more overlay packages.</li>
170 *
171 * <li><b>overlay [package]</b> -- An apk that provides additional
172 * resources to another apk.</li>
173 *
174 * <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
175 *
176 * <li><b>approved</b> -- An overlay is approved if the OMS has verified
177 * that it can be used technically speaking (its target package is
178 * installed, at least one resource name in both packages match, the
179 * idmap was created, etc) and that it is secure to do so. External
180 * clients can not change this state.</li>
181 *
182 * <li><b>not approved</b> -- The opposite of approved.</li>
183 *
184 * <li><b>enabled</b> -- An overlay currently in active use and thus part
185 * of resource lookups. This requires the overlay to be approved. Only
186 * external clients can change this state.</li>
187 *
188 * <li><b>disabled</b> -- The opposite of enabled.</li>
189 *
190 * <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
191 * used during resource lookup. Also the name of the binary that creates
192 * the mapping.</li>
193 * </ul>
194 */
195public final class OverlayManagerService extends SystemService {
196
197 static final String TAG = "OverlayManager";
198
199 static final boolean DEBUG = false;
200
201 static final String PERMISSION_DENIED = "Operation not permitted for user shell";
202
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800203 /**
204 * The system property that specifies the default overlays to apply.
205 * This is a semicolon separated list of package names.
206 *
207 * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
208 */
209 private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
210
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100211 private final Object mLock = new Object();
212
213 private final AtomicFile mSettingsFile;
214
215 private final PackageManagerHelper mPackageManager;
216
217 private final UserManagerService mUserManager;
218
219 private final OverlayManagerSettings mSettings;
220
221 private final OverlayManagerServiceImpl mImpl;
222
223 private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
224
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800225 private Future<?> mInitCompleteSignal;
226
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100227 public OverlayManagerService(@NonNull final Context context,
228 @NonNull final Installer installer) {
229 super(context);
230 mSettingsFile =
231 new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml"));
232 mPackageManager = new PackageManagerHelper();
233 mUserManager = UserManagerService.getInstance();
234 IdmapManager im = new IdmapManager(installer);
235 mSettings = new OverlayManagerSettings();
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800236 mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
237 getDefaultOverlayPackages());
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800238 mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
239 final IntentFilter packageFilter = new IntentFilter();
240 packageFilter.addAction(ACTION_PACKAGE_ADDED);
241 packageFilter.addAction(ACTION_PACKAGE_CHANGED);
242 packageFilter.addAction(ACTION_PACKAGE_REMOVED);
243 packageFilter.addDataScheme("package");
244 getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
245 packageFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100246
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800247 final IntentFilter userFilter = new IntentFilter();
248 userFilter.addAction(ACTION_USER_REMOVED);
249 getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
250 userFilter, null, null);
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100251
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800252 restoreSettings();
253 onSwitchUser(UserHandle.USER_SYSTEM);
254 schedulePersistSettings();
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100255
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800256 mSettings.addChangeListener(new OverlayChangeListener());
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100257
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800258 publishBinderService(Context.OVERLAY_SERVICE, mService);
259 publishLocalService(OverlayManagerService.class, this);
260 }, "Init OverlayManagerService");
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100261 }
262
263 @Override
264 public void onStart() {
265 // Intentionally left empty.
266 }
267
268 @Override
Fyodor Kupolov94ab1a62017-03-06 14:28:20 -0800269 public void onBootPhase(int phase) {
270 if (phase == PHASE_SYSTEM_SERVICES_READY) {
271 ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
272 "Wait for OverlayManagerService init");
273 mInitCompleteSignal = null;
274 }
275 }
276
277 @Override
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100278 public void onSwitchUser(final int newUserId) {
279 // ensure overlays in the settings are up-to-date, and propagate
280 // any asset changes to the rest of the system
281 final List<String> targets;
282 synchronized (mLock) {
283 targets = mImpl.onSwitchUser(newUserId);
284 }
285 updateAssets(newUserId, targets);
286 }
287
Adam Lesinskia5ca6242017-03-01 15:45:12 -0800288 private static Set<String> getDefaultOverlayPackages() {
289 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
290 if (TextUtils.isEmpty(str)) {
291 return Collections.emptySet();
292 }
293
294 final ArraySet<String> defaultPackages = new ArraySet<>();
295 for (String packageName : str.split(";")) {
296 if (!TextUtils.isEmpty(packageName)) {
297 defaultPackages.add(packageName);
298 }
299 }
300 return defaultPackages;
301 }
302
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100303 private final class PackageReceiver extends BroadcastReceiver {
304 @Override
305 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
306 final Uri data = intent.getData();
307 if (data == null) {
308 Slog.e(TAG, "Cannot handle package broadcast with null data");
309 return;
310 }
311 final String packageName = data.getSchemeSpecificPart();
312
313 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
314
315 final int[] userIds;
316 final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
317 if (extraUid == UserHandle.USER_NULL) {
318 userIds = mUserManager.getUserIds();
319 } else {
320 userIds = new int[] { UserHandle.getUserId(extraUid) };
321 }
322
323 switch (intent.getAction()) {
324 case ACTION_PACKAGE_ADDED:
325 if (replacing) {
326 onPackageUpgraded(packageName, userIds);
327 } else {
328 onPackageAdded(packageName, userIds);
329 }
330 break;
331 case ACTION_PACKAGE_CHANGED:
332 onPackageChanged(packageName, userIds);
333 break;
334 case ACTION_PACKAGE_REMOVED:
335 if (replacing) {
336 onPackageUpgrading(packageName, userIds);
337 } else {
338 onPackageRemoved(packageName, userIds);
339 }
340 break;
341 default:
342 // do nothing
343 break;
344 }
345 }
346
347 private void onPackageAdded(@NonNull final String packageName,
348 @NonNull final int[] userIds) {
349 for (final int userId : userIds) {
350 synchronized (mLock) {
351 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
352 if (pi != null) {
353 mPackageManager.cachePackageInfo(packageName, userId, pi);
354 if (!isOverlayPackage(pi)) {
355 mImpl.onTargetPackageAdded(packageName, userId);
356 } else {
357 mImpl.onOverlayPackageAdded(packageName, userId);
358 }
359 }
360 }
361 }
362 }
363
364 private void onPackageChanged(@NonNull final String packageName,
365 @NonNull final int[] userIds) {
366 for (int userId : userIds) {
367 synchronized (mLock) {
368 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
369 if (pi != null) {
370 mPackageManager.cachePackageInfo(packageName, userId, pi);
371 if (!isOverlayPackage(pi)) {
372 mImpl.onTargetPackageChanged(packageName, userId);
373 } else {
374 mImpl.onOverlayPackageChanged(packageName, userId);
375 }
376 }
377 }
378 }
379 }
380
381 private void onPackageUpgrading(@NonNull final String packageName,
382 @NonNull final int[] userIds) {
383 for (int userId : userIds) {
384 synchronized (mLock) {
385 mPackageManager.forgetPackageInfo(packageName, userId);
386 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
387 if (oi == null) {
388 mImpl.onTargetPackageUpgrading(packageName, userId);
389 } else {
390 mImpl.onOverlayPackageUpgrading(packageName, userId);
391 }
392 }
393 }
394 }
395
396 private void onPackageUpgraded(@NonNull final String packageName,
397 @NonNull final int[] userIds) {
398 for (int userId : userIds) {
399 synchronized (mLock) {
400 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false);
401 if (pi != null) {
402 mPackageManager.cachePackageInfo(packageName, userId, pi);
403 if (!isOverlayPackage(pi)) {
404 mImpl.onTargetPackageUpgraded(packageName, userId);
405 } else {
406 mImpl.onOverlayPackageUpgraded(packageName, userId);
407 }
408 }
409 }
410 }
411 }
412
413 private void onPackageRemoved(@NonNull final String packageName,
414 @NonNull final int[] userIds) {
415 for (int userId : userIds) {
416 synchronized (mLock) {
417 mPackageManager.forgetPackageInfo(packageName, userId);
418 final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
419 if (oi == null) {
420 mImpl.onTargetPackageRemoved(packageName, userId);
421 } else {
422 mImpl.onOverlayPackageRemoved(packageName, userId);
423 }
424 }
425 }
426 }
427 }
428
429 private final class UserReceiver extends BroadcastReceiver {
430 @Override
431 public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
432 switch (intent.getAction()) {
433 case ACTION_USER_REMOVED:
434 final int userId =
435 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
436 if (userId != UserHandle.USER_NULL) {
437 synchronized (mLock) {
438 mImpl.onUserRemoved(userId);
439 mPackageManager.forgetAllPackageInfos(userId);
440 }
441 }
442 break;
443 default:
444 // do nothing
445 break;
446 }
447 }
448 }
449
450 private final IBinder mService = new IOverlayManager.Stub() {
451 @Override
452 public Map<String, List<OverlayInfo>> getAllOverlays(int userId)
453 throws RemoteException {
454 userId = handleIncomingUser(userId, "getAllOverlays");
455
456 synchronized (mLock) {
457 return mImpl.getOverlaysForUser(userId);
458 }
459 }
460
461 @Override
462 public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
463 int userId) throws RemoteException {
464 userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
465 if (targetPackageName == null) {
466 return Collections.emptyList();
467 }
468
469 synchronized (mLock) {
470 return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
471 }
472 }
473
474 @Override
475 public OverlayInfo getOverlayInfo(@Nullable final String packageName,
476 int userId) throws RemoteException {
477 userId = handleIncomingUser(userId, "getOverlayInfo");
478 if (packageName == null) {
479 return null;
480 }
481
482 synchronized (mLock) {
483 return mImpl.getOverlayInfo(packageName, userId);
484 }
485 }
486
487 @Override
488 public boolean setEnabled(@Nullable final String packageName, final boolean enable,
489 int userId) throws RemoteException {
490 enforceChangeOverlayPackagesPermission("setEnabled");
491 userId = handleIncomingUser(userId, "setEnabled");
492 if (packageName == null) {
493 return false;
494 }
495
496 final long ident = Binder.clearCallingIdentity();
497 try {
498 synchronized (mLock) {
499 return mImpl.setEnabled(packageName, enable, userId);
500 }
501 } finally {
502 Binder.restoreCallingIdentity(ident);
503 }
504 }
505
506 @Override
507 public boolean setPriority(@Nullable final String packageName,
508 @Nullable final String parentPackageName, int userId) throws RemoteException {
509 enforceChangeOverlayPackagesPermission("setPriority");
510 userId = handleIncomingUser(userId, "setPriority");
511 if (packageName == null || parentPackageName == null) {
512 return false;
513 }
514
515 final long ident = Binder.clearCallingIdentity();
516 try {
517 synchronized (mLock) {
518 return mImpl.setPriority(packageName, parentPackageName, userId);
519 }
520 } finally {
521 Binder.restoreCallingIdentity(ident);
522 }
523 }
524
525 @Override
526 public boolean setHighestPriority(@Nullable final String packageName, int userId)
527 throws RemoteException {
528 enforceChangeOverlayPackagesPermission("setHighestPriority");
529 userId = handleIncomingUser(userId, "setHighestPriority");
530 if (packageName == null) {
531 return false;
532 }
533
534 final long ident = Binder.clearCallingIdentity();
535 try {
536 synchronized (mLock) {
537 return mImpl.setHighestPriority(packageName, userId);
538 }
539 } finally {
540 Binder.restoreCallingIdentity(ident);
541 }
542 }
543
544 @Override
545 public boolean setLowestPriority(@Nullable final String packageName, int userId)
546 throws RemoteException {
547 enforceChangeOverlayPackagesPermission("setLowestPriority");
548 userId = handleIncomingUser(userId, "setLowestPriority");
549 if (packageName == null) {
550 return false;
551 }
552
553 final long ident = Binder.clearCallingIdentity();
554 try {
555 synchronized (mLock) {
556 return mImpl.setLowestPriority(packageName, userId);
557 }
558 } finally {
559 Binder.restoreCallingIdentity(ident);
560 }
561 }
562
563 @Override
564 public void onShellCommand(@NonNull final FileDescriptor in,
565 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
566 @NonNull final String[] args, @NonNull final ShellCallback callback,
567 @NonNull final ResultReceiver resultReceiver) {
568 (new OverlayManagerShellCommand(this)).exec(
569 this, in, out, err, args, callback, resultReceiver);
570 }
571
572 @Override
573 protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw,
574 @NonNull final String[] argv) {
575 enforceDumpPermission("dump");
576
577 final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]);
578
579 synchronized (mLock) {
580 mImpl.onDump(pw);
581 mPackageManager.dump(pw, verbose);
582 }
583 }
584
585 /**
586 * Ensure that the caller has permission to interact with the given userId.
587 * If the calling user is not the same as the provided user, the caller needs
588 * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
589 * root).
590 *
591 * @param userId the user to interact with
592 * @param message message for any SecurityException
593 */
594 private int handleIncomingUser(final int userId, @NonNull final String message) {
595 return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
596 Binder.getCallingUid(), userId, false, true, message, null);
597 }
598
599 /**
600 * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
601 * system or root).
602 *
603 * @param message used as message if SecurityException is thrown
604 * @throws SecurityException if the permission check fails
605 */
606 private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
607 getContext().enforceCallingOrSelfPermission(
608 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
609 }
610
611 /**
612 * Enforce that the caller holds the DUMP permission (or is system or root).
613 *
614 * @param message used as message if SecurityException is thrown
615 * @throws SecurityException if the permission check fails
616 */
617 private void enforceDumpPermission(@NonNull final String message) {
618 getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
619 message);
620 }
621 };
622
623 private boolean isOverlayPackage(@NonNull final PackageInfo pi) {
624 return pi != null && pi.overlayTarget != null;
625 }
626
627 private final class OverlayChangeListener implements OverlayManagerSettings.ChangeListener {
628 @Override
629 public void onSettingsChanged() {
630 schedulePersistSettings();
631 }
632
633 @Override
634 public void onOverlayAdded(@NonNull final OverlayInfo oi) {
635 scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled());
636 }
637
638 @Override
639 public void onOverlayRemoved(@NonNull final OverlayInfo oi) {
640 scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled());
641 }
642
643 @Override
644 public void onOverlayChanged(@NonNull final OverlayInfo oi,
645 @NonNull final OverlayInfo oldOi) {
646 scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, oi.isEnabled() != oldOi.isEnabled());
647 }
648
649 @Override
650 public void onOverlayPriorityChanged(@NonNull final OverlayInfo oi) {
651 scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled());
652 }
653
654 private void scheduleBroadcast(@NonNull final String action, @NonNull final OverlayInfo oi,
655 final boolean doUpdate) {
656 FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate));
657 }
658
659 private final class BroadcastRunnable implements Runnable {
660 private final String mAction;
661 private final OverlayInfo mOverlayInfo;
662 private final boolean mDoUpdate;
663
664 BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi,
665 final boolean doUpdate) {
666 mAction = action;
667 mOverlayInfo = oi;
668 mDoUpdate = doUpdate;
669 }
670
671 @Override
672 public void run() {
673 if (mDoUpdate) {
674 updateAssets(mOverlayInfo.userId, mOverlayInfo.targetPackageName);
675 }
676 sendBroadcast(mAction, mOverlayInfo.targetPackageName, mOverlayInfo.packageName,
677 mOverlayInfo.userId);
678 }
679
680 private void sendBroadcast(@NonNull final String action,
681 @NonNull final String targetPackageName, @NonNull final String packageName,
682 final int userId) {
683 final Intent intent = new Intent(action, Uri.fromParts("package",
684 String.format("%s/%s", targetPackageName, packageName), null));
685 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
686 if (DEBUG) {
687 Slog.d(TAG, String.format("send broadcast %s", intent));
688 }
689 try {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200690 ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100691 null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
692 userId);
693 } catch (RemoteException e) {
694 // Intentionally left empty.
695 }
696 }
697
698 }
699 }
700
701 private void updateAssets(final int userId, final String targetPackageName) {
702 final List<String> list = new ArrayList<>();
703 list.add(targetPackageName);
704 updateAssets(userId, list);
705 }
706
707 private void updateAssets(final int userId, List<String> targetPackageNames) {
Mårten Kongstad2e0d0f32016-06-02 09:35:31 +0200708 final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
709 final boolean updateFrameworkRes = targetPackageNames.contains("android");
710 if (updateFrameworkRes) {
711 targetPackageNames = pm.getTargetPackageNames(userId);
712 }
713
714 final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
715 synchronized (mLock) {
716 final int N = targetPackageNames.size();
717 for (int i = 0; i < N; i++) {
718 final String targetPackageName = targetPackageNames.get(i);
719 pendingChanges.put(targetPackageName,
720 mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
721 }
722 }
723
724 final int N = targetPackageNames.size();
725 for (int i = 0; i < N; i++) {
726 final String targetPackageName = targetPackageNames.get(i);
727 if (!pm.setEnabledOverlayPackages(
728 userId, targetPackageName, pendingChanges.get(targetPackageName))) {
729 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
730 targetPackageName, userId));
731 }
732 }
733
734 final IActivityManager am = ActivityManager.getService();
735 try {
736 am.scheduleApplicationInfoChanged(targetPackageNames, userId);
737 } catch (RemoteException e) {
738 // Intentionally left empty.
739 }
Mårten Kongstadeabc9e92015-12-15 16:40:23 +0100740 }
741
742 private void schedulePersistSettings() {
743 if (mPersistSettingsScheduled.getAndSet(true)) {
744 return;
745 }
746 IoThread.getHandler().post(new Runnable() {
747 @Override
748 public void run() {
749 mPersistSettingsScheduled.set(false);
750 synchronized (mLock) {
751 FileOutputStream stream = null;
752 try {
753 stream = mSettingsFile.startWrite();
754 mSettings.persist(stream);
755 mSettingsFile.finishWrite(stream);
756 } catch (IOException | XmlPullParserException e) {
757 mSettingsFile.failWrite(stream);
758 Slog.e(TAG, "failed to persist overlay state", e);
759 }
760 }
761 }
762 });
763 }
764
765 private void restoreSettings() {
766 synchronized (mLock) {
767 if (!mSettingsFile.getBaseFile().exists()) {
768 return;
769 }
770 try (final FileInputStream stream = mSettingsFile.openRead()) {
771 mSettings.restore(stream);
772
773 // We might have data for dying users if the device was
774 // restarted before we received USER_REMOVED. Remove data for
775 // users that will not exist after the system is ready.
776
777 final List<UserInfo> deadUsers = getDeadUsers();
778 final int N = deadUsers.size();
779 for (int i = 0; i < N; i++) {
780 final UserInfo deadUser = deadUsers.get(i);
781 final int userId = deadUser.getUserHandle().getIdentifier();
782 mSettings.removeUser(userId);
783 }
784 } catch (IOException | XmlPullParserException e) {
785 Slog.e(TAG, "failed to restore overlay state", e);
786 }
787 }
788 }
789
790 private List<UserInfo> getDeadUsers() {
791 final List<UserInfo> users = mUserManager.getUsers(false);
792 final List<UserInfo> onlyLiveUsers = mUserManager.getUsers(true);
793 users.removeAll(onlyLiveUsers);
794 return users;
795 }
796
797 private static final class PackageManagerHelper implements
798 OverlayManagerServiceImpl.PackageManagerHelper {
799
800 private final IPackageManager mPackageManager;
801 private final PackageManagerInternal mPackageManagerInternal;
802
803 // Use a cache for performance and for consistency within OMS: because
804 // additional PACKAGE_* intents may be delivered while we process an
805 // intent, querying the PackageManagerService for the actual current
806 // state may lead to contradictions within OMS. Better then to lag
807 // behind until all pending intents have been processed.
808 private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
809
810 PackageManagerHelper() {
811 mPackageManager = getPackageManager();
812 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
813 }
814
815 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
816 final boolean useCache) {
817 if (useCache) {
818 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
819 if (cachedPi != null) {
820 return cachedPi;
821 }
822 }
823 try {
824 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
825 if (useCache && pi != null) {
826 cachePackageInfo(packageName, userId, pi);
827 }
828 return pi;
829 } catch (RemoteException e) {
830 // Intentionally left empty.
831 }
832 return null;
833 }
834
835 @Override
836 public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
837 return getPackageInfo(packageName, userId, true);
838 }
839
840 @Override
841 public boolean signaturesMatching(@NonNull final String packageName1,
842 @NonNull final String packageName2, final int userId) {
843 // The package manager does not support different versions of packages
844 // to be installed for different users: ignore userId for now.
845 try {
846 return mPackageManager.checkSignatures(packageName1, packageName2) == SIGNATURE_MATCH;
847 } catch (RemoteException e) {
848 // Intentionally left blank
849 }
850 return false;
851 }
852
853 @Override
854 public List<PackageInfo> getOverlayPackages(final int userId) {
855 return mPackageManagerInternal.getOverlayPackages(userId);
856 }
857
858 public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
859 final int userId) {
860 final HashMap<String, PackageInfo> map = mCache.get(userId);
861 return map == null ? null : map.get(packageName);
862 }
863
864 public void cachePackageInfo(@NonNull final String packageName, final int userId,
865 @NonNull final PackageInfo pi) {
866 HashMap<String, PackageInfo> map = mCache.get(userId);
867 if (map == null) {
868 map = new HashMap<>();
869 mCache.put(userId, map);
870 }
871 map.put(packageName, pi);
872 }
873
874 public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
875 final HashMap<String, PackageInfo> map = mCache.get(userId);
876 if (map == null) {
877 return;
878 }
879 map.remove(packageName);
880 if (map.isEmpty()) {
881 mCache.delete(userId);
882 }
883 }
884
885 public void forgetAllPackageInfos(final int userId) {
886 mCache.delete(userId);
887 }
888
889 private static final String TAB1 = " ";
890 private static final String TAB2 = TAB1 + TAB1;
891
892 public void dump(@NonNull final PrintWriter pw, final boolean verbose) {
893 pw.println("PackageInfo cache");
894
895 if (!verbose) {
896 int count = 0;
897 final int N = mCache.size();
898 for (int i = 0; i < N; i++) {
899 final int userId = mCache.keyAt(i);
900 count += mCache.get(userId).size();
901 }
902 pw.println(TAB1 + count + " package(s)");
903 return;
904 }
905
906 if (mCache.size() == 0) {
907 pw.println(TAB1 + "<empty>");
908 return;
909 }
910
911 final int N = mCache.size();
912 for (int i = 0; i < N; i++) {
913 final int userId = mCache.keyAt(i);
914 pw.println(TAB1 + "User " + userId);
915 final HashMap<String, PackageInfo> map = mCache.get(userId);
916 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
917 pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
918 }
919 }
920 }
921 }
922}