• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_OVERLAY_CHANGED;
21 import static android.content.Intent.ACTION_USER_ADDED;
22 import static android.content.Intent.ACTION_USER_REMOVED;
23 import static android.content.Intent.EXTRA_PACKAGE_NAME;
24 import static android.content.Intent.EXTRA_REASON;
25 import static android.content.Intent.EXTRA_USER_ID;
26 import static android.content.om.OverlayManagerTransaction.Request.TYPE_REGISTER_FABRICATED;
27 import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_DISABLED;
28 import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_ENABLED;
29 import static android.content.om.OverlayManagerTransaction.Request.TYPE_UNREGISTER_FABRICATED;
30 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
31 import static android.os.Process.INVALID_UID;
32 import static android.os.Trace.TRACE_TAG_RRO;
33 import static android.os.Trace.traceBegin;
34 import static android.os.Trace.traceEnd;
35 
36 import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
37 
38 import android.annotation.NonNull;
39 import android.annotation.Nullable;
40 import android.annotation.UserIdInt;
41 import android.app.ActivityManager;
42 import android.app.ActivityManagerInternal;
43 import android.app.IActivityManager;
44 import android.content.BroadcastReceiver;
45 import android.content.Context;
46 import android.content.Intent;
47 import android.content.IntentFilter;
48 import android.content.om.IOverlayManager;
49 import android.content.om.OverlayConstraint;
50 import android.content.om.OverlayIdentifier;
51 import android.content.om.OverlayInfo;
52 import android.content.om.OverlayManagerTransaction;
53 import android.content.om.OverlayManagerTransaction.Request;
54 import android.content.om.OverlayableInfo;
55 import android.content.pm.IPackageManager;
56 import android.content.pm.PackageManagerInternal;
57 import android.content.pm.UserInfo;
58 import android.content.pm.UserPackage;
59 import android.content.pm.overlay.OverlayPaths;
60 import android.content.res.ApkAssets;
61 import android.net.Uri;
62 import android.os.Binder;
63 import android.os.Build;
64 import android.os.Bundle;
65 import android.os.Environment;
66 import android.os.FabricatedOverlayInternal;
67 import android.os.HandlerThread;
68 import android.os.IBinder;
69 import android.os.Process;
70 import android.os.RemoteException;
71 import android.os.ResultReceiver;
72 import android.os.ShellCallback;
73 import android.os.SystemProperties;
74 import android.os.UserHandle;
75 import android.os.UserManager;
76 import android.text.TextUtils;
77 import android.util.ArrayMap;
78 import android.util.ArraySet;
79 import android.util.AtomicFile;
80 import android.util.EventLog;
81 import android.util.Slog;
82 import android.util.SparseArray;
83 
84 import com.android.internal.annotations.GuardedBy;
85 import com.android.internal.content.PackageMonitor;
86 import com.android.internal.content.om.OverlayConfig;
87 import com.android.internal.util.ArrayUtils;
88 import com.android.internal.util.CollectionUtils;
89 import com.android.server.FgThread;
90 import com.android.server.LocalServices;
91 import com.android.server.SystemConfig;
92 import com.android.server.SystemService;
93 import com.android.server.pm.KnownPackages;
94 import com.android.server.pm.UserManagerInternal;
95 import com.android.server.pm.UserManagerService;
96 import com.android.server.pm.pkg.PackageState;
97 
98 import libcore.util.EmptyArray;
99 
100 import org.xmlpull.v1.XmlPullParserException;
101 
102 import java.io.File;
103 import java.io.FileDescriptor;
104 import java.io.FileInputStream;
105 import java.io.FileOutputStream;
106 import java.io.IOException;
107 import java.io.PrintWriter;
108 import java.util.ArrayList;
109 import java.util.Arrays;
110 import java.util.Collection;
111 import java.util.Collections;
112 import java.util.HashSet;
113 import java.util.Iterator;
114 import java.util.List;
115 import java.util.Map;
116 import java.util.Objects;
117 import java.util.Set;
118 
119 /**
120  * Service to manage asset overlays.
121  *
122  * <p>Asset overlays are additional resources that come from apks loaded
123  * alongside the system and app apks. This service, the OverlayManagerService
124  * (OMS), tracks which installed overlays to use and provides methods to change
125  * this. Changes propagate to running applications as part of the Activity
126  * lifecycle. This allows Activities to reread their resources at a well
127  * defined point.</p>
128  *
129  * <p>By itself, the OMS will not change what overlays should be active.
130  * Instead, it is only responsible for making sure that overlays *can* be used
131  * from a technical and security point of view and to activate overlays in
132  * response to external requests. The responsibility to toggle overlays on and
133  * off lies within components that implement different use-cases such as themes
134  * or dynamic customization.</p>
135  *
136  * <p>The OMS receives input from three sources:</p>
137  *
138  * <ul>
139  *     <li>Callbacks from the SystemService class, specifically when the
140  *     Android framework is booting and when the end user switches Android
141  *     users.</li>
142  *
143  *     <li>Intents from the PackageManagerService (PMS). Overlays are regular
144  *     apks, and whenever a package is installed (or removed, or has a
145  *     component enabled or disabled), the PMS broadcasts this as an intent.
146  *     When the OMS receives one of these intents, it updates its internal
147  *     representation of the available overlays and, if there was a visible
148  *     change, triggers an asset refresh in the affected apps.</li>
149  *
150  *     <li>External requests via the {@link IOverlayManager AIDL interface}.
151  *     The interface allows clients to read information about the currently
152  *     available overlays, change whether an overlay should be used or not, and
153  *     change the relative order in which overlay packages are loaded.
154  *     Read-access is granted if the request targets the same Android user as
155  *     the caller runs as, or if the caller holds the
156  *     INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
157  *     caller is granted read-access and additionaly holds the
158  *     CHANGE_OVERLAY_PACKAGES permission.</li>
159  * </ul>
160  *
161  * <p>The AIDL interface works with String package names, int user IDs, and
162  * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
163  * specific pair of target and overlay packages and include information such as
164  * the current state of the overlay. OverlayInfo objects are immutable.</p>
165  *
166  * <p>Internally, OverlayInfo objects are maintained by the
167  * OverlayManagerSettings class. The OMS and its helper classes are notified of
168  * changes to the settings by the OverlayManagerSettings.ChangeListener
169  * callback interface. The file /data/system/overlays.xml is used to persist
170  * the settings.</p>
171  *
172  * <p>Creation and deletion of idmap files are handled by the IdmapManager
173  * class.</p>
174  *
175  * <p>The following is an overview of OMS and its related classes. Note how box
176  * (2) does the heavy lifting, box (1) interacts with the Android framework,
177  * and box (3) replaces box (1) during unit testing.</p>
178  *
179  * <pre>
180  *         Android framework
181  *            |         ^
182  *      . . . | . . . . | . . . .
183  *     .      |         |       .
184  *     .    AIDL,   broadcasts  .
185  *     .   intents      |       .
186  *     .      |         |       . . . . . . . . . . . .
187  *     .      v         |       .                     .
188  *     .  OverlayManagerService . OverlayManagerTests .
189  *     .                  \     .     /               .
190  *     . (1)               \    .    /            (3) .
191  *      . . . . . . . . . . \ . . . / . . . . . . . . .
192  *     .                     \     /              .
193  *     . (2)                  \   /               .
194  *     .           OverlayManagerServiceImpl      .
195  *     .                  |            |          .
196  *     .                  |            |          .
197  *     . OverlayManagerSettings     IdmapManager  .
198  *     .                                          .
199  *     . . . .  . . . . . . . . . . . . . . . . . .
200  * </pre>
201  *
202  * <p>To test the OMS, execute:
203  * <code>
204  * atest FrameworksServicesTests:com.android.server.om  # internal tests
205  * atest OverlayDeviceTests OverlayHostTests            # public API tests
206  * </code>
207  * </p>
208  *
209  * <p>Finally, here is a list of keywords used in the OMS context.</p>
210  *
211  * <ul>
212  *     <li><b>target [package]</b> -- A regular apk that may have its resource
213  *     pool extended  by zero or more overlay packages.</li>
214  *
215  *     <li><b>overlay [package]</b> -- An apk that provides additional
216  *     resources to another apk.</li>
217  *
218  *     <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
219  *
220  *     <li><b>approved</b> -- An overlay is approved if the OMS has verified
221  *     that it can be used technically speaking (its target package is
222  *     installed, at least one resource name in both packages match, the
223  *     idmap was created, etc) and that it is secure to do so. External
224  *     clients can not change this state.</li>
225  *
226  *     <li><b>not approved</b> -- The opposite of approved.</li>
227  *
228  *     <li><b>enabled</b> -- An overlay currently in active use and thus part
229  *     of resource lookups. This requires the overlay to be approved. Only
230  *     external clients can change this state.</li>
231  *
232  *     <li><b>disabled</b> -- The opposite of enabled.</li>
233  *
234  *     <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
235  *     used during resource lookup. Also the name of the binary that creates
236  *     the mapping.</li>
237  * </ul>
238  */
239 public final class OverlayManagerService extends SystemService {
240     static final String TAG = "OverlayManager";
241 
242     static final boolean DEBUG = false;
243 
244     /**
245      * The system property that specifies the default overlays to apply.
246      * This is a semicolon separated list of package names.
247      *
248      * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
249      */
250     private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
251 
252     private final Object mLock = new Object();
253 
254     @GuardedBy("mLock")
255     private final AtomicFile mSettingsFile;
256 
257     private final PackageManagerHelperImpl mPackageManager;
258 
259     private final UserManagerService mUserManager;
260 
261     @GuardedBy("mLock")
262     private final OverlayManagerSettings mSettings;
263 
264     @GuardedBy("mLock")
265     private final OverlayManagerServiceImpl mImpl;
266 
267     private final OverlayActorEnforcer mActorEnforcer;
268 
269     private final PackageMonitor mPackageMonitor = new OverlayManagerPackageMonitor();
270 
271     private int mPrevStartedUserId = -1;
272 
OverlayManagerService(@onNull final Context context)273     public OverlayManagerService(@NonNull final Context context) {
274         super(context);
275         try {
276             traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
277             mSettingsFile = new AtomicFile(
278                     new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
279             mPackageManager = new PackageManagerHelperImpl(context);
280             mUserManager = UserManagerService.getInstance();
281             IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
282             mSettings = new OverlayManagerSettings();
283             mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
284                     OverlayConfig.getSystemInstance(), getDefaultOverlayPackages());
285             mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
286 
287             HandlerThread packageMonitorThread = new HandlerThread(TAG);
288             packageMonitorThread.start();
289             mPackageMonitor.register(
290                     context, packageMonitorThread.getLooper(), UserHandle.ALL, true);
291 
292             final IntentFilter userFilter = new IntentFilter();
293             userFilter.addAction(ACTION_USER_ADDED);
294             userFilter.addAction(ACTION_USER_REMOVED);
295             getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
296                     userFilter, null, null);
297 
298             UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
299             umi.addUserLifecycleListener(new UserLifecycleListener());
300 
301             // No async stuff happening in the constructor yet, so it's OK to call a ...Locked()
302             // method without a lock here.
303             restoreSettingsLocked();
304 
305             // Wipe all shell overlays on boot, to recover from a potentially broken device
306             String shellPkgName = TextUtils.emptyIfNull(
307                     getContext().getString(android.R.string.config_systemShell));
308             mSettings.removeIf(overlayInfo -> overlayInfo.isFabricated
309                     && shellPkgName.equals(overlayInfo.packageName));
310 
311             initIfNeeded();
312             onStartUser(UserHandle.USER_SYSTEM);
313 
314             publishBinderService(Context.OVERLAY_SERVICE, mService);
315             publishLocalService(OverlayManagerService.class, this);
316         } finally {
317             traceEnd(TRACE_TAG_RRO);
318         }
319     }
320 
321     @Override
onStart()322     public void onStart() {
323         // Intentionally left empty.
324     }
325 
initIfNeeded()326     private void initIfNeeded() {
327         final UserManager um = getContext().getSystemService(UserManager.class);
328         final List<UserInfo> users = um.getAliveUsers();
329         synchronized (mLock) {
330             final int userCount = users.size();
331             for (int i = 0; i < userCount; i++) {
332                 final UserInfo userInfo = users.get(i);
333                 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
334                     // Initialize any users that can't be switched to, as their state would
335                     // never be setup in onStartUser(). We will switch to the system user right
336                     // after this, and its state will be setup there.
337                     updatePackageManagerLocked(mImpl.updateOverlaysForUser(users.get(i).id));
338                 }
339             }
340         }
341     }
342 
343     @Override
onUserStarting(TargetUser user)344     public void onUserStarting(TargetUser user) {
345         onStartUser(user.getUserIdentifier());
346     }
347 
onStartUser(@serIdInt int newUserId)348     private void onStartUser(@UserIdInt int newUserId) {
349         // Do nothing when start a user that is the same as the one started previously.
350         if (newUserId == mPrevStartedUserId) {
351             return;
352         }
353         Slog.i(TAG, "Updating overlays for starting user " + newUserId);
354         try {
355             traceBegin(TRACE_TAG_RRO, "OMS#onStartUser " + newUserId);
356             // ensure overlays in the settings are up-to-date, and propagate
357             // any asset changes to the rest of the system
358             synchronized (mLock) {
359                 updateTargetPackagesLocked(mImpl.updateOverlaysForUser(newUserId));
360             }
361         } finally {
362             traceEnd(TRACE_TAG_RRO);
363         }
364         mPrevStartedUserId = newUserId;
365     }
366 
getDefaultOverlayPackages()367     private static String[] getDefaultOverlayPackages() {
368         final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
369         if (TextUtils.isEmpty(str)) {
370             return EmptyArray.STRING;
371         }
372 
373         final ArraySet<String> defaultPackages = new ArraySet<>();
374         for (String packageName : str.split(";")) {
375             if (!TextUtils.isEmpty(packageName)) {
376                 defaultPackages.add(packageName);
377             }
378         }
379         return defaultPackages.toArray(new String[0]);
380     }
381 
382     private final class OverlayManagerPackageMonitor extends PackageMonitor {
383 
384         @Override
onPackageAppearedWithExtras(String packageName, Bundle extras)385         public void onPackageAppearedWithExtras(String packageName, Bundle extras) {
386             handlePackageAdd(packageName, extras, getChangingUserId());
387         }
388 
389         @Override
onPackageChangedWithExtras(String packageName, Bundle extras)390         public void onPackageChangedWithExtras(String packageName, Bundle extras) {
391             handlePackageChange(packageName, extras, getChangingUserId());
392         }
393 
394         @Override
onPackageDisappearedWithExtras(String packageName, Bundle extras)395         public void onPackageDisappearedWithExtras(String packageName, Bundle extras) {
396             handlePackageRemove(packageName, extras, getChangingUserId());
397         }
398     }
399 
getUserIds(int uid)400     private int[] getUserIds(int uid) {
401         final int[] userIds;
402         if (uid == INVALID_UID) {
403             userIds = mUserManager.getUserIds();
404         } else {
405             userIds = new int[] { UserHandle.getUserId(uid) };
406         }
407         return userIds;
408     }
409 
410     /**
411      * Ensure that the caller has permission to interact with the given userId.
412      * If the calling user is not the same as the provided user, the caller needs
413      * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
414      * root).
415      *
416      * @param userId the user to interact with
417      * @param message message for any SecurityException
418      */
handleIncomingUser(final int userId, @NonNull final String message)419     static int handleIncomingUser(final int userId, @NonNull final String message) {
420         return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
421                 Binder.getCallingUid(), userId, false, true, message, null);
422     }
423 
handlePackageAdd(String packageName, Bundle extras, int userId)424     private void handlePackageAdd(String packageName, Bundle extras, int userId) {
425         final boolean replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
426         if (replacing) {
427             onPackageReplaced(packageName, userId);
428         } else {
429             onPackageAdded(packageName, userId);
430         }
431     }
432 
handlePackageChange(String packageName, Bundle extras, int userId)433     private void handlePackageChange(String packageName, Bundle extras, int userId) {
434         if (!ACTION_OVERLAY_CHANGED.equals(extras.getString(EXTRA_REASON))) {
435             onPackageChanged(packageName, userId);
436         }
437     }
438 
handlePackageRemove(String packageName, Bundle extras, int userId)439     private void handlePackageRemove(String packageName, Bundle extras, int userId) {
440         final boolean replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
441         final boolean systemUpdateUninstall =
442                 extras.getBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, false);
443 
444         if (replacing) {
445             onPackageReplacing(packageName, systemUpdateUninstall, userId);
446         } else {
447             onPackageRemoved(packageName, userId);
448         }
449     }
450 
onPackageAdded(@onNull final String packageName, final int userId)451     private void onPackageAdded(@NonNull final String packageName, final int userId) {
452         try {
453             traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName);
454             synchronized (mLock) {
455                 var packageState = mPackageManager.onPackageAdded(packageName, userId);
456                 if (packageState != null && !mPackageManager.isInstantApp(packageName,
457                         userId)) {
458                     try {
459                         updateTargetPackagesLocked(
460                                 mImpl.onPackageAdded(packageName, userId));
461                     } catch (OperationFailedException e) {
462                         Slog.e(TAG, "onPackageAdded internal error", e);
463                     }
464                 }
465             }
466         } finally {
467             traceEnd(TRACE_TAG_RRO);
468         }
469     }
470 
onPackageChanged(@onNull final String packageName, final int userId)471     private void onPackageChanged(@NonNull final String packageName, final int userId) {
472         try {
473             traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName);
474             synchronized (mLock) {
475                 var packageState = mPackageManager.onPackageUpdated(packageName, userId);
476                 if (packageState != null && !mPackageManager.isInstantApp(packageName,
477                         userId)) {
478                     try {
479                         updateTargetPackagesLocked(
480                                 mImpl.onPackageChanged(packageName, userId));
481                     } catch (OperationFailedException e) {
482                         Slog.e(TAG, "onPackageChanged internal error", e);
483                     }
484                 }
485             }
486         } finally {
487             traceEnd(TRACE_TAG_RRO);
488         }
489     }
490 
onPackageReplacing(@onNull final String packageName, boolean systemUpdateUninstall, final int userId)491     private void onPackageReplacing(@NonNull final String packageName,
492                                     boolean systemUpdateUninstall, final int userId) {
493         try {
494             traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplacing " + packageName);
495             synchronized (mLock) {
496                 var packageState = mPackageManager.onPackageUpdated(packageName, userId);
497                 if (packageState != null && !mPackageManager.isInstantApp(packageName,
498                         userId)) {
499                     try {
500                         updateTargetPackagesLocked(mImpl.onPackageReplacing(packageName,
501                                 systemUpdateUninstall, userId));
502                     } catch (OperationFailedException e) {
503                         Slog.e(TAG, "onPackageReplacing internal error", e);
504                     }
505                 }
506             }
507         } finally {
508             traceEnd(TRACE_TAG_RRO);
509         }
510     }
511 
onPackageReplaced(@onNull final String packageName, final int userId)512     private void onPackageReplaced(@NonNull final String packageName, final int userId) {
513         try {
514             traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplaced " + packageName);
515             synchronized (mLock) {
516                 var packageState = mPackageManager.onPackageUpdated(packageName, userId);
517                 if (packageState != null && !mPackageManager.isInstantApp(packageName,
518                         userId)) {
519                     try {
520                         updateTargetPackagesLocked(
521                                 mImpl.onPackageReplaced(packageName, userId));
522                     } catch (OperationFailedException e) {
523                         Slog.e(TAG, "onPackageReplaced internal error", e);
524                     }
525                 }
526             }
527         } finally {
528             traceEnd(TRACE_TAG_RRO);
529         }
530     }
531 
onPackageRemoved(@onNull final String packageName, final int userId)532     private void onPackageRemoved(@NonNull final String packageName, final int userId) {
533         try {
534             traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName);
535             synchronized (mLock) {
536                 mPackageManager.onPackageRemoved(packageName, userId);
537                 updateTargetPackagesLocked(mImpl.onPackageRemoved(packageName, userId));
538             }
539         } finally {
540             traceEnd(TRACE_TAG_RRO);
541         }
542     }
543 
544     /**
545      * Indicates that the given user is of great importance so that when it is created, we quickly
546      * update its overlays by using a Listener mechanism rather than a Broadcast mechanism. This
547      * is especially important for {@link UserManager#isHeadlessSystemUserMode() HSUM}'s MainUser,
548      * which is created and switched-to immediately on first boot.
549      */
isHighPriorityUserCreation(UserInfo user)550     private static boolean isHighPriorityUserCreation(UserInfo user) {
551         // TODO: Consider extending this to all created users (guarded behind a flag in that case).
552         return user != null && user.isMain();
553     }
554 
555     private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener {
556         @Override
onUserCreated(UserInfo user, Object token)557         public void onUserCreated(UserInfo user, Object token) {
558             if (isHighPriorityUserCreation(user)) {
559                 final int userId = user.id;
560                 try {
561                     Slog.i(TAG, "Updating overlays for onUserCreated " + userId);
562                     traceBegin(TRACE_TAG_RRO, "OMS#onUserCreated " + userId);
563                     synchronized (mLock) {
564                         updatePackageManagerLocked(mImpl.updateOverlaysForUser(userId));
565                     }
566                 } finally {
567                     traceEnd(TRACE_TAG_RRO);
568                 }
569             }
570         }
571     }
572 
573     private final class UserReceiver extends BroadcastReceiver {
574         @Override
onReceive(@onNull final Context context, @NonNull final Intent intent)575         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
576             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
577             switch (intent.getAction()) {
578                 case ACTION_USER_ADDED:
579                     UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
580                     UserInfo userInfo = umi.getUserInfo(userId);
581                     if (userId != UserHandle.USER_NULL && !isHighPriorityUserCreation(userInfo)) {
582                         try {
583                             Slog.i(TAG, "Updating overlays for added user " + userId);
584                             traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
585                             synchronized (mLock) {
586                                 updatePackageManagerLocked(mImpl.updateOverlaysForUser(userId));
587                             }
588                         } finally {
589                             traceEnd(TRACE_TAG_RRO);
590                         }
591                     }
592                     break;
593 
594                 case ACTION_USER_REMOVED:
595                     if (userId != UserHandle.USER_NULL) {
596                         try {
597                             traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED");
598                             synchronized (mLock) {
599                                 mImpl.onUserRemoved(userId);
600                                 mPackageManager.forgetAllPackageInfos(userId);
601                             }
602                         } finally {
603                             traceEnd(TRACE_TAG_RRO);
604                         }
605                     }
606                     break;
607                 default:
608                     // do nothing
609                     break;
610             }
611         }
612     }
613 
614     private final IBinder mService = new IOverlayManager.Stub() {
615         @Override
616         public Map<String, List<OverlayInfo>> getAllOverlays(final int userIdArg) {
617             try {
618                 traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userIdArg);
619                 final int realUserId = handleIncomingUser(userIdArg, "getAllOverlays");
620 
621                 synchronized (mLock) {
622                     return mImpl.getOverlaysForUser(realUserId);
623                 }
624             } finally {
625                 traceEnd(TRACE_TAG_RRO);
626             }
627         }
628 
629         @Override
630         public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
631                 final int userIdArg) {
632             if (targetPackageName == null) {
633                 return Collections.emptyList();
634             }
635 
636             try {
637                 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName);
638                 final int realUserId = handleIncomingUser(userIdArg, "getOverlayInfosForTarget");
639 
640                 synchronized (mLock) {
641                     return mImpl.getOverlayInfosForTarget(targetPackageName, realUserId);
642                 }
643             } finally {
644                 traceEnd(TRACE_TAG_RRO);
645             }
646         }
647 
648         @Override
649         public OverlayInfo getOverlayInfo(@Nullable final String packageName,
650                 final int userIdArg) {
651             return getOverlayInfoByIdentifier(new OverlayIdentifier(packageName), userIdArg);
652         }
653 
654         @Override
655         public OverlayInfo getOverlayInfoByIdentifier(@Nullable final OverlayIdentifier overlay,
656                 final int userIdArg) {
657             if (overlay == null || overlay.getPackageName() == null) {
658                 return null;
659             }
660 
661             try {
662                 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + overlay);
663                 final int realUserId = handleIncomingUser(userIdArg, "getOverlayInfo");
664 
665                 synchronized (mLock) {
666                     return mImpl.getOverlayInfo(overlay, realUserId);
667                 }
668             } finally {
669                 traceEnd(TRACE_TAG_RRO);
670             }
671         }
672 
673         @Override
674         public boolean setEnabled(@Nullable final String packageName, final boolean enable,
675                 int userIdArg) {
676             return setEnabled(packageName, enable, userIdArg,
677                     Collections.emptyList() /* constraints */);
678         }
679 
680         @Override
681         public boolean enableWithConstraints(@Nullable final String packageName, int userIdArg,
682                 @NonNull final List<OverlayConstraint> constraints) {
683             return setEnabled(packageName, true /* enable */, userIdArg, constraints);
684         }
685 
686         private boolean setEnabled(@Nullable final String packageName, final boolean enable,
687                 int userIdArg, @NonNull final List<OverlayConstraint> constraints) {
688             if (packageName == null) {
689                 return false;
690             }
691 
692             try {
693                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable);
694 
695                 final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
696                 final int realUserId = handleIncomingUser(userIdArg, "setEnabled");
697                 enforceActor(overlay, "setEnabled", realUserId);
698 
699                 final long ident = Binder.clearCallingIdentity();
700                 try {
701                     synchronized (mLock) {
702                         try {
703                             updateTargetPackagesLocked(
704                                     mImpl.setEnabled(overlay, enable, realUserId, constraints));
705                             return true;
706                         } catch (OperationFailedException e) {
707                             return false;
708                         }
709                     }
710                 } finally {
711                     Binder.restoreCallingIdentity(ident);
712                 }
713             } finally {
714                 traceEnd(TRACE_TAG_RRO);
715             }
716         }
717 
718         @Override
719         public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
720                 int userIdArg) {
721             if (packageName == null || !enable) {
722                 return false;
723             }
724 
725             try {
726                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable);
727 
728                 final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
729                 final int realUserId = handleIncomingUser(userIdArg, "setEnabledExclusive");
730                 enforceActor(overlay, "setEnabledExclusive", realUserId);
731 
732                 final long ident = Binder.clearCallingIdentity();
733                 try {
734                     synchronized (mLock) {
735                         try {
736                             mImpl.setEnabledExclusive(
737                                             overlay, false /* withinCategory */, realUserId)
738                                     .ifPresent(
739                                             OverlayManagerService.this::updateTargetPackagesLocked);
740                             return true;
741                         } catch (OperationFailedException e) {
742                             return false;
743                         }
744                     }
745                 } finally {
746                     Binder.restoreCallingIdentity(ident);
747                 }
748             } finally {
749                 traceEnd(TRACE_TAG_RRO);
750             }
751         }
752 
753         @Override
754         public boolean setEnabledExclusiveInCategory(@Nullable String packageName,
755                 final int userIdArg) {
756             if (packageName == null) {
757                 return false;
758             }
759 
760             try {
761                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
762 
763                 final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
764                 final int realUserId = handleIncomingUser(userIdArg,
765                         "setEnabledExclusiveInCategory");
766                 enforceActor(overlay, "setEnabledExclusiveInCategory", realUserId);
767 
768                 final long ident = Binder.clearCallingIdentity();
769                 try {
770                     synchronized (mLock) {
771                         try {
772                             mImpl.setEnabledExclusive(overlay,
773                                     true /* withinCategory */, realUserId)
774                                 .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
775                             return true;
776                         } catch (OperationFailedException e) {
777                             return false;
778                         }
779                     }
780                 } finally {
781                     Binder.restoreCallingIdentity(ident);
782                 }
783             } finally {
784                 traceEnd(TRACE_TAG_RRO);
785             }
786         }
787 
788         @Override
789         public boolean setPriority(@Nullable final String packageName,
790                 @Nullable final String parentPackageName, final int userIdArg) {
791             if (packageName == null || parentPackageName == null) {
792                 return false;
793             }
794 
795             try {
796                 traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " "
797                         + parentPackageName);
798 
799                 final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
800                 final OverlayIdentifier parentOverlay = new OverlayIdentifier(parentPackageName);
801                 final int realUserId = handleIncomingUser(userIdArg, "setPriority");
802                 enforceActor(overlay, "setPriority", realUserId);
803 
804                 final long ident = Binder.clearCallingIdentity();
805                 try {
806                     synchronized (mLock) {
807                         try {
808                             mImpl.setPriority(overlay, parentOverlay, realUserId)
809                                 .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
810                             return true;
811                         } catch (OperationFailedException e) {
812                             return false;
813                         }
814                     }
815                 } finally {
816                     Binder.restoreCallingIdentity(ident);
817                 }
818             } finally {
819                 traceEnd(TRACE_TAG_RRO);
820             }
821         }
822 
823         @Override
824         public boolean setHighestPriority(@Nullable final String packageName, final int userIdArg) {
825             if (packageName == null) {
826                 return false;
827             }
828 
829             try {
830                 traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName);
831 
832                 final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
833                 final int realUserId = handleIncomingUser(userIdArg, "setHighestPriority");
834                 enforceActor(overlay, "setHighestPriority", realUserId);
835 
836                 final long ident = Binder.clearCallingIdentity();
837                 try {
838                     synchronized (mLock) {
839                         try {
840                             updateTargetPackagesLocked(
841                                     mImpl.setHighestPriority(overlay, realUserId));
842                             return true;
843                         } catch (OperationFailedException e) {
844                             return false;
845                         }
846                     }
847                 } finally {
848                     Binder.restoreCallingIdentity(ident);
849                 }
850             } finally {
851                 traceEnd(TRACE_TAG_RRO);
852             }
853         }
854 
855         @Override
856         public boolean setLowestPriority(@Nullable final String packageName, final int userIdArg) {
857             if (packageName == null) {
858                 return false;
859             }
860 
861             try {
862                 traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName);
863 
864                 final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
865                 final int realUserId = handleIncomingUser(userIdArg, "setLowestPriority");
866                 enforceActor(overlay, "setLowestPriority", realUserId);
867 
868                 final long ident = Binder.clearCallingIdentity();
869                 try {
870                     synchronized (mLock) {
871                         try {
872                             mImpl.setLowestPriority(overlay, realUserId)
873                                 .ifPresent(OverlayManagerService.this::updateTargetPackagesLocked);
874                             return true;
875                         } catch (OperationFailedException e) {
876                             return false;
877                         }
878                     }
879                 } finally {
880                     Binder.restoreCallingIdentity(ident);
881                 }
882             } finally {
883                 traceEnd(TRACE_TAG_RRO);
884             }
885         }
886 
887         @Override
888         public String[] getDefaultOverlayPackages() {
889             try {
890                 traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages");
891                 getContext().enforceCallingOrSelfPermission(
892                         android.Manifest.permission.MODIFY_THEME_OVERLAY, null);
893 
894                 final long ident = Binder.clearCallingIdentity();
895                 try {
896                     synchronized (mLock) {
897                         return mImpl.getDefaultOverlayPackages();
898                     }
899                 } finally {
900                     Binder.restoreCallingIdentity(ident);
901                 }
902             } finally {
903                 traceEnd(TRACE_TAG_RRO);
904             }
905         }
906 
907         @Override
908         public void invalidateCachesForOverlay(@Nullable String packageName, final int userIdArg) {
909             if (packageName == null) {
910                 return;
911             }
912 
913             final OverlayIdentifier overlay = new OverlayIdentifier(packageName);
914             final int realUserId = handleIncomingUser(userIdArg, "invalidateCachesForOverlay");
915             enforceActor(overlay, "invalidateCachesForOverlay", realUserId);
916             final long ident = Binder.clearCallingIdentity();
917             try {
918                 synchronized (mLock) {
919                     try {
920                         mImpl.removeIdmapForOverlay(overlay, realUserId);
921                     } catch (OperationFailedException e) {
922                         Slog.w(TAG, "invalidate caches for overlay '" + overlay + "' failed", e);
923                     }
924                 }
925             } finally {
926                 Binder.restoreCallingIdentity(ident);
927             }
928         }
929 
930         @Override
931         public void commit(@NonNull final OverlayManagerTransaction transaction)
932                 throws RemoteException {
933             try {
934                 traceBegin(TRACE_TAG_RRO, "OMS#commit " + transaction);
935                 synchronized (mLock) {
936                     try {
937                         executeAllRequestsLocked(transaction);
938                     } catch (Exception e) {
939                         final long ident = Binder.clearCallingIdentity();
940                         try {
941                             restoreSettingsLocked();
942                         } finally {
943                             Binder.restoreCallingIdentity(ident);
944                         }
945                         Slog.d(TAG, "commit failed: " + e.getMessage(), e);
946                         throw new SecurityException("commit failed"
947                                 + (DEBUG || Build.IS_DEBUGGABLE ? ": " + e.getMessage() : ""));
948                     }
949                 }
950             } finally {
951                 traceEnd(TRACE_TAG_RRO);
952             }
953         }
954 
955         @GuardedBy("mLock")
956         private Set<UserPackage> executeRequestLocked(
957                 @NonNull final OverlayManagerTransaction.Request request)
958                 throws OperationFailedException {
959             Objects.requireNonNull(request, "Transaction contains a null request");
960             Objects.requireNonNull(request.overlay,
961                     "Transaction overlay identifier must be non-null");
962 
963             final int callingUid = Binder.getCallingUid();
964             final int realUserId;
965             if (request.type == TYPE_REGISTER_FABRICATED
966                     || request.type == TYPE_UNREGISTER_FABRICATED) {
967                 if (request.userId != UserHandle.USER_ALL) {
968                     throw new IllegalArgumentException(request.typeToString()
969                             + " unsupported for user " + request.userId);
970                 }
971 
972                 // Normal apps are blocked from accessing OMS via SELinux, so to block non-root,
973                 // non privileged callers, a simple check against the shell UID is sufficient, since
974                 // that's the only exception from the other categories. This is enough while OMS
975                 // is not a public API, but this will have to be changed if it's ever exposed.
976                 if (callingUid == Process.SHELL_UID) {
977                     EventLog.writeEvent(0x534e4554, "202768292", -1, "");
978                     throw new IllegalArgumentException("Non-root shell cannot fabricate overlays");
979                 }
980 
981                 realUserId = UserHandle.USER_ALL;
982 
983                 // Enforce that the calling process can only register and unregister fabricated
984                 // overlays using its package name.
985                 final String pkgName = request.overlay.getPackageName();
986                 if (callingUid != Process.ROOT_UID && !ArrayUtils.contains(
987                         mPackageManager.getPackagesForUid(callingUid), pkgName)) {
988                     throw new IllegalArgumentException("UID " + callingUid + " does not own "
989                             + "packageName " + pkgName);
990                 }
991             } else {
992                 // Enforce actor requirements for enabling, disabling, and reordering overlays.
993                 realUserId = handleIncomingUser(request.userId, request.typeToString());
994                 enforceActor(request.overlay, request.typeToString(), realUserId);
995             }
996 
997             final long ident = Binder.clearCallingIdentity();
998             try {
999                 switch (request.type) {
1000                     case TYPE_SET_ENABLED:
1001                         Set<UserPackage> result = null;
1002                         result = CollectionUtils.addAll(result,
1003                                 mImpl.setEnabled(request.overlay, true /* enable */, realUserId,
1004                                         request.constraints));
1005                         result = CollectionUtils.addAll(result,
1006                                 mImpl.setHighestPriority(request.overlay, realUserId));
1007                         return CollectionUtils.emptyIfNull(result);
1008 
1009                     case TYPE_SET_DISABLED:
1010                         return mImpl.setEnabled(request.overlay, false /* enable */, realUserId,
1011                                 request.constraints);
1012 
1013                     case TYPE_REGISTER_FABRICATED:
1014                         final FabricatedOverlayInternal fabricated =
1015                                 request.extras.getParcelable(
1016                                         OverlayManagerTransaction.Request.BUNDLE_FABRICATED_OVERLAY
1017                                 , android.os.FabricatedOverlayInternal.class);
1018                         Objects.requireNonNull(fabricated,
1019                                 "no fabricated overlay attached to request");
1020                         return mImpl.registerFabricatedOverlay(fabricated);
1021 
1022                     case TYPE_UNREGISTER_FABRICATED:
1023                         return mImpl.unregisterFabricatedOverlay(request.overlay);
1024 
1025                     default:
1026                         throw new IllegalArgumentException("unsupported request: " + request);
1027                 }
1028             } finally {
1029                 Binder.restoreCallingIdentity(ident);
1030             }
1031         }
1032 
1033         @GuardedBy("mLock")
1034         private void executeAllRequestsLocked(@NonNull final OverlayManagerTransaction transaction)
1035                 throws OperationFailedException {
1036             if (DEBUG) {
1037                 Slog.d(TAG, "commit " + transaction);
1038             }
1039 
1040             // execute the requests (as calling user)
1041             Set<UserPackage> affectedPackagesToUpdate = null;
1042             for (Iterator<Request> it = transaction.getRequests(); it.hasNext(); ) {
1043                 Request request = it.next();
1044                 affectedPackagesToUpdate = CollectionUtils.addAll(affectedPackagesToUpdate,
1045                         executeRequestLocked(request));
1046             }
1047 
1048             // past the point of no return: the entire transaction has been
1049             // processed successfully, we can no longer fail: continue as
1050             // system_server
1051             final long ident = Binder.clearCallingIdentity();
1052             try {
1053                 updateTargetPackagesLocked(affectedPackagesToUpdate);
1054             } finally {
1055                 Binder.restoreCallingIdentity(ident);
1056             }
1057         }
1058 
1059         @Override
1060         public void onShellCommand(@NonNull final FileDescriptor in,
1061                 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
1062                 @NonNull final String[] args, @NonNull final ShellCallback callback,
1063                 @NonNull final ResultReceiver resultReceiver) {
1064             (new OverlayManagerShellCommand(getContext(), this)).exec(
1065                     this, in, out, err, args, callback, resultReceiver);
1066         }
1067 
1068         @Override
1069         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1070             final DumpState dumpState = new DumpState();
1071             int userId = UserHandle.USER_ALL;
1072 
1073             int opti = 0;
1074             while (opti < args.length) {
1075                 final String opt = args[opti];
1076                 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
1077                     break;
1078                 }
1079                 opti++;
1080 
1081                 if ("-a".equals(opt)) {
1082                     // dumpsys will pass in -a; silently ignore it
1083                 } else if ("-h".equals(opt)) {
1084                     pw.println("dump [-h] [--verbose] [--user USER_ID] [[FIELD] PACKAGE]");
1085                     pw.println("  Print debugging information about the overlay manager.");
1086                     pw.println("  With optional parameter PACKAGE, limit output to the specified");
1087                     pw.println("  package. With optional parameter FIELD, limit output to");
1088                     pw.println("  the value of that SettingsItem field. Field names are");
1089                     pw.println("  case insensitive and out.println the m prefix can be omitted,");
1090                     pw.println("  so the following are equivalent: mState, mstate, State, state.");
1091                     return;
1092                 } else if ("--user".equals(opt)) {
1093                     if (opti >= args.length) {
1094                         pw.println("Error: user missing argument");
1095                         return;
1096                     }
1097                     try {
1098                         userId = UserHandle.parseUserArg(args[opti]);
1099                         opti++;
1100                     } catch (Exception e) {
1101                         pw.println("Error: " + e.getMessage());
1102                         return;
1103                     }
1104                 } else if ("--verbose".equals(opt)) {
1105                     dumpState.setVerbose(true);
1106                 } else {
1107                     pw.println("Unknown argument: " + opt + "; use -h for help");
1108                 }
1109             }
1110             if (opti < args.length) {
1111                 final String arg = args[opti];
1112                 opti++;
1113                 switch (arg) {
1114                     case "packagename":
1115                     case "userid":
1116                     case "targetpackagename":
1117                     case "targetoverlayablename":
1118                     case "basecodepath":
1119                     case "state":
1120                     case "isenabled":
1121                     case "ismutable":
1122                     case "priority":
1123                     case "category":
1124                         dumpState.setField(arg);
1125                         break;
1126                     default:
1127                         dumpState.setOverlyIdentifier(arg);
1128                         break;
1129                 }
1130             }
1131             if (dumpState.getPackageName() == null && opti < args.length) {
1132                 dumpState.setOverlyIdentifier(args[opti]);
1133                 opti++;
1134             }
1135 
1136             enforceDumpPermission("dump");
1137             final int realUserId = userId != UserHandle.USER_ALL
1138                     ? handleIncomingUser(userId, "dump") : userId;
1139             dumpState.setUserId(realUserId);
1140             synchronized (mLock) {
1141                 mImpl.dump(pw, dumpState);
1142                 if (dumpState.getPackageName() == null) {
1143                     mPackageManager.dump(pw, dumpState);
1144                 }
1145             }
1146         }
1147 
1148         /**
1149          * Enforce that the caller holds the DUMP permission (or is system or root).
1150          *
1151          * @param message used as message if SecurityException is thrown
1152          * @throws SecurityException if the permission check fails
1153          */
1154         private void enforceDumpPermission(@NonNull final String message) {
1155             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
1156         }
1157 
1158         private void enforceActor(@NonNull OverlayIdentifier overlay, @NonNull String methodName,
1159                 int realUserId) throws SecurityException {
1160             OverlayInfo overlayInfo = mImpl.getOverlayInfo(overlay, realUserId);
1161 
1162             if (overlayInfo == null) {
1163                 throw new IllegalArgumentException("Unable to retrieve overlay information for "
1164                         + overlay);
1165             }
1166 
1167             int callingUid = Binder.getCallingUid();
1168             mActorEnforcer.enforceActor(overlayInfo, methodName, callingUid, realUserId);
1169         }
1170 
1171         /**
1172          * @hide
1173          */
1174         public String getPartitionOrder() {
1175             return mImpl.getOverlayConfig().getPartitionOrder();
1176         }
1177 
1178         /**
1179          * @hide
1180          */
1181         public boolean isDefaultPartitionOrder() {
1182             return mImpl.getOverlayConfig().isDefaultPartitionOrder();
1183         }
1184 
1185     };
1186 
1187     private static final class PackageManagerHelperImpl implements PackageManagerHelper {
1188         private static class PackageStateUsers {
1189             private PackageState mPackageState;
1190             private final Set<Integer> mInstalledUsers = new ArraySet<>();
PackageStateUsers(@onNull PackageState packageState)1191             private PackageStateUsers(@NonNull PackageState packageState) {
1192                 this.mPackageState = packageState;
1193             }
1194         }
1195         private final Context mContext;
1196         private final IPackageManager mPackageManager;
1197         private final PackageManagerInternal mPackageManagerInternal;
1198 
1199         // Use a cache for performance and for consistency within OMS: because
1200         // additional PACKAGE_* intents may be delivered while we process an
1201         // intent, querying the PackageManagerService for the actual current
1202         // state may lead to contradictions within OMS. Better then to lag
1203         // behind until all pending intents have been processed.
1204         @GuardedBy("itself")
1205         private final ArrayMap<String, PackageStateUsers> mCache = new ArrayMap<>();
1206         private final ArraySet<Integer> mInitializedUsers = new ArraySet<>();
1207 
PackageManagerHelperImpl(Context context)1208         PackageManagerHelperImpl(Context context) {
1209             mContext = context;
1210             mPackageManager = getPackageManager();
1211             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
1212         }
1213 
1214         /**
1215          * Initializes the helper for the user. This only needs to be invoked one time before
1216          * packages of this user are queried.
1217          * @param userId the user id to initialize
1218          * @return a map of package name to all packages installed in the user
1219          */
1220         @NonNull
initializeForUser(final int userId)1221         public ArrayMap<String, PackageState> initializeForUser(final int userId) {
1222             if (mInitializedUsers.add(userId)) {
1223                 mPackageManagerInternal.forEachPackageState((packageState -> {
1224                     if (packageState.getPkg() != null
1225                             && packageState.getUserStateOrDefault(userId).isInstalled()) {
1226                         addPackageUser(packageState, userId);
1227                     }
1228                 }));
1229             }
1230 
1231             final ArrayMap<String, PackageState> userPackages = new ArrayMap<>();
1232             synchronized (mCache) {
1233                 for (int i = 0, n = mCache.size(); i < n; i++) {
1234                     final PackageStateUsers pkg = mCache.valueAt(i);
1235                     if (pkg.mInstalledUsers.contains(userId)) {
1236                         userPackages.put(mCache.keyAt(i), pkg.mPackageState);
1237                     }
1238                 }
1239             }
1240             return userPackages;
1241         }
1242 
1243         @Override
1244         @Nullable
getPackageStateForUser(@onNull final String packageName, final int userId)1245         public PackageState getPackageStateForUser(@NonNull final String packageName,
1246                 final int userId) {
1247             final PackageStateUsers pkg;
1248 
1249             synchronized (mCache) {
1250                 pkg = mCache.get(packageName);
1251             }
1252             if (pkg != null && pkg.mInstalledUsers.contains(userId)) {
1253                 return pkg.mPackageState;
1254             }
1255             try {
1256                 if (!mPackageManager.isPackageAvailable(packageName, userId)) {
1257                     return null;
1258                 }
1259             } catch (RemoteException e) {
1260                 Slog.w(TAG, "Failed to check availability of package '" + packageName
1261                         + "' for user " + userId, e);
1262                 return null;
1263             }
1264             return addPackageUser(packageName, userId);
1265         }
1266 
1267         @NonNull
addPackageUser(@onNull final String packageName, final int user)1268         private PackageState addPackageUser(@NonNull final String packageName,
1269                 final int user) {
1270             final PackageState pkg = mPackageManagerInternal.getPackageStateInternal(packageName);
1271             if (pkg == null) {
1272                 Slog.w(TAG, "Android package for '" + packageName + "' could not be found;"
1273                         + " continuing as if package was never added", new Throwable());
1274                 return null;
1275             }
1276             return addPackageUser(pkg, user);
1277         }
1278 
1279         @NonNull
addPackageUser(@onNull final PackageState pkg, final int user)1280         private PackageState addPackageUser(@NonNull final PackageState pkg,
1281                 final int user) {
1282             PackageStateUsers pkgUsers;
1283             synchronized (mCache) {
1284                 pkgUsers = mCache.get(pkg.getPackageName());
1285                 if (pkgUsers == null) {
1286                     pkgUsers = new PackageStateUsers(pkg);
1287                     mCache.put(pkg.getPackageName(), pkgUsers);
1288                 } else {
1289                     pkgUsers.mPackageState = pkg;
1290                 }
1291             }
1292             pkgUsers.mInstalledUsers.add(user);
1293             return pkgUsers.mPackageState;
1294         }
1295 
1296 
1297         @NonNull
removePackageUser(@onNull final String packageName, final int user)1298         private void removePackageUser(@NonNull final String packageName, final int user) {
1299             // synchronize should include the call to the other removePackageUser() method so that
1300             // the access and modification happen under the same lock.
1301             synchronized (mCache) {
1302                 final PackageStateUsers pkgUsers = mCache.get(packageName);
1303                 if (pkgUsers == null) {
1304                     return;
1305                 }
1306                 removePackageUser(pkgUsers, user);
1307             }
1308         }
1309 
1310         @NonNull
removePackageUser(@onNull final PackageStateUsers pkg, final int user)1311         private void removePackageUser(@NonNull final PackageStateUsers pkg, final int user) {
1312             pkg.mInstalledUsers.remove(user);
1313             if (pkg.mInstalledUsers.isEmpty()) {
1314                 synchronized (mCache) {
1315                     mCache.remove(pkg.mPackageState.getPackageName());
1316                 }
1317             }
1318         }
1319 
1320         @Nullable
onPackageAdded(@onNull final String packageName, final int userId)1321         public PackageState onPackageAdded(@NonNull final String packageName, final int userId) {
1322             return addPackageUser(packageName, userId);
1323         }
1324 
1325         @Nullable
onPackageUpdated(@onNull final String packageName, final int userId)1326         public PackageState onPackageUpdated(@NonNull final String packageName,
1327                 final int userId) {
1328             return addPackageUser(packageName, userId);
1329         }
1330 
onPackageRemoved(@onNull final String packageName, final int userId)1331         public void onPackageRemoved(@NonNull final String packageName, final int userId) {
1332             removePackageUser(packageName, userId);
1333         }
1334 
1335         @Override
isInstantApp(@onNull final String packageName, final int userId)1336         public boolean isInstantApp(@NonNull final String packageName, final int userId) {
1337             return mPackageManagerInternal.isInstantApp(packageName, userId);
1338         }
1339 
1340         @NonNull
1341         @Override
getNamedActors()1342         public Map<String, Map<String, String>> getNamedActors() {
1343             return SystemConfig.getInstance().getNamedActors();
1344         }
1345 
1346         @Override
signaturesMatching(@onNull final String packageName1, @NonNull final String packageName2, final int userId)1347         public boolean signaturesMatching(@NonNull final String packageName1,
1348                 @NonNull final String packageName2, final int userId) {
1349             // The package manager does not support different versions of packages
1350             // to be installed for different users: ignore userId for now.
1351             try {
1352                 return mPackageManager.checkSignatures(
1353                         packageName1, packageName2, userId) == SIGNATURE_MATCH;
1354             } catch (RemoteException e) {
1355                 // Intentionally left blank
1356             }
1357             return false;
1358         }
1359 
1360         @Override
getConfigSignaturePackage()1361         public String getConfigSignaturePackage() {
1362             final String[] pkgs = mPackageManagerInternal.getKnownPackageNames(
1363                     KnownPackages.PACKAGE_OVERLAY_CONFIG_SIGNATURE,
1364                     UserHandle.USER_SYSTEM);
1365             return (pkgs.length == 0) ? null : pkgs[0];
1366         }
1367 
1368         @Nullable
1369         @Override
getOverlayableForTarget(@onNull String packageName, @NonNull String targetOverlayableName, int userId)1370         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
1371                 @NonNull String targetOverlayableName, int userId)
1372                 throws IOException {
1373             var packageState = getPackageStateForUser(packageName, userId);
1374             var pkg = packageState == null ? null : packageState.getAndroidPackage();
1375             if (pkg == null) {
1376                 throw new IOException("Unable to get target package");
1377             }
1378 
1379             ApkAssets apkAssets = null;
1380             try {
1381                 apkAssets = ApkAssets.loadFromPath(pkg.getSplits().get(0).getPath(),
1382                         ApkAssets.PROPERTY_ONLY_OVERLAYABLES);
1383                 return apkAssets.getOverlayableInfo(targetOverlayableName);
1384             } finally {
1385                 if (apkAssets != null) {
1386                     try {
1387                         apkAssets.close();
1388                     } catch (Throwable ignored) {
1389                     }
1390                 }
1391             }
1392         }
1393 
1394         @Override
doesTargetDefineOverlayable(String targetPackageName, int userId)1395         public boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
1396                 throws IOException {
1397             var packageState = getPackageStateForUser(targetPackageName, userId);
1398             var pkg = packageState == null ? null : packageState.getAndroidPackage();
1399             if (pkg == null) {
1400                 throw new IOException("Unable to get target package");
1401             }
1402 
1403             ApkAssets apkAssets = null;
1404             try {
1405                 apkAssets = ApkAssets.loadFromPath(pkg.getSplits().get(0).getPath(),
1406                         ApkAssets.PROPERTY_ONLY_OVERLAYABLES);
1407                 return apkAssets.definesOverlayable();
1408             } finally {
1409                 if (apkAssets != null) {
1410                     try {
1411                         apkAssets.close();
1412                     } catch (Throwable ignored) {
1413                     }
1414                 }
1415             }
1416         }
1417 
1418         @Override
enforcePermission(String permission, String message)1419         public void enforcePermission(String permission, String message) throws SecurityException {
1420             mContext.enforceCallingOrSelfPermission(permission, message);
1421         }
1422 
forgetAllPackageInfos(final int userId)1423         public void forgetAllPackageInfos(final int userId) {
1424             // Iterate in reverse order since removing the package in all users will remove the
1425             // package from the cache.
1426             synchronized (mCache) {
1427                 for (int i = mCache.size() - 1; i >= 0; i--) {
1428                     removePackageUser(mCache.valueAt(i), userId);
1429                 }
1430             }
1431         }
1432 
1433         @Nullable
1434         @Override
getPackagesForUid(int uid)1435         public String[] getPackagesForUid(int uid) {
1436             try {
1437                 return mPackageManager.getPackagesForUid(uid);
1438             } catch (RemoteException ignored) {
1439                 return null;
1440             }
1441         }
1442 
1443         private static final String TAB1 = "    ";
1444 
dump(@onNull final PrintWriter pw, @NonNull DumpState dumpState)1445         public void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
1446             pw.println("AndroidPackage cache");
1447             synchronized (mCache) {
1448                 if (!dumpState.isVerbose()) {
1449                     pw.println(TAB1 + mCache.size() + " package(s)");
1450                     return;
1451                 }
1452 
1453                 if (mCache.size() == 0) {
1454                     pw.println(TAB1 + "<empty>");
1455                     return;
1456                 }
1457 
1458                 for (int i = 0, n = mCache.size(); i < n; i++) {
1459                     final String packageName = mCache.keyAt(i);
1460                     final PackageStateUsers pkg = mCache.valueAt(i);
1461                     pw.print(TAB1 + packageName + ": " + pkg.mPackageState + " users=");
1462                     pw.println(TextUtils.join(", ", pkg.mInstalledUsers));
1463                 }
1464             }
1465         }
1466     }
1467 
1468     @GuardedBy("mLock")
updateTargetPackagesLocked(@ullable UserPackage updatedTarget)1469     private void updateTargetPackagesLocked(@Nullable UserPackage updatedTarget) {
1470         if (updatedTarget != null) {
1471             updateTargetPackagesLocked(Set.of(updatedTarget));
1472         }
1473     }
1474 
1475     @GuardedBy("mLock")
updateTargetPackagesLocked(@ullable Set<UserPackage> updatedTargets)1476     private void updateTargetPackagesLocked(@Nullable Set<UserPackage> updatedTargets) {
1477         if (CollectionUtils.isEmpty(updatedTargets)) {
1478             return;
1479         }
1480         persistSettingsLocked();
1481         final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(updatedTargets);
1482         for (int i = 0, n = userTargets.size(); i < n; i++) {
1483             final ArraySet<String> targets = userTargets.valueAt(i);
1484             final int userId = userTargets.keyAt(i);
1485             final List<String> affectedPackages = updatePackageManagerLocked(targets, userId);
1486             if (affectedPackages.isEmpty()) {
1487                 // The package manager paths are already up-to-date.
1488                 continue;
1489             }
1490 
1491             FgThread.getHandler().post(() -> {
1492                 // Send configuration changed events for all target packages that have been affected
1493                 // by overlay state changes.
1494                 updateActivityManager(affectedPackages, userId);
1495 
1496                 // Do not send broadcasts for all affected targets. Overlays targeting the framework
1497                 // or shared libraries may cause too many broadcasts to be sent at once.
1498                 broadcastActionOverlayChanged(targets, userId);
1499             });
1500         }
1501     }
1502 
1503     @Nullable
groupTargetsByUserId( @ullable final Set<UserPackage> targetsAndUsers)1504     private static SparseArray<ArraySet<String>> groupTargetsByUserId(
1505             @Nullable final Set<UserPackage> targetsAndUsers) {
1506         final SparseArray<ArraySet<String>> userTargets = new SparseArray<>();
1507         CollectionUtils.forEach(targetsAndUsers, target -> {
1508             ArraySet<String> targets = userTargets.get(target.userId);
1509             if (targets == null) {
1510                 targets = new ArraySet<>();
1511                 userTargets.put(target.userId, targets);
1512             }
1513             targets.add(target.packageName);
1514         });
1515         return userTargets;
1516     }
1517 
1518     // Helper methods to update other parts of the system or read/write
1519     // settings: these methods should never call into each other!
1520 
broadcastActionOverlayChanged(@onNull final Set<String> targetPackages, final int userId)1521     private static void broadcastActionOverlayChanged(@NonNull final Set<String> targetPackages,
1522             final int userId) {
1523         final ActivityManagerInternal amInternal =
1524                 LocalServices.getService(ActivityManagerInternal.class);
1525         CollectionUtils.forEach(targetPackages, target -> {
1526             final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
1527                     Uri.fromParts("package", target, null));
1528             intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1529             intent.putExtra(EXTRA_PACKAGE_NAME, target);
1530             intent.putExtra(EXTRA_USER_ID, userId);
1531             amInternal.broadcastIntent(intent, null /* resultTo */, null /* requiredPermissions */,
1532                     false /* serialized */, userId, null /* appIdAllowList */,
1533                     OverlayManagerService::filterReceiverAccess, null /* bOptions */);
1534         });
1535     }
1536 
1537     /**
1538      * A callback from the broadcast queue to determine whether the intent
1539      * {@link Intent#ACTION_OVERLAY_CHANGED} is visible to the receiver.
1540      *
1541      * @param callingUid The receiver's uid.
1542      * @param extras The extras of intent that contains {@link Intent#EXTRA_PACKAGE_NAME} and
1543      * {@link Intent#EXTRA_USER_ID} to check.
1544      * @return {@code null} if the intent is not visible to the receiver.
1545      */
1546     @Nullable
filterReceiverAccess(int callingUid, @NonNull Bundle extras)1547     private static Bundle filterReceiverAccess(int callingUid, @NonNull Bundle extras) {
1548         final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
1549         final int userId = extras.getInt(EXTRA_USER_ID);
1550         if (LocalServices.getService(PackageManagerInternal.class).filterAppAccess(
1551                 packageName, callingUid, userId, false /* filterUninstalled */)) {
1552             return null;
1553         }
1554         return extras;
1555     }
1556 
1557     /**
1558      * Tell the activity manager to tell a set of packages to reload their
1559      * resources.
1560      */
updateActivityManager(@onNull List<String> targetPackageNames, final int userId)1561     private void updateActivityManager(@NonNull List<String> targetPackageNames, final int userId) {
1562         final IActivityManager am = ActivityManager.getService();
1563         try {
1564             am.scheduleApplicationInfoChanged(targetPackageNames, userId);
1565         } catch (RemoteException e) {
1566             Slog.e(TAG, "updateActivityManager remote exception", e);
1567         }
1568     }
1569 
1570     @NonNull
1571     @GuardedBy("mLock")
updatePackageManagerLocked( @ullable Set<UserPackage> targets)1572     private SparseArray<List<String>> updatePackageManagerLocked(
1573             @Nullable Set<UserPackage> targets) {
1574         if (CollectionUtils.isEmpty(targets)) {
1575             return new SparseArray<>();
1576         }
1577         final SparseArray<List<String>> affectedTargets = new SparseArray<>();
1578         final SparseArray<ArraySet<String>> userTargets = groupTargetsByUserId(targets);
1579         for (int i = 0, n = userTargets.size(); i < n; i++) {
1580             final int userId = userTargets.keyAt(i);
1581             affectedTargets.put(userId, updatePackageManagerLocked(userTargets.valueAt(i), userId));
1582         }
1583         return affectedTargets;
1584     }
1585 
1586     /**
1587      * Updates the target packages' set of enabled overlays in PackageManager.
1588      * @return the package names of affected targets (a superset of
1589      *         targetPackageNames: the target themselves and shared libraries)
1590      */
1591     @NonNull
1592     @GuardedBy("mLock")
updatePackageManagerLocked(@onNull Collection<String> targetPackageNames, final int userId)1593     private List<String> updatePackageManagerLocked(@NonNull Collection<String> targetPackageNames,
1594             final int userId) {
1595         try {
1596             traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManagerLocked " + targetPackageNames);
1597             if (DEBUG) {
1598                 Slog.d(TAG, "Update package manager about changed overlays");
1599             }
1600             final PackageManagerInternal pm =
1601                     LocalServices.getService(PackageManagerInternal.class);
1602             final boolean updateFrameworkRes = targetPackageNames.contains("android");
1603             if (updateFrameworkRes) {
1604                 targetPackageNames = pm.getTargetPackageNames(userId);
1605             }
1606 
1607             final ArrayMap<String, OverlayPaths> pendingChanges =
1608                     new ArrayMap<>(targetPackageNames.size());
1609             synchronized (mLock) {
1610                 final OverlayPaths frameworkOverlays =
1611                         mImpl.getEnabledOverlayPaths("android", userId, false);
1612                 for (final String targetPackageName : targetPackageNames) {
1613                     final var list = new OverlayPaths.Builder(frameworkOverlays);
1614                     if (!"android".equals(targetPackageName)) {
1615                         list.addAll(mImpl.getEnabledOverlayPaths(targetPackageName, userId, true));
1616                     }
1617                     pendingChanges.put(targetPackageName, list.build());
1618                 }
1619             }
1620 
1621             final HashSet<String> updatedPackages = new HashSet<>();
1622             final HashSet<String> invalidPackages = new HashSet<>();
1623             pm.setEnabledOverlayPackages(userId, pendingChanges, updatedPackages, invalidPackages);
1624 
1625             if (DEBUG || !invalidPackages.isEmpty()) {
1626                 for (final String targetPackageName : targetPackageNames) {
1627                     if (DEBUG) {
1628                         Slog.d(TAG,
1629                                 "-> Updating overlay: target=" + targetPackageName + " overlays=["
1630                                         + pendingChanges.get(targetPackageName)
1631                                         + "] userId=" + userId);
1632                     }
1633 
1634                     if (invalidPackages.contains(targetPackageName)) {
1635                         Slog.e(TAG, TextUtils.formatSimple(
1636                                 "Failed to change enabled overlays for %s user %d",
1637                                 targetPackageName,
1638                                 userId));
1639                     }
1640                 }
1641             }
1642             return new ArrayList<>(updatedPackages);
1643         } finally {
1644             traceEnd(TRACE_TAG_RRO);
1645         }
1646     }
1647 
1648     @GuardedBy("mLock")
persistSettingsLocked()1649     private void persistSettingsLocked() {
1650         if (DEBUG) {
1651             Slog.d(TAG, "Writing overlay settings");
1652         }
1653         FileOutputStream stream = null;
1654         try {
1655             stream = mSettingsFile.startWrite();
1656             mSettings.persist(stream);
1657             mSettingsFile.finishWrite(stream);
1658         } catch (IOException | XmlPullParserException e) {
1659             mSettingsFile.failWrite(stream);
1660             Slog.e(TAG, "failed to persist overlay state", e);
1661         }
1662     }
1663 
1664     @GuardedBy("mLock")
restoreSettingsLocked()1665     private void restoreSettingsLocked() {
1666         try {
1667             traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
1668 
1669             if (!mSettingsFile.getBaseFile().exists()) {
1670                 return;
1671             }
1672             try (FileInputStream stream = mSettingsFile.openRead()) {
1673                 mSettings.restore(stream);
1674 
1675                 // We might have data for dying users if the device was
1676                 // restarted before we received USER_REMOVED. Remove data for
1677                 // users that will not exist after the system is ready.
1678 
1679                 final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
1680                 final int[] liveUserIds = new int[liveUsers.size()];
1681                 for (int i = 0; i < liveUsers.size(); i++) {
1682                     liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
1683                 }
1684                 Arrays.sort(liveUserIds);
1685 
1686                 for (int userId : mSettings.getUsers()) {
1687                     if (Arrays.binarySearch(liveUserIds, userId) < 0) {
1688                         mSettings.removeUser(userId);
1689                     }
1690                 }
1691             } catch (IOException | XmlPullParserException e) {
1692                 Slog.e(TAG, "failed to restore overlay state", e);
1693             }
1694         } finally {
1695             traceEnd(TRACE_TAG_RRO);
1696         }
1697     }
1698 }
1699