• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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