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