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