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