Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80bbdfd1 authored by Benjamin Franz's avatar Benjamin Franz Committed by Gerrit Code Review
Browse files

Merge "Add versioning to app compat framework"

parents b8d9e77b 360d60d5
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -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).
@@ -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();
        }
    }
}
+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);
        }
    };
}
+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;
+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];
                }
            };
}
+12 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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