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.content.om.OverlayInfo.STATE_DISABLED;
     20 import static android.content.om.OverlayInfo.STATE_ENABLED;
     21 import static android.content.om.OverlayInfo.STATE_ENABLED_STATIC;
     22 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
     23 import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
     24 import static android.content.om.OverlayInfo.STATE_OVERLAY_UPGRADING;
     25 import static android.content.om.OverlayInfo.STATE_TARGET_UPGRADING;
     26 
     27 import static com.android.server.om.OverlayManagerService.DEBUG;
     28 import static com.android.server.om.OverlayManagerService.TAG;
     29 
     30 import android.annotation.NonNull;
     31 import android.annotation.Nullable;
     32 import android.content.om.OverlayInfo;
     33 import android.content.pm.PackageInfo;
     34 import android.text.TextUtils;
     35 import android.util.ArrayMap;
     36 import android.util.ArraySet;
     37 import android.util.Slog;
     38 
     39 import java.io.PrintWriter;
     40 import java.util.ArrayList;
     41 import java.util.Iterator;
     42 import java.util.List;
     43 import java.util.Map;
     44 import java.util.Objects;
     45 import java.util.Set;
     46 
     47 /**
     48  * Internal implementation of OverlayManagerService.
     49  *
     50  * Methods in this class should only be called by the OverlayManagerService.
     51  * This class is not thread-safe; the caller is expected to ensure the
     52  * necessary thread synchronization.
     53  *
     54  * @see OverlayManagerService
     55  */
     56 final class OverlayManagerServiceImpl {
     57     // Flags to use in conjunction with updateState.
     58     private static final int FLAG_TARGET_IS_UPGRADING = 1<<0;
     59     private static final int FLAG_OVERLAY_IS_UPGRADING = 1<<1;
     60 
     61     private final PackageManagerHelper mPackageManager;
     62     private final IdmapManager mIdmapManager;
     63     private final OverlayManagerSettings mSettings;
     64     private final String[] mDefaultOverlays;
     65     private final OverlayChangeListener mListener;
     66 
     67     /**
     68      * Helper method to merge the overlay manager's (as read from overlays.xml)
     69      * and package manager's (as parsed from AndroidManifest.xml files) views
     70      * on overlays.
     71      *
     72      * Both managers are usually in agreement, but especially after an OTA things
     73      * may differ. The package manager is always providing the truth; the overlay
     74      * manager has to adapt. Depending on what has changed about an overlay, we
     75      * should either scrap the overlay manager's previous settings or merge the old
     76      * settings with the new.
     77      */
     78     private static boolean mustReinitializeOverlay(@NonNull final PackageInfo theTruth,
     79             @Nullable final OverlayInfo oldSettings) {
     80         if (oldSettings == null) {
     81             return true;
     82         }
     83         if (!Objects.equals(theTruth.overlayTarget, oldSettings.targetPackageName)) {
     84             return true;
     85         }
     86         if (theTruth.isStaticOverlayPackage() != oldSettings.isStatic) {
     87             return true;
     88         }
     89         // a change in priority is only relevant for static RROs: specifically,
     90         // a regular RRO should not have its state reset only because a change
     91         // in priority
     92         if (theTruth.isStaticOverlayPackage() &&
     93                 theTruth.overlayPriority != oldSettings.priority) {
     94             return true;
     95         }
     96         return false;
     97     }
     98 
     99     OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
    100             @NonNull final IdmapManager idmapManager,
    101             @NonNull final OverlayManagerSettings settings,
    102             @NonNull final String[] defaultOverlays,
    103             @NonNull final OverlayChangeListener listener) {
    104         mPackageManager = packageManager;
    105         mIdmapManager = idmapManager;
    106         mSettings = settings;
    107         mDefaultOverlays = defaultOverlays;
    108         mListener = listener;
    109     }
    110 
    111     /**
    112      * Call this to synchronize the Settings for a user with what PackageManager knows about a user.
    113      * Returns a list of target packages that must refresh their overlays. This list is the union
    114      * of two sets: the set of targets with currently active overlays, and the
    115      * set of targets that had, but no longer have, active overlays.
    116      */
    117     ArrayList<String> updateOverlaysForUser(final int newUserId) {
    118         if (DEBUG) {
    119             Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId);
    120         }
    121 
    122         final Set<String> packagesToUpdateAssets = new ArraySet<>();
    123         final ArrayMap<String, List<OverlayInfo>> tmp = mSettings.getOverlaysForUser(newUserId);
    124         final int tmpSize = tmp.size();
    125         final ArrayMap<String, OverlayInfo> storedOverlayInfos = new ArrayMap<>(tmpSize);
    126         for (int i = 0; i < tmpSize; i++) {
    127             final List<OverlayInfo> chunk = tmp.valueAt(i);
    128             final int chunkSize = chunk.size();
    129             for (int j = 0; j < chunkSize; j++) {
    130                 final OverlayInfo oi = chunk.get(j);
    131                 storedOverlayInfos.put(oi.packageName, oi);
    132             }
    133         }
    134 
    135         // Reset overlays if something critical like the target package name
    136         // has changed
    137         List<PackageInfo> overlayPackages = mPackageManager.getOverlayPackages(newUserId);
    138         final int overlayPackagesSize = overlayPackages.size();
    139         for (int i = 0; i < overlayPackagesSize; i++) {
    140             final PackageInfo overlayPackage = overlayPackages.get(i);
    141             final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
    142 
    143             if (mustReinitializeOverlay(overlayPackage, oi)) {
    144                 // if targetPackageName has changed the package that *used* to
    145                 // be the target must also update its assets
    146                 if (oi != null) {
    147                     packagesToUpdateAssets.add(oi.targetPackageName);
    148                 }
    149 
    150                 mSettings.init(overlayPackage.packageName, newUserId,
    151                         overlayPackage.overlayTarget,
    152                         overlayPackage.applicationInfo.getBaseCodePath(),
    153                         overlayPackage.isStaticOverlayPackage(),
    154                         overlayPackage.overlayPriority,
    155                         overlayPackage.overlayCategory);
    156             }
    157 
    158             storedOverlayInfos.remove(overlayPackage.packageName);
    159         }
    160 
    161         // any OverlayInfo left in storedOverlayInfos is no longer
    162         // installed and should be removed
    163         final int storedOverlayInfosSize = storedOverlayInfos.size();
    164         for (int i = 0; i < storedOverlayInfosSize; i++) {
    165             final OverlayInfo oi = storedOverlayInfos.valueAt(i);
    166             mSettings.remove(oi.packageName, oi.userId);
    167             removeIdmapIfPossible(oi);
    168             packagesToUpdateAssets.add(oi.targetPackageName);
    169         }
    170 
    171         // make sure every overlay's state is up-to-date; this needs to happen
    172         // after old overlays have been removed, or we risk removing a
    173         // legitimate idmap file if a new overlay package has the same apk path
    174         // as the removed overlay package used to have
    175         for (int i = 0; i < overlayPackagesSize; i++) {
    176             final PackageInfo overlayPackage = overlayPackages.get(i);
    177             try {
    178                 updateState(overlayPackage.overlayTarget, overlayPackage.packageName,
    179                         newUserId, 0);
    180             } catch (OverlayManagerSettings.BadKeyException e) {
    181                 Slog.e(TAG, "failed to update settings", e);
    182                 mSettings.remove(overlayPackage.packageName, newUserId);
    183             }
    184             packagesToUpdateAssets.add(overlayPackage.overlayTarget);
    185         }
    186 
    187         // remove target packages that are not installed
    188         final Iterator<String> iter = packagesToUpdateAssets.iterator();
    189         while (iter.hasNext()) {
    190             String targetPackageName = iter.next();
    191             if (mPackageManager.getPackageInfo(targetPackageName, newUserId) == null) {
    192                 iter.remove();
    193             }
    194         }
    195 
    196         // Collect all of the categories in which we have at least one overlay enabled.
    197         final ArraySet<String> enabledCategories = new ArraySet<>();
    198         final ArrayMap<String, List<OverlayInfo>> userOverlays =
    199                 mSettings.getOverlaysForUser(newUserId);
    200         final int userOverlayTargetCount = userOverlays.size();
    201         for (int i = 0; i < userOverlayTargetCount; i++) {
    202             final List<OverlayInfo> overlayList = userOverlays.valueAt(i);
    203             final int overlayCount = overlayList != null ? overlayList.size() : 0;
    204             for (int j = 0; j < overlayCount; j++) {
    205                 final OverlayInfo oi = overlayList.get(j);
    206                 if (oi.isEnabled()) {
    207                     enabledCategories.add(oi.category);
    208                 }
    209             }
    210         }
    211 
    212         // Enable the default overlay if its category does not have a single overlay enabled.
    213         for (final String defaultOverlay : mDefaultOverlays) {
    214             try {
    215                 final OverlayInfo oi = mSettings.getOverlayInfo(defaultOverlay, newUserId);
    216                 if (!enabledCategories.contains(oi.category)) {
    217                     Slog.w(TAG, "Enabling default overlay '" + defaultOverlay + "' for target '"
    218                             + oi.targetPackageName + "' in category '" + oi.category + "' for user "
    219                             + newUserId);
    220                     mSettings.setEnabled(oi.packageName, newUserId, true);
    221                     if (updateState(oi.targetPackageName, oi.packageName, newUserId, 0)) {
    222                         packagesToUpdateAssets.add(oi.targetPackageName);
    223                     }
    224                 }
    225             } catch (OverlayManagerSettings.BadKeyException e) {
    226                 Slog.e(TAG, "Failed to set default overlay '" + defaultOverlay + "' for user "
    227                         + newUserId, e);
    228             }
    229         }
    230 
    231         return new ArrayList<>(packagesToUpdateAssets);
    232     }
    233 
    234     void onUserRemoved(final int userId) {
    235         if (DEBUG) {
    236             Slog.d(TAG, "onUserRemoved userId=" + userId);
    237         }
    238         mSettings.removeUser(userId);
    239     }
    240 
    241     void onTargetPackageAdded(@NonNull final String packageName, final int userId) {
    242         if (DEBUG) {
    243             Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
    244         }
    245 
    246         if (updateAllOverlaysForTarget(packageName, userId, 0)) {
    247             mListener.onOverlaysChanged(packageName, userId);
    248         }
    249     }
    250 
    251     void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
    252         if (DEBUG) {
    253             Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
    254         }
    255 
    256         updateAllOverlaysForTarget(packageName, userId, 0);
    257     }
    258 
    259     void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
    260         if (DEBUG) {
    261             Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId="
    262                     + userId);
    263         }
    264 
    265         updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING);
    266     }
    267 
    268     void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
    269         if (DEBUG) {
    270             Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
    271         }
    272 
    273         updateAllOverlaysForTarget(packageName, userId, 0);
    274     }
    275 
    276     void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
    277         if (DEBUG) {
    278             Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
    279         }
    280 
    281         if (updateAllOverlaysForTarget(packageName, userId, 0)) {
    282             mListener.onOverlaysChanged(packageName, userId);
    283         }
    284     }
    285 
    286     /**
    287      * Update the state of any overlays for this target.
    288      *
    289      * Returns true if the system should refresh the app's overlay paths (i.e.
    290      * if the settings were modified for this target, or there is at least one
    291      * enabled framework overlay).
    292      */
    293     private boolean updateAllOverlaysForTarget(@NonNull final String targetPackageName,
    294             final int userId, final int flags) {
    295         boolean modified = false;
    296         final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(targetPackageName, userId);
    297         final int N = ois.size();
    298         for (int i = 0; i < N; i++) {
    299             final OverlayInfo oi = ois.get(i);
    300             final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
    301                     userId);
    302             if (overlayPackage == null) {
    303                 modified |= mSettings.remove(oi.packageName, oi.userId);
    304                 removeIdmapIfPossible(oi);
    305             } else {
    306                 try {
    307                     modified |= updateState(targetPackageName, oi.packageName, userId, flags);
    308                 } catch (OverlayManagerSettings.BadKeyException e) {
    309                     Slog.e(TAG, "failed to update settings", e);
    310                     modified |= mSettings.remove(oi.packageName, userId);
    311                 }
    312             }
    313         }
    314 
    315         // check for enabled framework overlays
    316         modified = modified || !getEnabledOverlayPackageNames("android", userId).isEmpty();
    317 
    318         return modified;
    319     }
    320 
    321     void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
    322         if (DEBUG) {
    323             Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId);
    324         }
    325 
    326         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    327         if (overlayPackage == null) {
    328             Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
    329             onOverlayPackageRemoved(packageName, userId);
    330             return;
    331         }
    332 
    333         mSettings.init(packageName, userId, overlayPackage.overlayTarget,
    334                 overlayPackage.applicationInfo.getBaseCodePath(),
    335                 overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority,
    336                 overlayPackage.overlayCategory);
    337         try {
    338             if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
    339                 mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
    340             }
    341         } catch (OverlayManagerSettings.BadKeyException e) {
    342             Slog.e(TAG, "failed to update settings", e);
    343             mSettings.remove(packageName, userId);
    344         }
    345     }
    346 
    347     void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
    348         if (DEBUG) {
    349             Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
    350         }
    351 
    352         try {
    353             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
    354             if (updateState(oi.targetPackageName, packageName, userId, 0)) {
    355                 mListener.onOverlaysChanged(oi.targetPackageName, userId);
    356             }
    357         } catch (OverlayManagerSettings.BadKeyException e) {
    358             Slog.e(TAG, "failed to update settings", e);
    359         }
    360     }
    361 
    362     void onOverlayPackageUpgrading(@NonNull final String packageName, final int userId) {
    363         if (DEBUG) {
    364             Slog.d(TAG, "onOverlayPackageUpgrading packageName=" + packageName + " userId="
    365                     + userId);
    366         }
    367 
    368         try {
    369             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
    370             if (updateState(oi.targetPackageName, packageName, userId, FLAG_OVERLAY_IS_UPGRADING)) {
    371                 removeIdmapIfPossible(oi);
    372                 mListener.onOverlaysChanged(oi.targetPackageName, userId);
    373             }
    374         } catch (OverlayManagerSettings.BadKeyException e) {
    375             Slog.e(TAG, "failed to update settings", e);
    376         }
    377     }
    378 
    379     void onOverlayPackageUpgraded(@NonNull final String packageName, final int userId) {
    380         if (DEBUG) {
    381             Slog.d(TAG, "onOverlayPackageUpgraded packageName=" + packageName + " userId="
    382                     + userId);
    383         }
    384 
    385         final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
    386         if (pkg == null) {
    387             Slog.w(TAG, "overlay package " + packageName + " was upgraded, but couldn't be found");
    388             onOverlayPackageRemoved(packageName, userId);
    389             return;
    390         }
    391 
    392         try {
    393             final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
    394             if (mustReinitializeOverlay(pkg, oldOi)) {
    395                 if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
    396                     mListener.onOverlaysChanged(pkg.overlayTarget, userId);
    397                 }
    398                 mSettings.init(packageName, userId, pkg.overlayTarget,
    399                         pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
    400                         pkg.overlayPriority, pkg.overlayCategory);
    401             }
    402 
    403             if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
    404                 mListener.onOverlaysChanged(pkg.overlayTarget, userId);
    405             }
    406         } catch (OverlayManagerSettings.BadKeyException e) {
    407             Slog.e(TAG, "failed to update settings", e);
    408         }
    409     }
    410 
    411     void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
    412         try {
    413             final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId);
    414             if (mSettings.remove(packageName, userId)) {
    415                 removeIdmapIfPossible(overlayInfo);
    416                 if (overlayInfo.isEnabled()) {
    417                     // Only trigger updates if the overlay was enabled.
    418                     mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId);
    419                 }
    420             }
    421         } catch (OverlayManagerSettings.BadKeyException e) {
    422             Slog.e(TAG, "failed to remove overlay", e);
    423         }
    424     }
    425 
    426     OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId) {
    427         try {
    428             return mSettings.getOverlayInfo(packageName, userId);
    429         } catch (OverlayManagerSettings.BadKeyException e) {
    430             return null;
    431         }
    432     }
    433 
    434     List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName,
    435             final int userId) {
    436         return mSettings.getOverlaysForTarget(targetPackageName, userId);
    437     }
    438 
    439     Map<String, List<OverlayInfo>> getOverlaysForUser(final int userId) {
    440         return mSettings.getOverlaysForUser(userId);
    441     }
    442 
    443     boolean setEnabled(@NonNull final String packageName, final boolean enable,
    444             final int userId) {
    445         if (DEBUG) {
    446             Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d",
    447                         packageName, enable, userId));
    448         }
    449 
    450         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    451         if (overlayPackage == null) {
    452             return false;
    453         }
    454 
    455         // Ignore static overlays.
    456         if (overlayPackage.isStaticOverlayPackage()) {
    457             return false;
    458         }
    459 
    460         try {
    461             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
    462             boolean modified = mSettings.setEnabled(packageName, userId, enable);
    463             modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
    464 
    465             if (modified) {
    466                 mListener.onOverlaysChanged(oi.targetPackageName, userId);
    467             }
    468             return true;
    469         } catch (OverlayManagerSettings.BadKeyException e) {
    470             return false;
    471         }
    472     }
    473 
    474     boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory,
    475             final int userId) {
    476         if (DEBUG) {
    477             Slog.d(TAG, String.format("setEnabledExclusive packageName=%s"
    478                     + " withinCategory=%s userId=%d", packageName, withinCategory, userId));
    479         }
    480 
    481         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    482         if (overlayPackage == null) {
    483             return false;
    484         }
    485 
    486         try {
    487             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
    488             final String targetPackageName = oi.targetPackageName;
    489 
    490             List<OverlayInfo> allOverlays = getOverlayInfosForTarget(targetPackageName, userId);
    491 
    492             boolean modified = false;
    493 
    494             // Disable all other overlays.
    495             allOverlays.remove(oi);
    496             for (int i = 0; i < allOverlays.size(); i++) {
    497                 final String disabledOverlayPackageName = allOverlays.get(i).packageName;
    498                 final PackageInfo disabledOverlayPackageInfo = mPackageManager.getPackageInfo(
    499                         disabledOverlayPackageName, userId);
    500                 if (disabledOverlayPackageInfo == null) {
    501                     modified |= mSettings.remove(disabledOverlayPackageName, userId);
    502                     continue;
    503                 }
    504 
    505                 if (disabledOverlayPackageInfo.isStaticOverlayPackage()) {
    506                     // Don't touch static overlays.
    507                     continue;
    508                 }
    509                 if (withinCategory && !Objects.equals(disabledOverlayPackageInfo.overlayCategory,
    510                         oi.category)) {
    511                     // Don't touch overlays from other categories.
    512                     continue;
    513                 }
    514 
    515                 // Disable the overlay.
    516                 modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false);
    517                 modified |= updateState(targetPackageName, disabledOverlayPackageName, userId, 0);
    518             }
    519 
    520             // Enable the selected overlay.
    521             modified |= mSettings.setEnabled(packageName, userId, true);
    522             modified |= updateState(targetPackageName, packageName, userId, 0);
    523 
    524             if (modified) {
    525                 mListener.onOverlaysChanged(targetPackageName, userId);
    526             }
    527             return true;
    528         } catch (OverlayManagerSettings.BadKeyException e) {
    529             return false;
    530         }
    531     }
    532 
    533     private boolean isPackageUpdatableOverlay(@NonNull final String packageName, final int userId) {
    534         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    535         if (overlayPackage == null || overlayPackage.isStaticOverlayPackage()) {
    536             return false;
    537         }
    538         return true;
    539     }
    540 
    541     boolean setPriority(@NonNull final String packageName,
    542             @NonNull final String newParentPackageName, final int userId) {
    543         if (DEBUG) {
    544             Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName="
    545                     + newParentPackageName + " userId=" + userId);
    546         }
    547 
    548         if (!isPackageUpdatableOverlay(packageName, userId)) {
    549             return false;
    550         }
    551 
    552         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    553         if (overlayPackage == null) {
    554             return false;
    555         }
    556 
    557         if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
    558             mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
    559         }
    560         return true;
    561     }
    562 
    563     boolean setHighestPriority(@NonNull final String packageName, final int userId) {
    564         if (DEBUG) {
    565             Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
    566         }
    567 
    568         if (!isPackageUpdatableOverlay(packageName, userId)) {
    569             return false;
    570         }
    571 
    572         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    573         if (overlayPackage == null) {
    574             return false;
    575         }
    576 
    577         if (mSettings.setHighestPriority(packageName, userId)) {
    578             mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
    579         }
    580         return true;
    581     }
    582 
    583     boolean setLowestPriority(@NonNull final String packageName, final int userId) {
    584         if (DEBUG) {
    585             Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
    586         }
    587 
    588         if (!isPackageUpdatableOverlay(packageName, userId)) {
    589             return false;
    590         }
    591 
    592         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
    593         if (overlayPackage == null) {
    594             return false;
    595         }
    596 
    597         if (mSettings.setLowestPriority(packageName, userId)) {
    598             mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
    599         }
    600         return true;
    601     }
    602 
    603     void onDump(@NonNull final PrintWriter pw) {
    604         mSettings.dump(pw);
    605         pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
    606     }
    607 
    608     List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
    609             final int userId) {
    610         final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
    611                 userId);
    612         final List<String> paths = new ArrayList<>(overlays.size());
    613         final int N = overlays.size();
    614         for (int i = 0; i < N; i++) {
    615             final OverlayInfo oi = overlays.get(i);
    616             if (oi.isEnabled()) {
    617                 paths.add(oi.packageName);
    618             }
    619         }
    620         return paths;
    621     }
    622 
    623     /**
    624      * Returns true if the settings/state was modified, false otherwise.
    625      */
    626     private boolean updateState(@NonNull final String targetPackageName,
    627             @NonNull final String overlayPackageName, final int userId, final int flags)
    628             throws OverlayManagerSettings.BadKeyException {
    629 
    630         final PackageInfo targetPackage = mPackageManager.getPackageInfo(targetPackageName, userId);
    631         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
    632                 userId);
    633 
    634         // Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
    635         if (targetPackage != null && overlayPackage != null &&
    636                 !("android".equals(targetPackageName)
    637                         && overlayPackage.isStaticOverlayPackage())) {
    638             mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
    639         }
    640 
    641         boolean modified = false;
    642         if (overlayPackage != null) {
    643             modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
    644                     overlayPackage.applicationInfo.getBaseCodePath());
    645             modified |= mSettings.setCategory(overlayPackageName, userId,
    646                     overlayPackage.overlayCategory);
    647         }
    648 
    649         final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
    650         final @OverlayInfo.State int newState = calculateNewState(targetPackage, overlayPackage,
    651                 userId, flags);
    652         if (currentState != newState) {
    653             if (DEBUG) {
    654                 Slog.d(TAG, String.format("%s:%d: %s -> %s",
    655                             overlayPackageName, userId,
    656                             OverlayInfo.stateToString(currentState),
    657                             OverlayInfo.stateToString(newState)));
    658             }
    659             modified |= mSettings.setState(overlayPackageName, userId, newState);
    660         }
    661         return modified;
    662     }
    663 
    664     private @OverlayInfo.State int calculateNewState(@Nullable final PackageInfo targetPackage,
    665             @Nullable final PackageInfo overlayPackage, final int userId, final int flags)
    666         throws OverlayManagerSettings.BadKeyException {
    667 
    668         if ((flags & FLAG_TARGET_IS_UPGRADING) != 0) {
    669             return STATE_TARGET_UPGRADING;
    670         }
    671 
    672         if ((flags & FLAG_OVERLAY_IS_UPGRADING) != 0) {
    673             return STATE_OVERLAY_UPGRADING;
    674         }
    675 
    676         // assert expectation on overlay package: can only be null if the flags are used
    677         if (DEBUG && overlayPackage == null) {
    678             throw new IllegalArgumentException("null overlay package not compatible with no flags");
    679         }
    680 
    681         if (targetPackage == null) {
    682             return STATE_MISSING_TARGET;
    683         }
    684 
    685         if (!mIdmapManager.idmapExists(overlayPackage, userId)) {
    686             return STATE_NO_IDMAP;
    687         }
    688 
    689         if (overlayPackage.isStaticOverlayPackage()) {
    690             return STATE_ENABLED_STATIC;
    691         }
    692 
    693         final boolean enabled = mSettings.getEnabled(overlayPackage.packageName, userId);
    694         return enabled ? STATE_ENABLED : STATE_DISABLED;
    695     }
    696 
    697     private void removeIdmapIfPossible(@NonNull final OverlayInfo oi) {
    698         // For a given package, all Android users share the same idmap file.
    699         // This works because Android currently does not support users to
    700         // install different versions of the same package. It also means we
    701         // cannot remove an idmap file if any user still needs it.
    702         //
    703         // When/if the Android framework allows different versions of the same
    704         // package to be installed for different users, idmap file handling
    705         // should be revised:
    706         //
    707         // - an idmap file should be unique for each {user, package} pair
    708         //
    709         // - the path to the idmap file should be passed to the native Asset
    710         //   Manager layers, just like the path to the apk is passed today
    711         //
    712         // As part of that change, calls to this method should be replaced by
    713         // direct calls to IdmapManager.removeIdmap, without looping over all
    714         // users.
    715 
    716         if (!mIdmapManager.idmapExists(oi)) {
    717             return;
    718         }
    719         final int[] userIds = mSettings.getUsers();
    720         for (int userId : userIds) {
    721             try {
    722                 final OverlayInfo tmp = mSettings.getOverlayInfo(oi.packageName, userId);
    723                 if (tmp != null && tmp.isEnabled()) {
    724                     // someone is still using the idmap file -> we cannot remove it
    725                     return;
    726                 }
    727             } catch (OverlayManagerSettings.BadKeyException e) {
    728                 // intentionally left empty
    729             }
    730         }
    731         mIdmapManager.removeIdmap(oi, oi.userId);
    732     }
    733 
    734     interface OverlayChangeListener {
    735 
    736         /**
    737          * An event triggered by changes made to overlay state or settings as well as changes that
    738          * add or remove target packages of overlays.
    739          **/
    740         void onOverlaysChanged(@NonNull String targetPackage, int userId);
    741     }
    742 
    743     interface PackageManagerHelper {
    744         PackageInfo getPackageInfo(@NonNull String packageName, int userId);
    745         boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2,
    746                                    int userId);
    747         List<PackageInfo> getOverlayPackages(int userId);
    748     }
    749 }
    750