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