Home | History | Annotate | Download | only in om
      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_PACKAGE_ADDED;
     21 import static android.content.Intent.ACTION_PACKAGE_CHANGED;
     22 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
     23 import static android.content.Intent.ACTION_USER_ADDED;
     24 import static android.content.Intent.ACTION_USER_REMOVED;
     25 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
     26 import static android.os.Trace.TRACE_TAG_RRO;
     27 import static android.os.Trace.traceBegin;
     28 import static android.os.Trace.traceEnd;
     29 
     30 import android.annotation.NonNull;
     31 import android.annotation.Nullable;
     32 import android.app.ActivityManager;
     33 import android.app.IActivityManager;
     34 import android.content.BroadcastReceiver;
     35 import android.content.Context;
     36 import android.content.Intent;
     37 import android.content.IntentFilter;
     38 import android.content.om.IOverlayManager;
     39 import android.content.om.OverlayInfo;
     40 import android.content.pm.IPackageManager;
     41 import android.content.pm.PackageInfo;
     42 import android.content.pm.PackageManagerInternal;
     43 import android.content.pm.UserInfo;
     44 import android.net.Uri;
     45 import android.os.Binder;
     46 import android.os.Environment;
     47 import android.os.IBinder;
     48 import android.os.RemoteException;
     49 import android.os.ResultReceiver;
     50 import android.os.ShellCallback;
     51 import android.os.SystemProperties;
     52 import android.os.UserHandle;
     53 import android.os.UserManager;
     54 import android.text.TextUtils;
     55 import android.util.ArrayMap;
     56 import android.util.ArraySet;
     57 import android.util.AtomicFile;
     58 import android.util.Slog;
     59 import android.util.SparseArray;
     60 
     61 import com.android.server.FgThread;
     62 import com.android.server.IoThread;
     63 import com.android.server.LocalServices;
     64 import com.android.server.SystemService;
     65 import com.android.server.pm.Installer;
     66 import com.android.server.pm.UserManagerService;
     67 
     68 import libcore.util.EmptyArray;
     69 
     70 import org.xmlpull.v1.XmlPullParserException;
     71 
     72 import java.io.File;
     73 import java.io.FileDescriptor;
     74 import java.io.FileInputStream;
     75 import java.io.FileOutputStream;
     76 import java.io.IOException;
     77 import java.io.PrintWriter;
     78 import java.util.ArrayList;
     79 import java.util.Arrays;
     80 import java.util.Collections;
     81 import java.util.HashMap;
     82 import java.util.List;
     83 import java.util.Map;
     84 import java.util.concurrent.atomic.AtomicBoolean;
     85 
     86 /**
     87  * Service to manage asset overlays.
     88  *
     89  * <p>Asset overlays are additional resources that come from apks loaded
     90  * alongside the system and app apks. This service, the OverlayManagerService
     91  * (OMS), tracks which installed overlays to use and provides methods to change
     92  * this. Changes propagate to running applications as part of the Activity
     93  * lifecycle. This allows Activities to reread their resources at a well
     94  * defined point.</p>
     95  *
     96  * <p>By itself, the OMS will not change what overlays should be active.
     97  * Instead, it is only responsible for making sure that overlays *can* be used
     98  * from a technical and security point of view and to activate overlays in
     99  * response to external requests. The responsibility to toggle overlays on and
    100  * off lies within components that implement different use-cases such as themes
    101  * or dynamic customization.</p>
    102  *
    103  * <p>The OMS receives input from three sources:</p>
    104  *
    105  * <ul>
    106  *     <li>Callbacks from the SystemService class, specifically when the
    107  *     Android framework is booting and when the end user switches Android
    108  *     users.</li>
    109  *
    110  *     <li>Intents from the PackageManagerService (PMS). Overlays are regular
    111  *     apks, and whenever a package is installed (or removed, or has a
    112  *     component enabled or disabled), the PMS broadcasts this as an intent.
    113  *     When the OMS receives one of these intents, it updates its internal
    114  *     representation of the available overlays and, if there was a visible
    115  *     change, triggers an asset refresh in the affected apps.</li>
    116  *
    117  *     <li>External requests via the {@link IOverlayManager AIDL interface}.
    118  *     The interface allows clients to read information about the currently
    119  *     available overlays, change whether an overlay should be used or not, and
    120  *     change the relative order in which overlay packages are loaded.
    121  *     Read-access is granted if the request targets the same Android user as
    122  *     the caller runs as, or if the caller holds the
    123  *     INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the
    124  *     caller is granted read-access and additionaly holds the
    125  *     CHANGE_OVERLAY_PACKAGES permission.</li>
    126  * </ul>
    127  *
    128  * <p>The AIDL interface works with String package names, int user IDs, and
    129  * {@link OverlayInfo} objects. OverlayInfo instances are used to track a
    130  * specific pair of target and overlay packages and include information such as
    131  * the current state of the overlay. OverlayInfo objects are immutable.</p>
    132  *
    133  * <p>Internally, OverlayInfo objects are maintained by the
    134  * OverlayManagerSettings class. The OMS and its helper classes are notified of
    135  * changes to the settings by the OverlayManagerSettings.ChangeListener
    136  * callback interface. The file /data/system/overlays.xml is used to persist
    137  * the settings.</p>
    138  *
    139  * <p>Creation and deletion of idmap files are handled by the IdmapManager
    140  * class.</p>
    141  *
    142  * <p>The following is an overview of OMS and its related classes. Note how box
    143  * (2) does the heavy lifting, box (1) interacts with the Android framework,
    144  * and box (3) replaces box (1) during unit testing.</p>
    145  *
    146  * <pre>
    147  *         Android framework
    148  *            |         ^
    149  *      . . . | . . . . | . . . .
    150  *     .      |         |       .
    151  *     .    AIDL,   broadcasts  .
    152  *     .   intents      |       .
    153  *     .      |         |       . . . . . . . . . . . .
    154  *     .      v         |       .                     .
    155  *     .  OverlayManagerService . OverlayManagerTests .
    156  *     .                  \     .     /               .
    157  *     . (1)               \    .    /            (3) .
    158  *      . . . . . . . . . . \ . . . / . . . . . . . . .
    159  *     .                     \     /              .
    160  *     . (2)                  \   /               .
    161  *     .           OverlayManagerServiceImpl      .
    162  *     .                  |            |          .
    163  *     .                  |            |          .
    164  *     . OverlayManagerSettings     IdmapManager  .
    165  *     .                                          .
    166  *     . . . .  . . . . . . . . . . . . . . . . . .
    167  * </pre>
    168  *
    169  * <p>To test the OMS, execute:
    170  * <code>
    171  * atest FrameworksServicesTests:com.android.server.om  # internal tests
    172  * atest OverlayDeviceTests OverlayHostTests            # public API tests
    173  * </code>
    174  * </p>
    175  *
    176  * <p>Finally, here is a list of keywords used in the OMS context.</p>
    177  *
    178  * <ul>
    179  *     <li><b>target [package]</b> -- A regular apk that may have its resource
    180  *     pool extended  by zero or more overlay packages.</li>
    181  *
    182  *     <li><b>overlay [package]</b> -- An apk that provides additional
    183  *     resources to another apk.</li>
    184  *
    185  *     <li><b>OMS</b> -- The OverlayManagerService, i.e. this class.</li>
    186  *
    187  *     <li><b>approved</b> -- An overlay is approved if the OMS has verified
    188  *     that it can be used technically speaking (its target package is
    189  *     installed, at least one resource name in both packages match, the
    190  *     idmap was created, etc) and that it is secure to do so. External
    191  *     clients can not change this state.</li>
    192  *
    193  *     <li><b>not approved</b> -- The opposite of approved.</li>
    194  *
    195  *     <li><b>enabled</b> -- An overlay currently in active use and thus part
    196  *     of resource lookups. This requires the overlay to be approved. Only
    197  *     external clients can change this state.</li>
    198  *
    199  *     <li><b>disabled</b> -- The opposite of enabled.</li>
    200  *
    201  *     <li><b>idmap</b> -- A mapping of resource IDs between target and overlay
    202  *     used during resource lookup. Also the name of the binary that creates
    203  *     the mapping.</li>
    204  * </ul>
    205  */
    206 public final class OverlayManagerService extends SystemService {
    207     static final String TAG = "OverlayManager";
    208 
    209     static final boolean DEBUG = false;
    210 
    211     /**
    212      * The system property that specifies the default overlays to apply.
    213      * This is a semicolon separated list of package names.
    214      *
    215      * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
    216      */
    217     private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
    218 
    219     private final Object mLock = new Object();
    220 
    221     private final AtomicFile mSettingsFile;
    222 
    223     private final PackageManagerHelper mPackageManager;
    224 
    225     private final UserManagerService mUserManager;
    226 
    227     private final OverlayManagerSettings mSettings;
    228 
    229     private final OverlayManagerServiceImpl mImpl;
    230 
    231     private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
    232 
    233     public OverlayManagerService(@NonNull final Context context,
    234             @NonNull final Installer installer) {
    235         super(context);
    236         try {
    237             traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
    238             mSettingsFile = new AtomicFile(
    239                     new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
    240             mPackageManager = new PackageManagerHelper();
    241             mUserManager = UserManagerService.getInstance();
    242             IdmapManager im = new IdmapManager(installer, mPackageManager);
    243             mSettings = new OverlayManagerSettings();
    244             mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
    245                     getDefaultOverlayPackages(), new OverlayChangeListener());
    246 
    247             final IntentFilter packageFilter = new IntentFilter();
    248             packageFilter.addAction(ACTION_PACKAGE_ADDED);
    249             packageFilter.addAction(ACTION_PACKAGE_CHANGED);
    250             packageFilter.addAction(ACTION_PACKAGE_REMOVED);
    251             packageFilter.addDataScheme("package");
    252             getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
    253                     packageFilter, null, null);
    254 
    255             final IntentFilter userFilter = new IntentFilter();
    256             userFilter.addAction(ACTION_USER_ADDED);
    257             userFilter.addAction(ACTION_USER_REMOVED);
    258             getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
    259                     userFilter, null, null);
    260 
    261             restoreSettings();
    262 
    263             initIfNeeded();
    264             onSwitchUser(UserHandle.USER_SYSTEM);
    265 
    266             publishBinderService(Context.OVERLAY_SERVICE, mService);
    267             publishLocalService(OverlayManagerService.class, this);
    268         } finally {
    269             traceEnd(TRACE_TAG_RRO);
    270         }
    271     }
    272 
    273     @Override
    274     public void onStart() {
    275         // Intentionally left empty.
    276     }
    277 
    278     private void initIfNeeded() {
    279         final UserManager um = getContext().getSystemService(UserManager.class);
    280         final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
    281         synchronized (mLock) {
    282             final int userCount = users.size();
    283             for (int i = 0; i < userCount; i++) {
    284                 final UserInfo userInfo = users.get(i);
    285                 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
    286                     // Initialize any users that can't be switched to, as there state would
    287                     // never be setup in onSwitchUser(). We will switch to the system user right
    288                     // after this, and its state will be setup there.
    289                     final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
    290                     updateOverlayPaths(users.get(i).id, targets);
    291                 }
    292             }
    293         }
    294     }
    295 
    296     @Override
    297     public void onSwitchUser(final int newUserId) {
    298         try {
    299             traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId);
    300             // ensure overlays in the settings are up-to-date, and propagate
    301             // any asset changes to the rest of the system
    302             synchronized (mLock) {
    303                 final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
    304                 updateAssets(newUserId, targets);
    305             }
    306             schedulePersistSettings();
    307         } finally {
    308             traceEnd(TRACE_TAG_RRO);
    309         }
    310     }
    311 
    312     private static String[] getDefaultOverlayPackages() {
    313         final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
    314         if (TextUtils.isEmpty(str)) {
    315             return EmptyArray.STRING;
    316         }
    317 
    318         final ArraySet<String> defaultPackages = new ArraySet<>();
    319         for (String packageName : str.split(";")) {
    320             if (!TextUtils.isEmpty(packageName)) {
    321                 defaultPackages.add(packageName);
    322             }
    323         }
    324         return defaultPackages.toArray(new String[defaultPackages.size()]);
    325     }
    326 
    327     private final class PackageReceiver extends BroadcastReceiver {
    328         @Override
    329         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
    330             final String action = intent.getAction();
    331             if (action == null) {
    332                 Slog.e(TAG, "Cannot handle package broadcast with null action");
    333                 return;
    334             }
    335             final Uri data = intent.getData();
    336             if (data == null) {
    337                 Slog.e(TAG, "Cannot handle package broadcast with null data");
    338                 return;
    339             }
    340             final String packageName = data.getSchemeSpecificPart();
    341 
    342             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
    343 
    344             final int[] userIds;
    345             final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
    346             if (extraUid == UserHandle.USER_NULL) {
    347                 userIds = mUserManager.getUserIds();
    348             } else {
    349                 userIds = new int[] { UserHandle.getUserId(extraUid) };
    350             }
    351 
    352             switch (action) {
    353                 case ACTION_PACKAGE_ADDED:
    354                     if (replacing) {
    355                         onPackageReplaced(packageName, userIds);
    356                     } else {
    357                         onPackageAdded(packageName, userIds);
    358                     }
    359                     break;
    360                 case ACTION_PACKAGE_CHANGED:
    361                     onPackageChanged(packageName, userIds);
    362                     break;
    363                 case ACTION_PACKAGE_REMOVED:
    364                     if (replacing) {
    365                         onPackageReplacing(packageName, userIds);
    366                     } else {
    367                         onPackageRemoved(packageName, userIds);
    368                     }
    369                     break;
    370                 default:
    371                     // do nothing
    372                     break;
    373             }
    374         }
    375 
    376         private void onPackageAdded(@NonNull final String packageName,
    377                 @NonNull final int[] userIds) {
    378             try {
    379                 traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName);
    380                 for (final int userId : userIds) {
    381                     synchronized (mLock) {
    382                         final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
    383                                 false);
    384                         if (pi != null && !pi.applicationInfo.isInstantApp()) {
    385                             mPackageManager.cachePackageInfo(packageName, userId, pi);
    386                             if (pi.isOverlayPackage()) {
    387                                 mImpl.onOverlayPackageAdded(packageName, userId);
    388                             } else {
    389                                 mImpl.onTargetPackageAdded(packageName, userId);
    390                             }
    391                         }
    392                     }
    393                 }
    394             } finally {
    395                 traceEnd(TRACE_TAG_RRO);
    396             }
    397         }
    398 
    399         private void onPackageChanged(@NonNull final String packageName,
    400                 @NonNull final int[] userIds) {
    401             try {
    402                 traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName);
    403                 for (int userId : userIds) {
    404                     synchronized (mLock) {
    405                         final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
    406                                 false);
    407                         if (pi != null && pi.applicationInfo.isInstantApp()) {
    408                             mPackageManager.cachePackageInfo(packageName, userId, pi);
    409                             if (pi.isOverlayPackage()) {
    410                                 mImpl.onOverlayPackageChanged(packageName, userId);
    411                             }  else {
    412                                 mImpl.onTargetPackageChanged(packageName, userId);
    413                             }
    414                         }
    415                     }
    416                 }
    417             } finally {
    418                 traceEnd(TRACE_TAG_RRO);
    419             }
    420         }
    421 
    422         private void onPackageReplacing(@NonNull final String packageName,
    423                 @NonNull final int[] userIds) {
    424             try {
    425                 traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplacing " + packageName);
    426                 for (int userId : userIds) {
    427                     synchronized (mLock) {
    428                         mPackageManager.forgetPackageInfo(packageName, userId);
    429                         final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
    430                         if (oi != null) {
    431                             mImpl.onOverlayPackageReplacing(packageName, userId);
    432                         }
    433                     }
    434                 }
    435             } finally {
    436                 traceEnd(TRACE_TAG_RRO);
    437             }
    438         }
    439 
    440         private void onPackageReplaced(@NonNull final String packageName,
    441                 @NonNull final int[] userIds) {
    442             try {
    443                 traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplaced " + packageName);
    444                 for (int userId : userIds) {
    445                     synchronized (mLock) {
    446                         final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
    447                                 false);
    448                         if (pi != null && !pi.applicationInfo.isInstantApp()) {
    449                             mPackageManager.cachePackageInfo(packageName, userId, pi);
    450                             if (pi.isOverlayPackage()) {
    451                                 mImpl.onOverlayPackageReplaced(packageName, userId);
    452                             } else {
    453                                 mImpl.onTargetPackageReplaced(packageName, userId);
    454                             }
    455                         }
    456                     }
    457                 }
    458             } finally {
    459                 traceEnd(TRACE_TAG_RRO);
    460             }
    461         }
    462 
    463         private void onPackageRemoved(@NonNull final String packageName,
    464                 @NonNull final int[] userIds) {
    465             try {
    466                 traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName);
    467                 for (int userId : userIds) {
    468                     synchronized (mLock) {
    469                         mPackageManager.forgetPackageInfo(packageName, userId);
    470                         final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
    471                         if (oi != null) {
    472                             mImpl.onOverlayPackageRemoved(packageName, userId);
    473                         } else {
    474                             mImpl.onTargetPackageRemoved(packageName, userId);
    475                         }
    476                     }
    477                 }
    478             } finally {
    479                 traceEnd(TRACE_TAG_RRO);
    480             }
    481         }
    482     }
    483 
    484     private final class UserReceiver extends BroadcastReceiver {
    485         @Override
    486         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
    487             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
    488             switch (intent.getAction()) {
    489                 case ACTION_USER_ADDED:
    490                     if (userId != UserHandle.USER_NULL) {
    491                         try {
    492                             traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
    493                             final ArrayList<String> targets;
    494                             synchronized (mLock) {
    495                                 targets = mImpl.updateOverlaysForUser(userId);
    496                             }
    497                             updateOverlayPaths(userId, targets);
    498                         } finally {
    499                             traceEnd(TRACE_TAG_RRO);
    500                         }
    501                     }
    502                     break;
    503 
    504                 case ACTION_USER_REMOVED:
    505                     if (userId != UserHandle.USER_NULL) {
    506                         try {
    507                             traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED");
    508                             synchronized (mLock) {
    509                                 mImpl.onUserRemoved(userId);
    510                                 mPackageManager.forgetAllPackageInfos(userId);
    511                             }
    512                         } finally {
    513                             traceEnd(TRACE_TAG_RRO);
    514                         }
    515                     }
    516                     break;
    517                 default:
    518                     // do nothing
    519                     break;
    520             }
    521         }
    522     }
    523 
    524     private final IBinder mService = new IOverlayManager.Stub() {
    525         @Override
    526         public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
    527             try {
    528                 traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId);
    529                 userId = handleIncomingUser(userId, "getAllOverlays");
    530 
    531                 synchronized (mLock) {
    532                     return mImpl.getOverlaysForUser(userId);
    533                 }
    534             } finally {
    535                 traceEnd(TRACE_TAG_RRO);
    536             }
    537         }
    538 
    539         @Override
    540         public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
    541                 int userId) throws RemoteException {
    542             try {
    543                 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName);
    544                 userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
    545                 if (targetPackageName == null) {
    546                     return Collections.emptyList();
    547                 }
    548 
    549                 synchronized (mLock) {
    550                     return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
    551                 }
    552             } finally {
    553                 traceEnd(TRACE_TAG_RRO);
    554             }
    555         }
    556 
    557         @Override
    558         public OverlayInfo getOverlayInfo(@Nullable final String packageName,
    559                 int userId) throws RemoteException {
    560             try {
    561                 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName);
    562                 userId = handleIncomingUser(userId, "getOverlayInfo");
    563                 if (packageName == null) {
    564                     return null;
    565                 }
    566 
    567                 synchronized (mLock) {
    568                     return mImpl.getOverlayInfo(packageName, userId);
    569                 }
    570             } finally {
    571                 traceEnd(TRACE_TAG_RRO);
    572             }
    573         }
    574 
    575         @Override
    576         public boolean setEnabled(@Nullable final String packageName, final boolean enable,
    577                 int userId) throws RemoteException {
    578             try {
    579                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable);
    580                 enforceChangeOverlayPackagesPermission("setEnabled");
    581                 userId = handleIncomingUser(userId, "setEnabled");
    582                 if (packageName == null) {
    583                     return false;
    584                 }
    585 
    586                 final long ident = Binder.clearCallingIdentity();
    587                 try {
    588                     synchronized (mLock) {
    589                         return mImpl.setEnabled(packageName, enable, userId);
    590                     }
    591                 } finally {
    592                     Binder.restoreCallingIdentity(ident);
    593                 }
    594             } finally {
    595                 traceEnd(TRACE_TAG_RRO);
    596             }
    597         }
    598 
    599         @Override
    600         public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
    601                 int userId) throws RemoteException {
    602             try {
    603                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable);
    604                 enforceChangeOverlayPackagesPermission("setEnabledExclusive");
    605                 userId = handleIncomingUser(userId, "setEnabledExclusive");
    606                 if (packageName == null || !enable) {
    607                     return false;
    608                 }
    609 
    610                 final long ident = Binder.clearCallingIdentity();
    611                 try {
    612                     synchronized (mLock) {
    613                         return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
    614                                 userId);
    615                     }
    616                 } finally {
    617                     Binder.restoreCallingIdentity(ident);
    618                 }
    619             } finally {
    620                 traceEnd(TRACE_TAG_RRO);
    621             }
    622         }
    623 
    624         @Override
    625         public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
    626                 throws RemoteException {
    627             try {
    628                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
    629                 enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
    630                 userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
    631                 if (packageName == null) {
    632                     return false;
    633                 }
    634 
    635                 final long ident = Binder.clearCallingIdentity();
    636                 try {
    637                     synchronized (mLock) {
    638                         return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
    639                                 userId);
    640                     }
    641                 } finally {
    642                     Binder.restoreCallingIdentity(ident);
    643                 }
    644             } finally {
    645                 traceEnd(TRACE_TAG_RRO);
    646             }
    647         }
    648 
    649         @Override
    650         public boolean setPriority(@Nullable final String packageName,
    651                 @Nullable final String parentPackageName, int userId) throws RemoteException {
    652             try {
    653                 traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " "
    654                         + parentPackageName);
    655                 enforceChangeOverlayPackagesPermission("setPriority");
    656                 userId = handleIncomingUser(userId, "setPriority");
    657                 if (packageName == null || parentPackageName == null) {
    658                     return false;
    659                 }
    660 
    661                 final long ident = Binder.clearCallingIdentity();
    662                 try {
    663                     synchronized (mLock) {
    664                         return mImpl.setPriority(packageName, parentPackageName, userId);
    665                     }
    666                 } finally {
    667                     Binder.restoreCallingIdentity(ident);
    668                 }
    669             } finally {
    670                 traceEnd(TRACE_TAG_RRO);
    671             }
    672         }
    673 
    674         @Override
    675         public boolean setHighestPriority(@Nullable final String packageName, int userId)
    676                 throws RemoteException {
    677             try {
    678                 traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName);
    679                 enforceChangeOverlayPackagesPermission("setHighestPriority");
    680                 userId = handleIncomingUser(userId, "setHighestPriority");
    681                 if (packageName == null) {
    682                     return false;
    683                 }
    684 
    685                 final long ident = Binder.clearCallingIdentity();
    686                 try {
    687                     synchronized (mLock) {
    688                         return mImpl.setHighestPriority(packageName, userId);
    689                     }
    690                 } finally {
    691                     Binder.restoreCallingIdentity(ident);
    692                 }
    693             } finally {
    694                 traceEnd(TRACE_TAG_RRO);
    695             }
    696         }
    697 
    698         @Override
    699         public boolean setLowestPriority(@Nullable final String packageName, int userId)
    700                 throws RemoteException {
    701             try {
    702                 traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName);
    703                 enforceChangeOverlayPackagesPermission("setLowestPriority");
    704                 userId = handleIncomingUser(userId, "setLowestPriority");
    705                 if (packageName == null) {
    706                     return false;
    707                 }
    708 
    709                 final long ident = Binder.clearCallingIdentity();
    710                 try {
    711                     synchronized (mLock) {
    712                         return mImpl.setLowestPriority(packageName, userId);
    713                     }
    714                 } finally {
    715                     Binder.restoreCallingIdentity(ident);
    716                 }
    717             } finally {
    718                 traceEnd(TRACE_TAG_RRO);
    719             }
    720         }
    721 
    722         @Override
    723         public String[] getDefaultOverlayPackages() throws RemoteException {
    724             try {
    725                 traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages");
    726                 getContext().enforceCallingOrSelfPermission(
    727                         android.Manifest.permission.MODIFY_THEME_OVERLAY, null);
    728 
    729                 final long ident = Binder.clearCallingIdentity();
    730                 try {
    731                     synchronized (mLock) {
    732                         return mImpl.getDefaultOverlayPackages();
    733                     }
    734                 } finally {
    735                     Binder.restoreCallingIdentity(ident);
    736                 }
    737             } finally {
    738                 traceEnd(TRACE_TAG_RRO);
    739             }
    740         }
    741 
    742         @Override
    743         public void onShellCommand(@NonNull final FileDescriptor in,
    744                 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
    745                 @NonNull final String[] args, @NonNull final ShellCallback callback,
    746                 @NonNull final ResultReceiver resultReceiver) {
    747             (new OverlayManagerShellCommand(this)).exec(
    748                     this, in, out, err, args, callback, resultReceiver);
    749         }
    750 
    751         @Override
    752         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    753             final DumpState dumpState = new DumpState();
    754             dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid()));
    755 
    756             int opti = 0;
    757             while (opti < args.length) {
    758                 final String opt = args[opti];
    759                 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
    760                     break;
    761                 }
    762                 opti++;
    763 
    764                 if ("-h".equals(opt)) {
    765                     pw.println("dump [-h] [--verbose] [--user USER_ID] [[FIELD] PACKAGE]");
    766                     pw.println("  Print debugging information about the overlay manager.");
    767                     pw.println("  With optional parameter PACKAGE, limit output to the specified");
    768                     pw.println("  package. With optional parameter FIELD, limit output to");
    769                     pw.println("  the value of that SettingsItem field. Field names are");
    770                     pw.println("  case insensitive and out.println the m prefix can be omitted,");
    771                     pw.println("  so the following are equivalent: mState, mstate, State, state.");
    772                     return;
    773                 } else if ("--user".equals(opt)) {
    774                     opti++;
    775                     if (opti >= args.length) {
    776                         pw.println("Error: user missing argument");
    777                         return;
    778                     }
    779                     try {
    780                         dumpState.setUserId(Integer.parseInt(args[opti]));
    781                     } catch (NumberFormatException e) {
    782                         pw.println("Error: user argument is not a number: " + args[opti]);
    783                         return;
    784                     }
    785                 } else if ("--verbose".equals(opt)) {
    786                     dumpState.setVerbose(true);
    787                 } else {
    788                     pw.println("Unknown argument: " + opt + "; use -h for help");
    789                 }
    790             }
    791             if (opti < args.length) {
    792                 final String arg = args[opti];
    793                 opti++;
    794                 switch (arg) {
    795                     case "packagename":
    796                     case "userid":
    797                     case "targetpackagename":
    798                     case "targetoverlayablename":
    799                     case "basecodepath":
    800                     case "state":
    801                     case "isenabled":
    802                     case "isstatic":
    803                     case "priority":
    804                     case "category":
    805                         dumpState.setField(arg);
    806                         break;
    807                     default:
    808                         dumpState.setPackageName(arg);
    809                         break;
    810                 }
    811             }
    812             if (dumpState.getPackageName() == null && opti < args.length) {
    813                 dumpState.setPackageName(args[opti]);
    814                 opti++;
    815             }
    816 
    817             enforceDumpPermission("dump");
    818             synchronized (mLock) {
    819                 mImpl.dump(pw, dumpState);
    820                 if (dumpState.getPackageName() == null) {
    821                     mPackageManager.dump(pw, dumpState);
    822                 }
    823             }
    824         }
    825 
    826         /**
    827          * Ensure that the caller has permission to interact with the given userId.
    828          * If the calling user is not the same as the provided user, the caller needs
    829          * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
    830          * root).
    831          *
    832          * @param userId the user to interact with
    833          * @param message message for any SecurityException
    834          */
    835         private int handleIncomingUser(final int userId, @NonNull final String message) {
    836             return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
    837                     Binder.getCallingUid(), userId, false, true, message, null);
    838         }
    839 
    840         /**
    841          * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
    842          * system or root).
    843          *
    844          * @param message used as message if SecurityException is thrown
    845          * @throws SecurityException if the permission check fails
    846          */
    847         private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
    848             getContext().enforceCallingOrSelfPermission(
    849                     android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
    850         }
    851 
    852         /**
    853          * Enforce that the caller holds the DUMP permission (or is system or root).
    854          *
    855          * @param message used as message if SecurityException is thrown
    856          * @throws SecurityException if the permission check fails
    857          */
    858         private void enforceDumpPermission(@NonNull final String message) {
    859             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
    860         }
    861     };
    862 
    863     private final class OverlayChangeListener
    864             implements OverlayManagerServiceImpl.OverlayChangeListener {
    865         @Override
    866         public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
    867             schedulePersistSettings();
    868             FgThread.getHandler().post(() -> {
    869                 updateAssets(userId, targetPackageName);
    870 
    871                 final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
    872                         Uri.fromParts("package", targetPackageName, null));
    873                 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    874 
    875                 if (DEBUG) {
    876                     Slog.d(TAG, "send broadcast " + intent);
    877                 }
    878 
    879                 try {
    880                     ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
    881                             null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
    882                             userId);
    883                 } catch (RemoteException e) {
    884                     // Intentionally left empty.
    885                 }
    886             });
    887         }
    888     }
    889 
    890     /**
    891      * Updates the target packages' set of enabled overlays in PackageManager.
    892      */
    893     private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
    894         try {
    895             traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
    896             if (DEBUG) {
    897                 Slog.d(TAG, "Updating overlay assets");
    898             }
    899             final PackageManagerInternal pm =
    900                     LocalServices.getService(PackageManagerInternal.class);
    901             final boolean updateFrameworkRes = targetPackageNames.contains("android");
    902             if (updateFrameworkRes) {
    903                 targetPackageNames = pm.getTargetPackageNames(userId);
    904             }
    905 
    906             final Map<String, List<String>> pendingChanges =
    907                     new ArrayMap<>(targetPackageNames.size());
    908             synchronized (mLock) {
    909                 final List<String> frameworkOverlays =
    910                         mImpl.getEnabledOverlayPackageNames("android", userId);
    911                 final int n = targetPackageNames.size();
    912                 for (int i = 0; i < n; i++) {
    913                     final String targetPackageName = targetPackageNames.get(i);
    914                     List<String> list = new ArrayList<>();
    915                     if (!"android".equals(targetPackageName)) {
    916                         list.addAll(frameworkOverlays);
    917                     }
    918                     list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
    919                     pendingChanges.put(targetPackageName, list);
    920                 }
    921             }
    922 
    923             final int n = targetPackageNames.size();
    924             for (int i = 0; i < n; i++) {
    925                 final String targetPackageName = targetPackageNames.get(i);
    926                 if (DEBUG) {
    927                     Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
    928                             + TextUtils.join(",", pendingChanges.get(targetPackageName))
    929                             + "] userId=" + userId);
    930                 }
    931 
    932                 if (!pm.setEnabledOverlayPackages(
    933                         userId, targetPackageName, pendingChanges.get(targetPackageName))) {
    934                     Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
    935                             targetPackageName, userId));
    936                 }
    937             }
    938         } finally {
    939             traceEnd(TRACE_TAG_RRO);
    940         }
    941     }
    942 
    943     private void updateAssets(final int userId, final String targetPackageName) {
    944         updateAssets(userId, Collections.singletonList(targetPackageName));
    945     }
    946 
    947     private void updateAssets(final int userId, List<String> targetPackageNames) {
    948         updateOverlayPaths(userId, targetPackageNames);
    949         final IActivityManager am = ActivityManager.getService();
    950         try {
    951             am.scheduleApplicationInfoChanged(targetPackageNames, userId);
    952         } catch (RemoteException e) {
    953             // Intentionally left empty.
    954         }
    955     }
    956 
    957     private void schedulePersistSettings() {
    958         if (mPersistSettingsScheduled.getAndSet(true)) {
    959             return;
    960         }
    961         IoThread.getHandler().post(() -> {
    962             mPersistSettingsScheduled.set(false);
    963             if (DEBUG) {
    964                 Slog.d(TAG, "Writing overlay settings");
    965             }
    966             synchronized (mLock) {
    967                 FileOutputStream stream = null;
    968                 try {
    969                     stream = mSettingsFile.startWrite();
    970                     mSettings.persist(stream);
    971                     mSettingsFile.finishWrite(stream);
    972                 } catch (IOException | XmlPullParserException e) {
    973                     mSettingsFile.failWrite(stream);
    974                     Slog.e(TAG, "failed to persist overlay state", e);
    975                 }
    976             }
    977         });
    978     }
    979 
    980     private void restoreSettings() {
    981         try {
    982             traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
    983             synchronized (mLock) {
    984                 if (!mSettingsFile.getBaseFile().exists()) {
    985                     return;
    986                 }
    987                 try (FileInputStream stream = mSettingsFile.openRead()) {
    988                     mSettings.restore(stream);
    989 
    990                     // We might have data for dying users if the device was
    991                     // restarted before we received USER_REMOVED. Remove data for
    992                     // users that will not exist after the system is ready.
    993 
    994                     final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
    995                     final int[] liveUserIds = new int[liveUsers.size()];
    996                     for (int i = 0; i < liveUsers.size(); i++) {
    997                         liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
    998                     }
    999                     Arrays.sort(liveUserIds);
   1000 
   1001                     for (int userId : mSettings.getUsers()) {
   1002                         if (Arrays.binarySearch(liveUserIds, userId) < 0) {
   1003                             mSettings.removeUser(userId);
   1004                         }
   1005                     }
   1006                 } catch (IOException | XmlPullParserException e) {
   1007                     Slog.e(TAG, "failed to restore overlay state", e);
   1008                 }
   1009             }
   1010         } finally {
   1011             traceEnd(TRACE_TAG_RRO);
   1012         }
   1013     }
   1014 
   1015     private static final class PackageManagerHelper implements
   1016             OverlayManagerServiceImpl.PackageManagerHelper {
   1017 
   1018         private final IPackageManager mPackageManager;
   1019         private final PackageManagerInternal mPackageManagerInternal;
   1020 
   1021         // Use a cache for performance and for consistency within OMS: because
   1022         // additional PACKAGE_* intents may be delivered while we process an
   1023         // intent, querying the PackageManagerService for the actual current
   1024         // state may lead to contradictions within OMS. Better then to lag
   1025         // behind until all pending intents have been processed.
   1026         private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
   1027 
   1028         PackageManagerHelper() {
   1029             mPackageManager = getPackageManager();
   1030             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
   1031         }
   1032 
   1033         public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
   1034                 final boolean useCache) {
   1035             if (useCache) {
   1036                 final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId);
   1037                 if (cachedPi != null) {
   1038                     return cachedPi;
   1039                 }
   1040             }
   1041             try {
   1042                 final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId);
   1043                 if (useCache && pi != null) {
   1044                     cachePackageInfo(packageName, userId, pi);
   1045                 }
   1046                 return pi;
   1047             } catch (RemoteException e) {
   1048                 // Intentionally left empty.
   1049             }
   1050             return null;
   1051         }
   1052 
   1053         @Override
   1054         public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
   1055             return getPackageInfo(packageName, userId, true);
   1056         }
   1057 
   1058         @Override
   1059         public boolean signaturesMatching(@NonNull final String packageName1,
   1060                 @NonNull final String packageName2, final int userId) {
   1061             // The package manager does not support different versions of packages
   1062             // to be installed for different users: ignore userId for now.
   1063             try {
   1064                 return mPackageManager.checkSignatures(
   1065                         packageName1, packageName2) == SIGNATURE_MATCH;
   1066             } catch (RemoteException e) {
   1067                 // Intentionally left blank
   1068             }
   1069             return false;
   1070         }
   1071 
   1072         @Override
   1073         public List<PackageInfo> getOverlayPackages(final int userId) {
   1074             return mPackageManagerInternal.getOverlayPackages(userId);
   1075         }
   1076 
   1077         public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
   1078                 final int userId) {
   1079             final HashMap<String, PackageInfo> map = mCache.get(userId);
   1080             return map == null ? null : map.get(packageName);
   1081         }
   1082 
   1083         public void cachePackageInfo(@NonNull final String packageName, final int userId,
   1084                 @NonNull final PackageInfo pi) {
   1085             HashMap<String, PackageInfo> map = mCache.get(userId);
   1086             if (map == null) {
   1087                 map = new HashMap<>();
   1088                 mCache.put(userId, map);
   1089             }
   1090             map.put(packageName, pi);
   1091         }
   1092 
   1093         public void forgetPackageInfo(@NonNull final String packageName, final int userId) {
   1094             final HashMap<String, PackageInfo> map = mCache.get(userId);
   1095             if (map == null) {
   1096                 return;
   1097             }
   1098             map.remove(packageName);
   1099             if (map.isEmpty()) {
   1100                 mCache.delete(userId);
   1101             }
   1102         }
   1103 
   1104         public void forgetAllPackageInfos(final int userId) {
   1105             mCache.delete(userId);
   1106         }
   1107 
   1108         private static final String TAB1 = "    ";
   1109         private static final String TAB2 = TAB1 + TAB1;
   1110 
   1111         public void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
   1112             pw.println("PackageInfo cache");
   1113 
   1114             if (!dumpState.isVerbose()) {
   1115                 int count = 0;
   1116                 final int n = mCache.size();
   1117                 for (int i = 0; i < n; i++) {
   1118                     final int userId = mCache.keyAt(i);
   1119                     count += mCache.get(userId).size();
   1120                 }
   1121                 pw.println(TAB1 + count + " package(s)");
   1122                 return;
   1123             }
   1124 
   1125             if (mCache.size() == 0) {
   1126                 pw.println(TAB1 + "<empty>");
   1127                 return;
   1128             }
   1129 
   1130             final int n = mCache.size();
   1131             for (int i = 0; i < n; i++) {
   1132                 final int userId = mCache.keyAt(i);
   1133                 pw.println(TAB1 + "User " + userId);
   1134                 final HashMap<String, PackageInfo> map = mCache.get(userId);
   1135                 for (Map.Entry<String, PackageInfo> entry : map.entrySet()) {
   1136                     pw.println(TAB2 + entry.getKey() + ": " + entry.getValue());
   1137                 }
   1138             }
   1139         }
   1140     }
   1141 }
   1142