Loading services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java +139 −10 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.server.compat.overrides; import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_PACKAGE_CHANGED; import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.provider.DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES; Loading @@ -24,11 +27,16 @@ import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_ import static java.util.Collections.emptySet; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.PackageOverride; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.DeviceConfig; Loading Loading @@ -67,8 +75,9 @@ public final class AppCompatOverridesService { private final PackageManager mPackageManager; private final IPlatformCompat mPlatformCompat; private final List<String> mSupportedNamespaces; private final List<DeviceConfigListener> mDeviceConfigListeners; private final AppCompatOverridesParser mOverridesParser; private final PackageReceiver mPackageReceiver; private final List<DeviceConfigListener> mDeviceConfigListeners; private AppCompatOverridesService(Context context) { this(context, IPlatformCompat.Stub.asInterface( Loading @@ -82,31 +91,42 @@ public final class AppCompatOverridesService { mPackageManager = mContext.getPackageManager(); mPlatformCompat = platformCompat; mSupportedNamespaces = supportedNamespaces; mDeviceConfigListeners = new ArrayList<>(); mOverridesParser = new AppCompatOverridesParser(mPackageManager); mPackageReceiver = new PackageReceiver(mContext); mDeviceConfigListeners = new ArrayList<>(); for (String namespace : mSupportedNamespaces) { mDeviceConfigListeners.add(new DeviceConfigListener(mContext, namespace)); } } @Override public void finalize() { unregisterDeviceConfigListeners(); unregisterPackageReceiver(); } @VisibleForTesting void registerDeviceConfigListeners() { for (String namespace : mSupportedNamespaces) { DeviceConfigListener listener = new DeviceConfigListener(namespace); DeviceConfig.addOnPropertiesChangedListener(namespace, mContext.getMainExecutor(), listener); mDeviceConfigListeners.add(listener); for (DeviceConfigListener listener : mDeviceConfigListeners) { listener.register(); } } private void unregisterDeviceConfigListeners() { for (DeviceConfigListener listener : mDeviceConfigListeners) { DeviceConfig.removeOnPropertiesChangedListener(listener); listener.unregister(); } } @VisibleForTesting void registerPackageReceiver() { mPackageReceiver.register(); } private void unregisterPackageReceiver() { mPackageReceiver.unregister(); } /** * Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code * namespace} are fetched via {@link DeviceConfig#getProperties}. Loading Loading @@ -139,6 +159,25 @@ public final class AppCompatOverridesService { } } /** * Applies all overrides in all supported namespaces for the given {@code packageName}. */ private void applyAllPackageOverrides(String packageName) { Long versionCode = getVersionCodeOrNull(packageName); if (versionCode == null) { return; } for (String namespace : mSupportedNamespaces) { // We apply overrides for each namespace separately so that if there is a failure for // one namespace, the other namespaces won't be affected. applyPackageOverrides( DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""), packageName, versionCode, getOverridesToRemove(namespace).getOrDefault(packageName, emptySet())); } } /** * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the * resulting {@link PackageOverrides#overridesToAdd} via {@link Loading @@ -154,6 +193,24 @@ public final class AppCompatOverridesService { removePackageOverrides(packageName, packageOverrides.overridesToRemove); } /** * Removes all owned overrides in all supported namespaces for the given {@code packageName}. * * <p>If a certain namespace doesn't have a package override flag for the given {@code * packageName}, that namespace is skipped.</p> */ private void removeAllPackageOverrides(String packageName) { for (String namespace : mSupportedNamespaces) { if (DeviceConfig.getString(namespace, packageName, /* defaultValue= */ "").isEmpty()) { // No overrides for this package in this namespace. continue; } // We remove overrides for each namespace separately so that if there is a failure for // one namespace, the other namespaces won't be affected. removePackageOverrides(packageName, getOwnedChangeIds(namespace)); } } /** * Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and * respective change IDs in {@code overridesToRemove}. Loading Loading @@ -211,6 +268,10 @@ public final class AppCompatOverridesService { } } private boolean isInstalledForAnyUser(String packageName) { return getVersionCodeOrNull(packageName) != null; } @Nullable private Long getVersionCodeOrNull(String packageName) { try { Loading @@ -218,7 +279,7 @@ public final class AppCompatOverridesService { MATCH_ANY_USER); return applicationInfo.longVersionCode; } catch (PackageManager.NameNotFoundException e) { // Package isn't installed yet. // Package isn't installed for any user. return null; } } Loading @@ -239,6 +300,7 @@ public final class AppCompatOverridesService { public void onStart() { mService = new AppCompatOverridesService(getContext()); mService.registerDeviceConfigListeners(); mService.registerPackageReceiver(); } } Loading @@ -247,12 +309,23 @@ public final class AppCompatOverridesService { * namespace and adds/removes overrides according to the changed flags. */ private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { private final Context mContext; private final String mNamespace; private DeviceConfigListener(String namespace) { private DeviceConfigListener(Context context, String namespace) { mContext = context; mNamespace = namespace; } private void register() { DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(), this); } private void unregister() { DeviceConfig.removeOnPropertiesChangedListener(this); } @Override public void onPropertiesChanged(Properties properties) { boolean removeOverridesFlagChanged = properties.getKeyset().contains( Loading @@ -276,4 +349,60 @@ public final class AppCompatOverridesService { } } } /** * A {@link BroadcastReceiver} that listens on package added/changed/removed events and * adds/removes overrides according to the corresponding Device Config flags. */ private final class PackageReceiver extends BroadcastReceiver { private final Context mContext; private final IntentFilter mIntentFilter; private PackageReceiver(Context context) { mContext = context; mIntentFilter = new IntentFilter(); mIntentFilter.addAction(ACTION_PACKAGE_ADDED); mIntentFilter.addAction(ACTION_PACKAGE_CHANGED); mIntentFilter.addAction(ACTION_PACKAGE_REMOVED); mIntentFilter.addDataScheme("package"); } private void register() { mContext.registerReceiverForAllUsers(this, mIntentFilter, /* broadcastPermission= */ null, /* scheduler= */ null); } private void unregister() { mContext.unregisterReceiver(this); } @Override public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { Uri data = intent.getData(); if (data == null) { Slog.w(TAG, "Failed to get package name in package receiver"); return; } String packageName = data.getSchemeSpecificPart(); String action = intent.getAction(); if (action == null) { Slog.w(TAG, "Failed to get action in package receiver"); return; } switch (action) { case ACTION_PACKAGE_ADDED: case ACTION_PACKAGE_CHANGED: applyAllPackageOverrides(packageName); break; case ACTION_PACKAGE_REMOVED: if (!isInstalledForAnyUser(packageName)) { removeAllPackageOverrides(packageName); } break; default: Slog.w(TAG, "Unsupported action in package receiver: " + action); break; } } }; } services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java +309 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java +139 −10 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package com.android.server.compat.overrides; import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_PACKAGE_CHANGED; import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.provider.DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES; Loading @@ -24,11 +27,16 @@ import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_ import static java.util.Collections.emptySet; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.PackageOverride; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.DeviceConfig; Loading Loading @@ -67,8 +75,9 @@ public final class AppCompatOverridesService { private final PackageManager mPackageManager; private final IPlatformCompat mPlatformCompat; private final List<String> mSupportedNamespaces; private final List<DeviceConfigListener> mDeviceConfigListeners; private final AppCompatOverridesParser mOverridesParser; private final PackageReceiver mPackageReceiver; private final List<DeviceConfigListener> mDeviceConfigListeners; private AppCompatOverridesService(Context context) { this(context, IPlatformCompat.Stub.asInterface( Loading @@ -82,31 +91,42 @@ public final class AppCompatOverridesService { mPackageManager = mContext.getPackageManager(); mPlatformCompat = platformCompat; mSupportedNamespaces = supportedNamespaces; mDeviceConfigListeners = new ArrayList<>(); mOverridesParser = new AppCompatOverridesParser(mPackageManager); mPackageReceiver = new PackageReceiver(mContext); mDeviceConfigListeners = new ArrayList<>(); for (String namespace : mSupportedNamespaces) { mDeviceConfigListeners.add(new DeviceConfigListener(mContext, namespace)); } } @Override public void finalize() { unregisterDeviceConfigListeners(); unregisterPackageReceiver(); } @VisibleForTesting void registerDeviceConfigListeners() { for (String namespace : mSupportedNamespaces) { DeviceConfigListener listener = new DeviceConfigListener(namespace); DeviceConfig.addOnPropertiesChangedListener(namespace, mContext.getMainExecutor(), listener); mDeviceConfigListeners.add(listener); for (DeviceConfigListener listener : mDeviceConfigListeners) { listener.register(); } } private void unregisterDeviceConfigListeners() { for (DeviceConfigListener listener : mDeviceConfigListeners) { DeviceConfig.removeOnPropertiesChangedListener(listener); listener.unregister(); } } @VisibleForTesting void registerPackageReceiver() { mPackageReceiver.register(); } private void unregisterPackageReceiver() { mPackageReceiver.unregister(); } /** * Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code * namespace} are fetched via {@link DeviceConfig#getProperties}. Loading Loading @@ -139,6 +159,25 @@ public final class AppCompatOverridesService { } } /** * Applies all overrides in all supported namespaces for the given {@code packageName}. */ private void applyAllPackageOverrides(String packageName) { Long versionCode = getVersionCodeOrNull(packageName); if (versionCode == null) { return; } for (String namespace : mSupportedNamespaces) { // We apply overrides for each namespace separately so that if there is a failure for // one namespace, the other namespaces won't be affected. applyPackageOverrides( DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""), packageName, versionCode, getOverridesToRemove(namespace).getOrDefault(packageName, emptySet())); } } /** * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the * resulting {@link PackageOverrides#overridesToAdd} via {@link Loading @@ -154,6 +193,24 @@ public final class AppCompatOverridesService { removePackageOverrides(packageName, packageOverrides.overridesToRemove); } /** * Removes all owned overrides in all supported namespaces for the given {@code packageName}. * * <p>If a certain namespace doesn't have a package override flag for the given {@code * packageName}, that namespace is skipped.</p> */ private void removeAllPackageOverrides(String packageName) { for (String namespace : mSupportedNamespaces) { if (DeviceConfig.getString(namespace, packageName, /* defaultValue= */ "").isEmpty()) { // No overrides for this package in this namespace. continue; } // We remove overrides for each namespace separately so that if there is a failure for // one namespace, the other namespaces won't be affected. removePackageOverrides(packageName, getOwnedChangeIds(namespace)); } } /** * Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and * respective change IDs in {@code overridesToRemove}. Loading Loading @@ -211,6 +268,10 @@ public final class AppCompatOverridesService { } } private boolean isInstalledForAnyUser(String packageName) { return getVersionCodeOrNull(packageName) != null; } @Nullable private Long getVersionCodeOrNull(String packageName) { try { Loading @@ -218,7 +279,7 @@ public final class AppCompatOverridesService { MATCH_ANY_USER); return applicationInfo.longVersionCode; } catch (PackageManager.NameNotFoundException e) { // Package isn't installed yet. // Package isn't installed for any user. return null; } } Loading @@ -239,6 +300,7 @@ public final class AppCompatOverridesService { public void onStart() { mService = new AppCompatOverridesService(getContext()); mService.registerDeviceConfigListeners(); mService.registerPackageReceiver(); } } Loading @@ -247,12 +309,23 @@ public final class AppCompatOverridesService { * namespace and adds/removes overrides according to the changed flags. */ private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { private final Context mContext; private final String mNamespace; private DeviceConfigListener(String namespace) { private DeviceConfigListener(Context context, String namespace) { mContext = context; mNamespace = namespace; } private void register() { DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(), this); } private void unregister() { DeviceConfig.removeOnPropertiesChangedListener(this); } @Override public void onPropertiesChanged(Properties properties) { boolean removeOverridesFlagChanged = properties.getKeyset().contains( Loading @@ -276,4 +349,60 @@ public final class AppCompatOverridesService { } } } /** * A {@link BroadcastReceiver} that listens on package added/changed/removed events and * adds/removes overrides according to the corresponding Device Config flags. */ private final class PackageReceiver extends BroadcastReceiver { private final Context mContext; private final IntentFilter mIntentFilter; private PackageReceiver(Context context) { mContext = context; mIntentFilter = new IntentFilter(); mIntentFilter.addAction(ACTION_PACKAGE_ADDED); mIntentFilter.addAction(ACTION_PACKAGE_CHANGED); mIntentFilter.addAction(ACTION_PACKAGE_REMOVED); mIntentFilter.addDataScheme("package"); } private void register() { mContext.registerReceiverForAllUsers(this, mIntentFilter, /* broadcastPermission= */ null, /* scheduler= */ null); } private void unregister() { mContext.unregisterReceiver(this); } @Override public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { Uri data = intent.getData(); if (data == null) { Slog.w(TAG, "Failed to get package name in package receiver"); return; } String packageName = data.getSchemeSpecificPart(); String action = intent.getAction(); if (action == null) { Slog.w(TAG, "Failed to get action in package receiver"); return; } switch (action) { case ACTION_PACKAGE_ADDED: case ACTION_PACKAGE_CHANGED: applyAllPackageOverrides(packageName); break; case ACTION_PACKAGE_REMOVED: if (!isInstalledForAnyUser(packageName)) { removeAllPackageOverrides(packageName); } break; default: Slog.w(TAG, "Unsupported action in package receiver: " + action); break; } } }; }
services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java +309 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes