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