Merge "Apply/remove overrides for a package when it's added/changed/removed." into sc-v2-dev

This commit is contained in:
Tom Natan
2021-07-13 09:59:10 +00:00
committed by Android (Google) Code Review
2 changed files with 448 additions and 11 deletions

View File

@@ -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;
@@ -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;
@@ -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(
@@ -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}.
@@ -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
@@ -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}.
@@ -211,6 +268,10 @@ public final class AppCompatOverridesService {
}
}
private boolean isInstalledForAnyUser(String packageName) {
return getVersionCodeOrNull(packageName) != null;
}
@Nullable
private Long getVersionCodeOrNull(String packageName) {
try {
@@ -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;
}
}
@@ -239,6 +300,7 @@ public final class AppCompatOverridesService {
public void onStart() {
mService = new AppCompatOverridesService(getContext());
mService.registerDeviceConfigListeners();
mService.registerPackageReceiver();
}
}
@@ -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(
@@ -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;
}
}
};
}

View File

@@ -16,6 +16,11 @@
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.Intent.ACTION_USER_SWITCHED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_OWNED_CHANGE_IDS;
import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES;
@@ -24,17 +29,25 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.compat.PackageOverride;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
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.Handler;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
@@ -73,7 +86,10 @@ import java.util.concurrent.Executor;
@Presubmit
public class AppCompatOverridesServiceTest {
private static final String NAMESPACE_1 = "namespace_1";
private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(NAMESPACE_1);
private static final String NAMESPACE_2 = "namespace_2";
private static final String NAMESPACE_3 = "namespace_3";
private static final List<String> SUPPORTED_NAMESPACES = Arrays.asList(NAMESPACE_1,
NAMESPACE_2, NAMESPACE_3);
private static final String PACKAGE_1 = "com.android.test1";
private static final String PACKAGE_2 = "com.android.test2";
@@ -82,6 +98,7 @@ public class AppCompatOverridesServiceTest {
private static final String PACKAGE_5 = "com.android.test5";
private MockContext mMockContext;
private BroadcastReceiver mPackageReceiver;
private AppCompatOverridesService mService;
@Mock
@@ -112,6 +129,15 @@ public class AppCompatOverridesServiceTest {
// Run on current thread
return Runnable::run;
}
@Override
@Nullable
public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
@NonNull IntentFilter filter, @Nullable String broadcastPermission,
@Nullable Handler scheduler) {
mPackageReceiver = receiver;
return null;
}
}
@Before
@@ -120,6 +146,8 @@ public class AppCompatOverridesServiceTest {
InstrumentationRegistry.getInstrumentation().getTargetContext());
mService = new AppCompatOverridesService(mMockContext, mPlatformCompat,
SUPPORTED_NAMESPACES);
mService.registerPackageReceiver();
assertThat(mPackageReceiver).isNotNull();
}
@Test
@@ -361,6 +389,282 @@ public class AppCompatOverridesServiceTest {
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
}
@Test
public void packageReceiver_packageAddedIntentDataIsNull_doesNothing() throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::true").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext, new Intent(ACTION_PACKAGE_ADDED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_actionIsNull_doesNothing() throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::true").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, /* action= */ null));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_unsupportedAction_doesNothing() throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::true").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_USER_SWITCHED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_packageAddedIntentPackageNotInstalled_doesNothing()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::true").build());
mockGetApplicationInfoNotInstalled(PACKAGE_1);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_packageAddedIntentNoOverridesForPackage_doesNothing()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_2, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_3, "201:::true").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_packageAddedIntent_appliesOverridesFromAllNamespaces()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true,103:::")
.setString(PACKAGE_2, "102:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_3, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(PACKAGE_1, "301:::true,302:::false")
.setString(PACKAGE_2, "302:::false").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
verify(mPlatformCompat, times(2)).putOverridesOnReleaseBuilds(
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
assertThat(configs.get(1).overrides.keySet()).containsExactly(301L, 302L);
assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
}
@Test
public void packageReceiver_packageChangedIntent_appliesOverrides()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true,103:::").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_CHANGED));
verify(mPlatformCompat).putOverridesOnReleaseBuilds(
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(101L);
assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(103L);
}
@Test
public void packageReceiver_packageAddedIntentRemoveOverridesSetForSomeNamespaces_skipsIds()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=103," + PACKAGE_2 + "=101")
.setString(PACKAGE_1, "101:::true,103:::")
.setString(PACKAGE_2, "102:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_1 + "=301," + PACKAGE_3 + "=302")
.setString(PACKAGE_1, "301:::true,302:::false,303:::")
.setString(PACKAGE_3, "302:::false").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
mOverridesToAddConfigCaptor.capture(), eq(PACKAGE_1));
verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
List<CompatibilityOverrideConfig> configs = mOverridesToAddConfigCaptor.getAllValues();
assertThat(configs.get(0).overrides.keySet()).containsExactly(101L);
assertThat(configs.get(1).overrides.keySet()).containsExactly(201L);
assertThat(configs.get(2).overrides.keySet()).containsExactly(302L);
assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(303L);
}
@Test
public void packageReceiver_packageRemovedIntentNoOverridesForPackage_doesNothing()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_OWNED_CHANGE_IDS, "101,102")
.setString(PACKAGE_2, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(FLAG_OWNED_CHANGE_IDS, "201,202")
.setString(PACKAGE_3, "201:::true").build());
mockGetApplicationInfoNotInstalled(PACKAGE_1);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_packageRemovedIntentPackageInstalledForAnotherUser_doesNothing()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
.setString(PACKAGE_1, "101:::true,103:::").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(FLAG_OWNED_CHANGE_IDS, "201,202")
.setString(PACKAGE_1, "202:::false").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
@Test
public void packageReceiver_packageRemovedIntent_removesOwnedOverridesForNamespacesWithPackage()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_OWNED_CHANGE_IDS, "101,102,103")
.setString(PACKAGE_1, "101:::true,103:::")
.setString(PACKAGE_2, "102:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(FLAG_OWNED_CHANGE_IDS, "201")
.setString(PACKAGE_3, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(FLAG_OWNED_CHANGE_IDS, "301,302")
.setString(PACKAGE_1, "302:::")
.setString(PACKAGE_2, "301:::true").build());
mockGetApplicationInfoNotInstalled(PACKAGE_1);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
List<CompatibilityOverridesToRemoveConfig> configs =
mOverridesToRemoveConfigCaptor.getAllValues();
assertThat(configs.get(0).changeIds).containsExactly(101L, 102L, 103L);
assertThat(configs.get(1).changeIds).containsExactly(301L, 302L);
}
@Test
public void packageReceiver_packageRemovedIntentNoOwnedIdsForSomeNamespace_skipsNamespace()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(FLAG_OWNED_CHANGE_IDS, "101,102")
.setString(PACKAGE_1, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(FLAG_OWNED_CHANGE_IDS, "301")
.setString(PACKAGE_1, "301:::true").build());
mockGetApplicationInfoNotInstalled(PACKAGE_1);
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_REMOVED));
verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
List<CompatibilityOverridesToRemoveConfig> configs =
mOverridesToRemoveConfigCaptor.getAllValues();
assertThat(configs.get(0).changeIds).containsExactly(101L, 102L);
assertThat(configs.get(1).changeIds).containsExactly(301L);
}
@Test
public void packageReceiver_platformCompatThrowsExceptionForSomeNamespace_skipsFailedCall()
throws Exception {
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "101:::true").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_2)
.setString(PACKAGE_1, "201:::false").build());
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_3)
.setString(PACKAGE_1, "301:::true").build());
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds(
argThat(config -> config.overrides.containsKey(201L)), eq(PACKAGE_1));
mPackageReceiver.onReceive(mMockContext,
createPackageIntent(PACKAGE_1, ACTION_PACKAGE_ADDED));
verify(mPlatformCompat, times(3)).putOverridesOnReleaseBuilds(
any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
}
private void mockGetApplicationInfo(String packageName, long versionCode)
throws Exception {
when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())).thenReturn(
@@ -377,4 +681,8 @@ public class AppCompatOverridesServiceTest {
appInfo.longVersionCode = versionCode;
return appInfo;
}
private Intent createPackageIntent(String packageName, @Nullable String action) {
return new Intent(action, Uri.parse("package:" + packageName));
}
}