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