diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.aidl b/core/java/com/android/internal/compat/CompatibilityChangeConfig.aidl new file mode 100644 index 0000000000000..434c1b819582e --- /dev/null +++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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 CompatibilityChangeConfig; diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java new file mode 100644 index 0000000000000..fd2ada08edc10 --- /dev/null +++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 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.compat.Compatibility.ChangeConfig; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashSet; +import java.util.Set; + +/** + * Parcelable containing compat config overrides for a given application. + * @hide + */ +public final class CompatibilityChangeConfig implements Parcelable { + private final ChangeConfig mChangeConfig; + + public CompatibilityChangeConfig(ChangeConfig changeConfig) { + mChangeConfig = changeConfig; + } + + /** + * Changes forced to be enabled. + */ + public Set enabledChanges() { + return mChangeConfig.forceEnabledSet(); + } + + /** + * Changes forced to be disabled. + */ + public Set disabledChanges() { + return mChangeConfig.forceDisabledSet(); + } + + private CompatibilityChangeConfig(Parcel in) { + long[] enabledArray = in.createLongArray(); + long[] disabledArray = in.createLongArray(); + Set enabled = toLongSet(enabledArray); + Set disabled = toLongSet(disabledArray); + mChangeConfig = new ChangeConfig(enabled, disabled); + } + + private static Set toLongSet(long[] values) { + Set ret = new HashSet<>(); + for (long value: values) { + ret.add(value); + } + return ret; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + long[] enabled = mChangeConfig.forceEnabledChangesArray(); + long[] disabled = mChangeConfig.forceDisabledChangesArray(); + + dest.writeLongArray(enabled); + dest.writeLongArray(disabled); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + + @Override + public CompatibilityChangeConfig createFromParcel(Parcel in) { + return new CompatibilityChangeConfig(in); + } + + @Override + public CompatibilityChangeConfig[] newArray(int size) { + return new CompatibilityChangeConfig[size]; + } + }; +} diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 4d8378a345999..4099cfa51b333 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -18,6 +18,8 @@ package com.android.internal.compat; import android.content.pm.ApplicationInfo; +parcelable CompatibilityChangeConfig; + /** * Platform private API for talking with the PlatformCompat service. * @@ -125,4 +127,21 @@ interface IPlatformCompat * @return {@code true} if the change is enabled for the current app. */ boolean isChangeEnabledByUid(long changeId, int uid); -} \ No newline at end of file + + /** + * Add overrides to compatibility changes. + * + * @param overrides Parcelable containing the compat change overrides to be applied. + * @param packageName The package name of the app whose changes will be overridden. + * + */ + void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); + + /** + * Revert overrides to compatibility changes. + * + * @param packageName The package name of the app whose overrides will be cleared. + * + */ + void clearOverrides(in String packageName); +} diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 027e2fb5ccaa8..0fabd9aef3737 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -25,6 +25,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.CompatibilityChangeConfig; import com.android.server.compat.config.Change; import com.android.server.compat.config.XmlParser; @@ -186,6 +187,43 @@ public final class CompatConfig { } return overrideExists; } + /** + * Overrides the enabled state for a given change and app. This method is intended to be used + * *only* for debugging purposes. + * + *

Note, package overrides are not persistent and will be lost on system or runtime restart. + * + * @param overrides list of overrides to default changes config. + * @param packageName app for which the overrides will be applied. + */ + public void addOverrides( + CompatibilityChangeConfig overrides, String packageName) { + synchronized (mChanges) { + for (Long changeId: overrides.enabledChanges()) { + addOverride(changeId, packageName, true); + } + for (Long changeId: overrides.disabledChanges()) { + addOverride(changeId, packageName, false); + } + } + } + + /** + * Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or + * {@link #addAppOverrides(CompatibilityChangeConfig, String)} for a certain package. + * + *

This restores the default behaviour for the given change and app, once any app + * processes have been restarted. + * + * @param packageName The package for which the overrides should be purged. + */ + public void removePackageOverrides(String packageName) { + synchronized (mChanges) { + for (int i = 0; i < mChanges.size(); ++i) { + mChanges.valueAt(i).removePackageOverride(packageName); + } + } + } /** * Dumps the current list of compatibility config information. diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index a7378880a91da..8a7dcc12baaef 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -23,6 +23,7 @@ import android.util.Slog; import android.util.StatsLog; import com.android.internal.compat.ChangeReporter; +import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.IPlatformCompat; import com.android.internal.util.DumpUtils; @@ -99,6 +100,17 @@ public class PlatformCompat extends IPlatformCompat.Stub { return enabled; } + @Override + public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { + CompatConfig.get().addOverrides(overrides, packageName); + } + + @Override + public void clearOverrides(String packageName) { + CompatConfig config = CompatConfig.get(); + config.removePackageOverrides(packageName); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;