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