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