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 */ mustReinitializeOverlay(@onNull final PackageInfo theTruth, @Nullable final OverlayInfo oldSettings)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 OverlayManagerServiceImpl(@onNull final PackageManagerHelper packageManager, @NonNull final IdmapManager idmapManager, @NonNull final OverlayManagerSettings settings, @NonNull final String[] defaultOverlays, @NonNull final OverlayChangeListener listener)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 */ updateOverlaysForUser(final int newUserId)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 onUserRemoved(final int userId)234 void onUserRemoved(final int userId) { 235 if (DEBUG) { 236 Slog.d(TAG, "onUserRemoved userId=" + userId); 237 } 238 mSettings.removeUser(userId); 239 } 240 onTargetPackageAdded(@onNull final String packageName, final int userId)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 onTargetPackageChanged(@onNull final String packageName, final int userId)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 onTargetPackageUpgrading(@onNull final String packageName, final int userId)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 onTargetPackageUpgraded(@onNull final String packageName, final int userId)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 onTargetPackageRemoved(@onNull final String packageName, final int userId)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 */ updateAllOverlaysForTarget(@onNull final String targetPackageName, final int userId, final int flags)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 onOverlayPackageAdded(@onNull final String packageName, final int userId)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 onOverlayPackageChanged(@onNull final String packageName, final int userId)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 onOverlayPackageUpgrading(@onNull final String packageName, final int userId)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 onOverlayPackageUpgraded(@onNull final String packageName, final int userId)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 onOverlayPackageRemoved(@onNull final String packageName, final int userId)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 getOverlayInfo(@onNull final String packageName, final int userId)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 getOverlayInfosForTarget(@onNull final String targetPackageName, final int userId)434 List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName, 435 final int userId) { 436 return mSettings.getOverlaysForTarget(targetPackageName, userId); 437 } 438 getOverlaysForUser(final int userId)439 Map<String, List<OverlayInfo>> getOverlaysForUser(final int userId) { 440 return mSettings.getOverlaysForUser(userId); 441 } 442 setEnabled(@onNull final String packageName, final boolean enable, final int userId)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 setEnabledExclusive(@onNull final String packageName, boolean withinCategory, final int userId)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 isPackageUpdatableOverlay(@onNull final String packageName, final int userId)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 setPriority(@onNull final String packageName, @NonNull final String newParentPackageName, final int userId)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 setHighestPriority(@onNull final String packageName, final int userId)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 setLowestPriority(@onNull final String packageName, final int userId)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 onDump(@onNull final PrintWriter pw)603 void onDump(@NonNull final PrintWriter pw) { 604 mSettings.dump(pw); 605 pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays)); 606 } 607 getEnabledOverlayPackageNames(@onNull final String targetPackageName, final int userId)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 */ updateState(@onNull final String targetPackageName, @NonNull final String overlayPackageName, final int userId, final int flags)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 calculateNewState(@ullable final PackageInfo targetPackage, @Nullable final PackageInfo overlayPackage, final int userId, final int flags)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 removeIdmapIfPossible(@onNull final OverlayInfo oi)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 **/ onOverlaysChanged(@onNull String targetPackage, int userId)740 void onOverlaysChanged(@NonNull String targetPackage, int userId); 741 } 742 743 interface PackageManagerHelper { getPackageInfo(@onNull String packageName, int userId)744 PackageInfo getPackageInfo(@NonNull String packageName, int userId); signaturesMatching(@onNull String packageName1, @NonNull String packageName2, int userId)745 boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2, 746 int userId); getOverlayPackages(int userId)747 List<PackageInfo> getOverlayPackages(int userId); 748 } 749 } 750