1 /* 2 * Copyright (C) 2015 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 android.content.om; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.annotation.UserIdInt; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.os.Build; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.Arrays; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.Objects; 37 38 /** 39 * An immutable information about an overlay. 40 * 41 * <p>Applications calling {@link OverlayManager#getOverlayInfosForTarget(String)} get the 42 * information list of the registered overlays. Each element in the list presents the information of 43 * the particular overlay. 44 * 45 * <!-- For OverlayManagerService, it isn't public part and hidden by HTML comment. --> 46 * <!-- 47 * Immutable overlay information about a package. All PackageInfos that 48 * represent an overlay package will have a corresponding OverlayInfo. 49 * --> 50 * 51 * @see OverlayManager#getOverlayInfosForTarget(String) 52 */ 53 public final class OverlayInfo implements CriticalOverlayInfo, Parcelable { 54 55 /** @hide */ 56 @IntDef(prefix = "STATE_", value = { 57 STATE_UNKNOWN, 58 STATE_MISSING_TARGET, 59 STATE_NO_IDMAP, 60 STATE_DISABLED, 61 STATE_ENABLED, 62 STATE_ENABLED_IMMUTABLE, 63 STATE_OVERLAY_IS_BEING_REPLACED, 64 STATE_SYSTEM_UPDATE_UNINSTALL, 65 }) 66 /** @hide */ 67 @Retention(RetentionPolicy.SOURCE) 68 public @interface State {} 69 70 /** 71 * An internal state used as the initial state of an overlay. OverlayInfo 72 * objects exposed outside the {@link 73 * com.android.server.om.OverlayManagerService} should never have this 74 * state. 75 * 76 * @hide 77 */ 78 public static final int STATE_UNKNOWN = -1; 79 80 /** 81 * The target package of the overlay is not installed. The overlay cannot be enabled. 82 * 83 * @hide 84 */ 85 public static final int STATE_MISSING_TARGET = 0; 86 87 /** 88 * Creation of idmap file failed (e.g. no matching resources). The overlay 89 * cannot be enabled. 90 * 91 * @hide 92 */ 93 public static final int STATE_NO_IDMAP = 1; 94 95 /** 96 * The overlay is currently disabled. It can be enabled. 97 * 98 * @see IOverlayManager#setEnabled 99 * @hide 100 */ 101 public static final int STATE_DISABLED = 2; 102 103 /** 104 * The overlay is currently enabled. It can be disabled. 105 * 106 * @see IOverlayManager#setEnabled 107 * @hide 108 */ 109 public static final int STATE_ENABLED = 3; 110 111 /** 112 * The target package is currently being upgraded or downgraded; the state 113 * will change once the package installation has finished. 114 * @hide 115 * 116 * @deprecated No longer used. Caused invalid transitions from enabled -> upgrading -> enabled, 117 * where an update is propagated when nothing has changed. Can occur during --dont-kill 118 * installs when code and resources are hot swapped and the Activity should not be relaunched. 119 * In all other cases, the process and therefore Activity is killed, so the state loop is 120 * irrelevant. 121 */ 122 @Deprecated 123 public static final int STATE_TARGET_IS_BEING_REPLACED = 4; 124 125 /** 126 * The overlay package is currently being upgraded or downgraded; the state 127 * will change once the package installation has finished. 128 * @hide 129 */ 130 public static final int STATE_OVERLAY_IS_BEING_REPLACED = 5; 131 132 /** 133 * The overlay package is currently enabled because it is marked as 134 * 'immutable'. It cannot be disabled but will change state if for instance 135 * its target is uninstalled. 136 * @hide 137 */ 138 @Deprecated 139 public static final int STATE_ENABLED_IMMUTABLE = 6; 140 141 /** 142 * The target package needs to be refreshed as a result of a system update uninstall, which 143 * must recalculate the state of overlays against the newly enabled system package, which may 144 * differ in resources/policy from the /data variant that was uninstalled. 145 * @hide 146 */ 147 public static final int STATE_SYSTEM_UPDATE_UNINSTALL = 7; 148 149 /** 150 * Overlay category: theme. 151 * <p> 152 * Change how Android (including the status bar, dialogs, ...) looks. 153 * 154 * @hide 155 */ 156 public static final String CATEGORY_THEME = "android.theme"; 157 158 /** 159 * Package name of the overlay package 160 * 161 * @hide 162 */ 163 @NonNull 164 public final String packageName; 165 166 /** 167 * The unique name within the package of the overlay. 168 * 169 * @hide 170 */ 171 @Nullable 172 public final String overlayName; 173 174 /** 175 * Package name of the target package 176 * 177 * @hide 178 */ 179 @NonNull 180 public final String targetPackageName; 181 182 /** 183 * Name of the target overlayable declaration. 184 * 185 * @hide 186 */ 187 @Nullable public final String targetOverlayableName; 188 189 /** 190 * Category of the overlay package 191 * 192 * @hide 193 */ 194 @Nullable public final String category; 195 196 /** 197 * Full path to the base APK for this overlay package 198 * @hide 199 */ 200 @NonNull 201 public final String baseCodePath; 202 203 /** 204 * The state of this OverlayInfo as defined by the STATE_* constants in this class. 205 * @hide 206 */ 207 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 208 public final @State int state; 209 210 /** 211 * User handle for which this overlay applies 212 * @hide 213 */ 214 public final int userId; 215 216 /** 217 * Priority as configured by {@link com.android.internal.content.om.OverlayConfig}. 218 * Not intended to be exposed to 3rd party. 219 * 220 * @hide 221 */ 222 public final int priority; 223 224 /** 225 * isMutable as configured by {@link com.android.internal.content.om.OverlayConfig}. 226 * If false, the overlay is unconditionally loaded and cannot be unloaded. Not intended to be 227 * exposed to 3rd party. 228 * 229 * @hide 230 */ 231 public final boolean isMutable; 232 233 private OverlayIdentifier mIdentifierCached; 234 235 /** 236 * @hide 237 */ 238 public final boolean isFabricated; 239 240 /** 241 * @hide 242 */ 243 @NonNull 244 public final List<OverlayConstraint> constraints; 245 246 /** 247 * Create a new OverlayInfo based on source with an updated state. 248 * 249 * @param source the source OverlayInfo to base the new instance on 250 * @param state the new state for the source OverlayInfo 251 * 252 * @hide 253 */ OverlayInfo(@onNull OverlayInfo source, @State int state)254 public OverlayInfo(@NonNull OverlayInfo source, @State int state) { 255 this(source.packageName, source.overlayName, source.targetPackageName, 256 source.targetOverlayableName, source.category, source.baseCodePath, state, 257 source.userId, source.priority, source.isMutable, source.isFabricated, 258 source.constraints); 259 } 260 261 /** @hide */ 262 @VisibleForTesting OverlayInfo(@onNull String packageName, @NonNull String targetPackageName, @Nullable String targetOverlayableName, @Nullable String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isMutable)263 public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, 264 @Nullable String targetOverlayableName, @Nullable String category, 265 @NonNull String baseCodePath, int state, int userId, int priority, boolean isMutable) { 266 this(packageName, null /* overlayName */, targetPackageName, targetOverlayableName, 267 category, baseCodePath, state, userId, priority, isMutable, 268 false /* isFabricated */); 269 } 270 271 /** @hide */ OverlayInfo(@onNull String packageName, @Nullable String overlayName, @NonNull String targetPackageName, @Nullable String targetOverlayableName, @Nullable String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isMutable, boolean isFabricated)272 public OverlayInfo(@NonNull String packageName, @Nullable String overlayName, 273 @NonNull String targetPackageName, @Nullable String targetOverlayableName, 274 @Nullable String category, @NonNull String baseCodePath, int state, int userId, 275 int priority, boolean isMutable, boolean isFabricated) { 276 this(packageName, overlayName, targetPackageName, targetOverlayableName, category, 277 baseCodePath, state, userId, priority, isMutable, isFabricated, 278 Collections.emptyList() /* constraints */); 279 } 280 281 /** @hide */ OverlayInfo(@onNull String packageName, @Nullable String overlayName, @NonNull String targetPackageName, @Nullable String targetOverlayableName, @Nullable String category, @NonNull String baseCodePath, int state, int userId, int priority, boolean isMutable, boolean isFabricated, @NonNull List<OverlayConstraint> constraints)282 public OverlayInfo(@NonNull String packageName, @Nullable String overlayName, 283 @NonNull String targetPackageName, @Nullable String targetOverlayableName, 284 @Nullable String category, @NonNull String baseCodePath, int state, int userId, 285 int priority, boolean isMutable, boolean isFabricated, 286 @NonNull List<OverlayConstraint> constraints) { 287 this.packageName = packageName; 288 this.overlayName = overlayName; 289 this.targetPackageName = targetPackageName; 290 this.targetOverlayableName = targetOverlayableName; 291 this.category = category; 292 this.baseCodePath = baseCodePath; 293 this.state = state; 294 this.userId = userId; 295 this.priority = priority; 296 this.isMutable = isMutable; 297 this.isFabricated = isFabricated; 298 this.constraints = constraints; 299 ensureValidState(); 300 } 301 302 /** @hide */ OverlayInfo(@onNull Parcel source)303 public OverlayInfo(@NonNull Parcel source) { 304 packageName = source.readString(); 305 overlayName = source.readString(); 306 targetPackageName = source.readString(); 307 targetOverlayableName = source.readString(); 308 category = source.readString(); 309 baseCodePath = source.readString(); 310 state = source.readInt(); 311 userId = source.readInt(); 312 priority = source.readInt(); 313 isMutable = source.readBoolean(); 314 isFabricated = source.readBoolean(); 315 constraints = Arrays.asList(source.createTypedArray(OverlayConstraint.CREATOR)); 316 ensureValidState(); 317 } 318 319 /** 320 * {@inheritDoc} 321 * @hide 322 */ 323 @Override 324 @SystemApi 325 @NonNull getPackageName()326 public String getPackageName() { 327 return packageName; 328 } 329 330 /** 331 * Get the overlay name from the registered fabricated overlay. 332 * 333 * @return the overlay name 334 */ 335 @Override 336 @Nullable getOverlayName()337 public String getOverlayName() { 338 return overlayName; 339 } 340 341 /** 342 * Returns the name of the target overlaid package. 343 * 344 * @return the target package name 345 */ 346 @Override 347 @NonNull getTargetPackageName()348 public String getTargetPackageName() { 349 return targetPackageName; 350 } 351 352 /** 353 * Returns the category of the current overlay. 354 * 355 * @hide 356 */ 357 @SystemApi 358 @Nullable getCategory()359 public String getCategory() { 360 return category; 361 } 362 363 /** 364 * Returns user handle for which this overlay applies to. 365 * 366 * @hide 367 */ 368 @SystemApi 369 @UserIdInt getUserId()370 public int getUserId() { 371 return userId; 372 } 373 374 /** 375 * Return the target overlayable name. 376 * 377 * @return the name of the target overlayable resources set 378 */ 379 @Override 380 @Nullable getTargetOverlayableName()381 public String getTargetOverlayableName() { 382 return targetOverlayableName; 383 } 384 385 /** 386 * {@inheritDoc} 387 * @hide 388 */ 389 @Override isFabricated()390 public boolean isFabricated() { 391 return isFabricated; 392 } 393 394 /** 395 * Full path to the base APK or fabricated overlay for this overlay package. 396 * 397 * @hide 398 */ 399 @NonNull getBaseCodePath()400 public String getBaseCodePath() { 401 return baseCodePath; 402 } 403 404 /** 405 * Get the unique identifier from the overlay information. 406 * 407 * <p>The return value of this function can be used to unregister the related overlay. 408 * 409 * @return an identifier representing the current overlay. 410 */ 411 @Override 412 @NonNull getOverlayIdentifier()413 public OverlayIdentifier getOverlayIdentifier() { 414 if (mIdentifierCached == null) { 415 mIdentifierCached = new OverlayIdentifier(packageName, overlayName); 416 } 417 return mIdentifierCached; 418 } 419 420 /** 421 * Returns the currently applied constraints (if any) for the overlay. An overlay 422 * may have constraints only when it is enabled. 423 * 424 * @hide 425 */ 426 @NonNull getConstraints()427 public List<OverlayConstraint> getConstraints() { 428 return constraints; 429 } 430 431 @SuppressWarnings("ConstantConditions") ensureValidState()432 private void ensureValidState() { 433 if (packageName == null) { 434 throw new IllegalArgumentException("packageName must not be null"); 435 } 436 if (targetPackageName == null) { 437 throw new IllegalArgumentException("targetPackageName must not be null"); 438 } 439 if (baseCodePath == null) { 440 throw new IllegalArgumentException("baseCodePath must not be null"); 441 } 442 if (constraints == null) { 443 throw new IllegalArgumentException("constraints must not be null"); 444 } 445 switch (state) { 446 case STATE_UNKNOWN: 447 case STATE_MISSING_TARGET: 448 case STATE_NO_IDMAP: 449 case STATE_DISABLED: 450 case STATE_ENABLED: 451 case STATE_ENABLED_IMMUTABLE: 452 case STATE_TARGET_IS_BEING_REPLACED: 453 case STATE_OVERLAY_IS_BEING_REPLACED: 454 break; 455 default: 456 throw new IllegalArgumentException("State " + state + " is not a valid state"); 457 } 458 } 459 460 @Override describeContents()461 public int describeContents() { 462 return 0; 463 } 464 465 @Override writeToParcel(@onNull Parcel dest, int flags)466 public void writeToParcel(@NonNull Parcel dest, int flags) { 467 dest.writeString(packageName); 468 dest.writeString(overlayName); 469 dest.writeString(targetPackageName); 470 dest.writeString(targetOverlayableName); 471 dest.writeString(category); 472 dest.writeString(baseCodePath); 473 dest.writeInt(state); 474 dest.writeInt(userId); 475 dest.writeInt(priority); 476 dest.writeBoolean(isMutable); 477 dest.writeBoolean(isFabricated); 478 dest.writeTypedArray(constraints.toArray(new OverlayConstraint[0]), flags); 479 } 480 481 public static final @NonNull Parcelable.Creator<OverlayInfo> CREATOR = 482 new Parcelable.Creator<>() { 483 @Override 484 public OverlayInfo createFromParcel(Parcel source) { 485 return new OverlayInfo(source); 486 } 487 488 @Override 489 public OverlayInfo[] newArray(int size) { 490 return new OverlayInfo[size]; 491 } 492 }; 493 494 /** 495 * Return true if this overlay is enabled, i.e. should be used to overlay 496 * the resources in the target package. 497 * 498 * Disabled overlay packages are installed but are currently not in use. 499 * 500 * @return true if the overlay is enabled, else false. 501 * 502 * @hide 503 */ 504 @SystemApi isEnabled()505 public boolean isEnabled() { 506 switch (state) { 507 case STATE_ENABLED: 508 case STATE_ENABLED_IMMUTABLE: 509 return true; 510 default: 511 return false; 512 } 513 } 514 515 /** 516 * Translate a state to a human readable string. Only intended for 517 * debugging purposes. 518 * 519 * @return a human readable String representing the state. 520 * 521 * @hide 522 */ stateToString(@tate int state)523 public static String stateToString(@State int state) { 524 switch (state) { 525 case STATE_UNKNOWN: 526 return "STATE_UNKNOWN"; 527 case STATE_MISSING_TARGET: 528 return "STATE_MISSING_TARGET"; 529 case STATE_NO_IDMAP: 530 return "STATE_NO_IDMAP"; 531 case STATE_DISABLED: 532 return "STATE_DISABLED"; 533 case STATE_ENABLED: 534 return "STATE_ENABLED"; 535 case STATE_ENABLED_IMMUTABLE: 536 return "STATE_ENABLED_IMMUTABLE"; 537 case STATE_TARGET_IS_BEING_REPLACED: 538 return "STATE_TARGET_IS_BEING_REPLACED"; 539 case STATE_OVERLAY_IS_BEING_REPLACED: 540 return "STATE_OVERLAY_IS_BEING_REPLACED"; 541 default: 542 return "<unknown state>"; 543 } 544 } 545 546 /** 547 * {@inheritDoc} 548 * 549 * @hide 550 */ 551 @Override hashCode()552 public int hashCode() { 553 final int prime = 31; 554 int result = 1; 555 result = prime * result + userId; 556 result = prime * result + state; 557 result = prime * result + ((packageName == null) ? 0 : packageName.hashCode()); 558 result = prime * result + ((overlayName == null) ? 0 : overlayName.hashCode()); 559 result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode()); 560 result = prime * result + ((targetOverlayableName == null) ? 0 561 : targetOverlayableName.hashCode()); 562 result = prime * result + ((category == null) ? 0 : category.hashCode()); 563 result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode()); 564 result = prime * result + (constraints.isEmpty() ? 0 : constraints.hashCode()); 565 return result; 566 } 567 568 /** 569 * {@inheritDoc} 570 * 571 * @hide 572 */ 573 @Override equals(@ullable Object obj)574 public boolean equals(@Nullable Object obj) { 575 if (this == obj) { 576 return true; 577 } 578 if (obj == null) { 579 return false; 580 } 581 if (getClass() != obj.getClass()) { 582 return false; 583 } 584 OverlayInfo other = (OverlayInfo) obj; 585 if (userId != other.userId) { 586 return false; 587 } 588 if (state != other.state) { 589 return false; 590 } 591 if (!packageName.equals(other.packageName)) { 592 return false; 593 } 594 if (!Objects.equals(overlayName, other.overlayName)) { 595 return false; 596 } 597 if (!targetPackageName.equals(other.targetPackageName)) { 598 return false; 599 } 600 if (!Objects.equals(targetOverlayableName, other.targetOverlayableName)) { 601 return false; 602 } 603 if (!Objects.equals(category, other.category)) { 604 return false; 605 } 606 if (!baseCodePath.equals(other.baseCodePath)) { 607 return false; 608 } 609 return Objects.equals(constraints, other.constraints); 610 } 611 612 /** 613 * {@inheritDoc} 614 * 615 * @hide 616 */ 617 @NonNull 618 @Override toString()619 public String toString() { 620 return "OverlayInfo {" 621 + "packageName=" + packageName 622 + ", overlayName=" + overlayName 623 + ", targetPackage=" + targetPackageName 624 + ", targetOverlayable=" + targetOverlayableName 625 + ", state=" + state + " (" + stateToString(state) + ")," 626 + ", userId=" + userId 627 + ", constraints=" + OverlayConstraint.constraintsToString(constraints) 628 + " }"; 629 } 630 } 631