Loading core/java/android/app/compat/CompatChanges.java +29 −0 Original line number Diff line number Diff line Loading @@ -20,8 +20,16 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.compat.Compatibility; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import com.android.internal.compat.CompatibilityOverrideConfig; import com.android.internal.compat.IPlatformCompat; import java.util.Map; /** * CompatChanges APIs - to be used by platform code only (including mainline * modules). Loading Loading @@ -89,4 +97,25 @@ public final class CompatChanges { return QUERY_CACHE.query(ChangeIdStateQuery.byUid(changeId, uid)); } /** * Set an app compat override for a given package. This will check whether the caller is allowed * to perform this operation on the given apk and build. Only the installer package is allowed * to set overrides on a non-debuggable final build and a non-test apk. * * @param packageName The package name of the app in question. * @param overrides A map from changeId to the override applied for this change id. * @hide */ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG) public static void setPackageOverride(String packageName, Map<Long, PackageOverride> overrides) { IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides); try { platformCompat.setOverridesFromInstaller(config, packageName); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } core/java/android/app/compat/PackageOverride.java 0 → 100644 +211 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.compat; import android.annotation.IntDef; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * An app compat override applied to a given package and change id pairing. * * A package override contains a list of version ranges with the desired boolean value of * the override for the app in this version range. Ranges can be open ended in either direction. * An instance of PackageOverride gets created via {@link Builder} and is immutable once created. * * @hide */ public class PackageOverride implements Parcelable { @IntDef({ VALUE_UNDEFINED, VALUE_ENABLED, VALUE_DISABLED }) @Retention(RetentionPolicy.SOURCE) /** @hide */ public @interface EvaluatedOverride { } /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * this PackageOverride does not define the value of the override for the given version. * @hide */ public static final int VALUE_UNDEFINED = 0; /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * the override evaluates to {@code true} for the given version. * @hide */ public static final int VALUE_ENABLED = 1; /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * the override evaluates to {@code fakse} for the given version. * @hide */ public static final int VALUE_DISABLED = 2; private final long mMinVersionCode; private final long mMaxVersionCode; private final boolean mEnabled; private PackageOverride(long minVersionCode, long maxVersionCode, boolean enabled) { this.mMinVersionCode = minVersionCode; this.mMaxVersionCode = maxVersionCode; this.mEnabled = enabled; } private PackageOverride(Parcel in) { this(in.readLong(), in.readLong(), in.readBoolean()); } /** * Evaluate the override for the given {@code versionCode}. If no override is defined for * the specified version code, {@link #VALUE_UNDEFINED} is returned. * @hide */ public @EvaluatedOverride int evaluate(long versionCode) { if (versionCode >= mMinVersionCode && versionCode <= mMaxVersionCode) { return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; } return VALUE_UNDEFINED; } /** * Evaluate the override independent of version code, i.e. only return an evaluated value if * this range covers all versions, otherwise {@link #VALUE_UNDEFINED} is returned. * @hide */ public int evaluateForAllVersions() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; } return VALUE_UNDEFINED; } /** Returns the minimum version code the override applies to. */ public long getMinVersionCode() { return mMinVersionCode; } /** Returns the minimum version code the override applies from. */ public long getMaxVersionCode() { return mMaxVersionCode; } /** Returns the enabled value for the override. */ public boolean getEnabled() { return mEnabled; } /** @hide */ @Override public int describeContents() { return 0; } /** @hide */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(mMinVersionCode); dest.writeLong(mMaxVersionCode); dest.writeBoolean(mEnabled); } /** @hide */ @Override public String toString() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { return Boolean.toString(mEnabled); } return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled); } /** @hide */ public static final Creator<PackageOverride> CREATOR = new Creator<PackageOverride>() { @Override public PackageOverride createFromParcel(Parcel in) { return new PackageOverride(in); } @Override public PackageOverride[] newArray(int size) { return new PackageOverride[size]; } }; /** * Builder to construct a PackageOverride. */ public static class Builder { private long mMinVersionCode = Long.MIN_VALUE; private long mMaxVersionCode = Long.MAX_VALUE; private boolean mEnabled; /** * Sets the minimum version code the override should apply from. * * default value: {@code Long.MIN_VALUE}. */ public Builder setMinVersionCode(long minVersionCode) { mMinVersionCode = minVersionCode; return this; } /** * Sets the maximum version code the override should apply to. * * default value: {@code Long.MAX_VALUE}. */ public Builder setMaxVersionCode(long maxVersionCode) { mMaxVersionCode = maxVersionCode; return this; } /** * Sets whether the override should be enabled for the given version range. * * default value: {@code false}. */ public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; } /** * Build the {@link PackageOverride}. * * @throws IllegalArgumentException if {@code minVersionCode} is larger than * {@code maxVersionCode}. */ public PackageOverride build() { if (mMinVersionCode > mMaxVersionCode) { throw new IllegalArgumentException("minVersionCode must not be larger than " + "maxVersionCode"); } return new PackageOverride(mMinVersionCode, mMaxVersionCode, mEnabled); } }; } core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl 0 → 100644 +19 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.compat; parcelable CompatibilityOverrideConfig; core/java/com/android/internal/compat/CompatibilityOverrideConfig.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.compat; import android.app.compat.PackageOverride; import android.os.Parcel; import android.os.Parcelable; import java.util.HashMap; import java.util.Map; /** * Parcelable containing compat config overrides for a given application. * @hide */ public final class CompatibilityOverrideConfig implements Parcelable { public final Map<Long, PackageOverride> overrides; public CompatibilityOverrideConfig(Map<Long, PackageOverride> overrides) { this.overrides = overrides; } private CompatibilityOverrideConfig(Parcel in) { int keyCount = in.readInt(); overrides = new HashMap<>(); for (int i = 0; i < keyCount; i++) { long key = in.readLong(); PackageOverride override = in.readParcelable(PackageOverride.class.getClassLoader()); overrides.put(key, override); } } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(overrides.size()); for (Long key : overrides.keySet()) { dest.writeLong(key); dest.writeParcelable(overrides.get(key), 0); } } public static final Creator<CompatibilityOverrideConfig> CREATOR = new Creator<CompatibilityOverrideConfig>() { @Override public CompatibilityOverrideConfig createFromParcel(Parcel in) { return new CompatibilityOverrideConfig(in); } @Override public CompatibilityOverrideConfig[] newArray(int size) { return new CompatibilityOverrideConfig[size]; } }; } core/java/com/android/internal/compat/IPlatformCompat.aidl +12 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.internal.compat.IOverrideValidator; import java.util.Map; parcelable CompatibilityChangeConfig; parcelable CompatibilityOverrideConfig; parcelable CompatibilityChangeInfo; /** * Platform private API for talking with the PlatformCompat service. Loading Loading @@ -149,6 +150,17 @@ interface IPlatformCompat { */ void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** * Adds overrides to compatibility changes. * * <p>Kills the app to allow the changes to take effect. * * @param overrides parcelable containing the compat change overrides to be applied * @param packageName the package name of the app whose changes will be overridden * @throws SecurityException if overriding changes is not permitted */ void setOverridesFromInstaller(in CompatibilityOverrideConfig overrides, in String packageName); /** * Adds overrides to compatibility changes. * Loading Loading
core/java/android/app/compat/CompatChanges.java +29 −0 Original line number Diff line number Diff line Loading @@ -20,8 +20,16 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.compat.Compatibility; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import com.android.internal.compat.CompatibilityOverrideConfig; import com.android.internal.compat.IPlatformCompat; import java.util.Map; /** * CompatChanges APIs - to be used by platform code only (including mainline * modules). Loading Loading @@ -89,4 +97,25 @@ public final class CompatChanges { return QUERY_CACHE.query(ChangeIdStateQuery.byUid(changeId, uid)); } /** * Set an app compat override for a given package. This will check whether the caller is allowed * to perform this operation on the given apk and build. Only the installer package is allowed * to set overrides on a non-debuggable final build and a non-test apk. * * @param packageName The package name of the app in question. * @param overrides A map from changeId to the override applied for this change id. * @hide */ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG) public static void setPackageOverride(String packageName, Map<Long, PackageOverride> overrides) { IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides); try { platformCompat.setOverridesFromInstaller(config, packageName); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } }
core/java/android/app/compat/PackageOverride.java 0 → 100644 +211 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.compat; import android.annotation.IntDef; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * An app compat override applied to a given package and change id pairing. * * A package override contains a list of version ranges with the desired boolean value of * the override for the app in this version range. Ranges can be open ended in either direction. * An instance of PackageOverride gets created via {@link Builder} and is immutable once created. * * @hide */ public class PackageOverride implements Parcelable { @IntDef({ VALUE_UNDEFINED, VALUE_ENABLED, VALUE_DISABLED }) @Retention(RetentionPolicy.SOURCE) /** @hide */ public @interface EvaluatedOverride { } /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * this PackageOverride does not define the value of the override for the given version. * @hide */ public static final int VALUE_UNDEFINED = 0; /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * the override evaluates to {@code true} for the given version. * @hide */ public static final int VALUE_ENABLED = 1; /** * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that * the override evaluates to {@code fakse} for the given version. * @hide */ public static final int VALUE_DISABLED = 2; private final long mMinVersionCode; private final long mMaxVersionCode; private final boolean mEnabled; private PackageOverride(long minVersionCode, long maxVersionCode, boolean enabled) { this.mMinVersionCode = minVersionCode; this.mMaxVersionCode = maxVersionCode; this.mEnabled = enabled; } private PackageOverride(Parcel in) { this(in.readLong(), in.readLong(), in.readBoolean()); } /** * Evaluate the override for the given {@code versionCode}. If no override is defined for * the specified version code, {@link #VALUE_UNDEFINED} is returned. * @hide */ public @EvaluatedOverride int evaluate(long versionCode) { if (versionCode >= mMinVersionCode && versionCode <= mMaxVersionCode) { return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; } return VALUE_UNDEFINED; } /** * Evaluate the override independent of version code, i.e. only return an evaluated value if * this range covers all versions, otherwise {@link #VALUE_UNDEFINED} is returned. * @hide */ public int evaluateForAllVersions() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { return mEnabled ? VALUE_ENABLED : VALUE_DISABLED; } return VALUE_UNDEFINED; } /** Returns the minimum version code the override applies to. */ public long getMinVersionCode() { return mMinVersionCode; } /** Returns the minimum version code the override applies from. */ public long getMaxVersionCode() { return mMaxVersionCode; } /** Returns the enabled value for the override. */ public boolean getEnabled() { return mEnabled; } /** @hide */ @Override public int describeContents() { return 0; } /** @hide */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(mMinVersionCode); dest.writeLong(mMaxVersionCode); dest.writeBoolean(mEnabled); } /** @hide */ @Override public String toString() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { return Boolean.toString(mEnabled); } return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled); } /** @hide */ public static final Creator<PackageOverride> CREATOR = new Creator<PackageOverride>() { @Override public PackageOverride createFromParcel(Parcel in) { return new PackageOverride(in); } @Override public PackageOverride[] newArray(int size) { return new PackageOverride[size]; } }; /** * Builder to construct a PackageOverride. */ public static class Builder { private long mMinVersionCode = Long.MIN_VALUE; private long mMaxVersionCode = Long.MAX_VALUE; private boolean mEnabled; /** * Sets the minimum version code the override should apply from. * * default value: {@code Long.MIN_VALUE}. */ public Builder setMinVersionCode(long minVersionCode) { mMinVersionCode = minVersionCode; return this; } /** * Sets the maximum version code the override should apply to. * * default value: {@code Long.MAX_VALUE}. */ public Builder setMaxVersionCode(long maxVersionCode) { mMaxVersionCode = maxVersionCode; return this; } /** * Sets whether the override should be enabled for the given version range. * * default value: {@code false}. */ public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; } /** * Build the {@link PackageOverride}. * * @throws IllegalArgumentException if {@code minVersionCode} is larger than * {@code maxVersionCode}. */ public PackageOverride build() { if (mMinVersionCode > mMaxVersionCode) { throw new IllegalArgumentException("minVersionCode must not be larger than " + "maxVersionCode"); } return new PackageOverride(mMinVersionCode, mMaxVersionCode, mEnabled); } }; }
core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl 0 → 100644 +19 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.compat; parcelable CompatibilityOverrideConfig;
core/java/com/android/internal/compat/CompatibilityOverrideConfig.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.compat; import android.app.compat.PackageOverride; import android.os.Parcel; import android.os.Parcelable; import java.util.HashMap; import java.util.Map; /** * Parcelable containing compat config overrides for a given application. * @hide */ public final class CompatibilityOverrideConfig implements Parcelable { public final Map<Long, PackageOverride> overrides; public CompatibilityOverrideConfig(Map<Long, PackageOverride> overrides) { this.overrides = overrides; } private CompatibilityOverrideConfig(Parcel in) { int keyCount = in.readInt(); overrides = new HashMap<>(); for (int i = 0; i < keyCount; i++) { long key = in.readLong(); PackageOverride override = in.readParcelable(PackageOverride.class.getClassLoader()); overrides.put(key, override); } } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(overrides.size()); for (Long key : overrides.keySet()) { dest.writeLong(key); dest.writeParcelable(overrides.get(key), 0); } } public static final Creator<CompatibilityOverrideConfig> CREATOR = new Creator<CompatibilityOverrideConfig>() { @Override public CompatibilityOverrideConfig createFromParcel(Parcel in) { return new CompatibilityOverrideConfig(in); } @Override public CompatibilityOverrideConfig[] newArray(int size) { return new CompatibilityOverrideConfig[size]; } }; }
core/java/com/android/internal/compat/IPlatformCompat.aidl +12 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.internal.compat.IOverrideValidator; import java.util.Map; parcelable CompatibilityChangeConfig; parcelable CompatibilityOverrideConfig; parcelable CompatibilityChangeInfo; /** * Platform private API for talking with the PlatformCompat service. Loading Loading @@ -149,6 +150,17 @@ interface IPlatformCompat { */ void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** * Adds overrides to compatibility changes. * * <p>Kills the app to allow the changes to take effect. * * @param overrides parcelable containing the compat change overrides to be applied * @param packageName the package name of the app whose changes will be overridden * @throws SecurityException if overriding changes is not permitted */ void setOverridesFromInstaller(in CompatibilityOverrideConfig overrides, in String packageName); /** * Adds overrides to compatibility changes. * Loading