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