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