Merge "Apply/remove overrides for a package when it's added/changed/removed." into sc-v2-dev
This commit is contained in:
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.server.compat.overrides;
|
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.content.pm.PackageManager.MATCH_ANY_USER;
|
||||||
import static android.provider.DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES;
|
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 static java.util.Collections.emptySet;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.compat.PackageOverride;
|
import android.app.compat.PackageOverride;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
@@ -67,8 +75,9 @@ public final class AppCompatOverridesService {
|
|||||||
private final PackageManager mPackageManager;
|
private final PackageManager mPackageManager;
|
||||||
private final IPlatformCompat mPlatformCompat;
|
private final IPlatformCompat mPlatformCompat;
|
||||||
private final List<String> mSupportedNamespaces;
|
private final List<String> mSupportedNamespaces;
|
||||||
private final List<DeviceConfigListener> mDeviceConfigListeners;
|
|
||||||
private final AppCompatOverridesParser mOverridesParser;
|
private final AppCompatOverridesParser mOverridesParser;
|
||||||
|
private final PackageReceiver mPackageReceiver;
|
||||||
|
private final List<DeviceConfigListener> mDeviceConfigListeners;
|
||||||
|
|
||||||
private AppCompatOverridesService(Context context) {
|
private AppCompatOverridesService(Context context) {
|
||||||
this(context, IPlatformCompat.Stub.asInterface(
|
this(context, IPlatformCompat.Stub.asInterface(
|
||||||
@@ -82,31 +91,42 @@ public final class AppCompatOverridesService {
|
|||||||
mPackageManager = mContext.getPackageManager();
|
mPackageManager = mContext.getPackageManager();
|
||||||
mPlatformCompat = platformCompat;
|
mPlatformCompat = platformCompat;
|
||||||
mSupportedNamespaces = supportedNamespaces;
|
mSupportedNamespaces = supportedNamespaces;
|
||||||
mDeviceConfigListeners = new ArrayList<>();
|
|
||||||
mOverridesParser = new AppCompatOverridesParser(mPackageManager);
|
mOverridesParser = new AppCompatOverridesParser(mPackageManager);
|
||||||
|
mPackageReceiver = new PackageReceiver(mContext);
|
||||||
|
mDeviceConfigListeners = new ArrayList<>();
|
||||||
|
for (String namespace : mSupportedNamespaces) {
|
||||||
|
mDeviceConfigListeners.add(new DeviceConfigListener(mContext, namespace));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finalize() {
|
public void finalize() {
|
||||||
unregisterDeviceConfigListeners();
|
unregisterDeviceConfigListeners();
|
||||||
|
unregisterPackageReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void registerDeviceConfigListeners() {
|
void registerDeviceConfigListeners() {
|
||||||
for (String namespace : mSupportedNamespaces) {
|
for (DeviceConfigListener listener : mDeviceConfigListeners) {
|
||||||
DeviceConfigListener listener = new DeviceConfigListener(namespace);
|
listener.register();
|
||||||
DeviceConfig.addOnPropertiesChangedListener(namespace, mContext.getMainExecutor(),
|
|
||||||
listener);
|
|
||||||
mDeviceConfigListeners.add(listener);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unregisterDeviceConfigListeners() {
|
private void unregisterDeviceConfigListeners() {
|
||||||
for (DeviceConfigListener listener : mDeviceConfigListeners) {
|
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
|
* Same as {@link #applyOverrides(Properties, Map)} except all properties of the given {@code
|
||||||
* namespace} are fetched via {@link DeviceConfig#getProperties}.
|
* 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
|
* Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments, adds the
|
||||||
* resulting {@link PackageOverrides#overridesToAdd} via {@link
|
* resulting {@link PackageOverrides#overridesToAdd} via {@link
|
||||||
@@ -154,6 +193,24 @@ public final class AppCompatOverridesService {
|
|||||||
removePackageOverrides(packageName, packageOverrides.overridesToRemove);
|
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
|
* Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and
|
||||||
* respective change IDs in {@code overridesToRemove}.
|
* respective change IDs in {@code overridesToRemove}.
|
||||||
@@ -211,6 +268,10 @@ public final class AppCompatOverridesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isInstalledForAnyUser(String packageName) {
|
||||||
|
return getVersionCodeOrNull(packageName) != null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Long getVersionCodeOrNull(String packageName) {
|
private Long getVersionCodeOrNull(String packageName) {
|
||||||
try {
|
try {
|
||||||
@@ -218,7 +279,7 @@ public final class AppCompatOverridesService {
|
|||||||
MATCH_ANY_USER);
|
MATCH_ANY_USER);
|
||||||
return applicationInfo.longVersionCode;
|
return applicationInfo.longVersionCode;
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
// Package isn't installed yet.
|
// Package isn't installed for any user.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,6 +300,7 @@ public final class AppCompatOverridesService {
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
mService = new AppCompatOverridesService(getContext());
|
mService = new AppCompatOverridesService(getContext());
|
||||||
mService.registerDeviceConfigListeners();
|
mService.registerDeviceConfigListeners();
|
||||||
|
mService.registerPackageReceiver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,12 +309,23 @@ public final class AppCompatOverridesService {
|
|||||||
* namespace and adds/removes overrides according to the changed flags.
|
* namespace and adds/removes overrides according to the changed flags.
|
||||||
*/
|
*/
|
||||||
private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
|
private final class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
|
||||||
|
private final Context mContext;
|
||||||
private final String mNamespace;
|
private final String mNamespace;
|
||||||
|
|
||||||
private DeviceConfigListener(String namespace) {
|
private DeviceConfigListener(Context context, String namespace) {
|
||||||
|
mContext = context;
|
||||||
mNamespace = namespace;
|
mNamespace = namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void register() {
|
||||||
|
DeviceConfig.addOnPropertiesChangedListener(mNamespace, mContext.getMainExecutor(),
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregister() {
|
||||||
|
DeviceConfig.removeOnPropertiesChangedListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPropertiesChanged(Properties properties) {
|
public void onPropertiesChanged(Properties properties) {
|
||||||
boolean removeOverridesFlagChanged = properties.getKeyset().contains(
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
package com.android.server.compat.overrides;
|
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.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_OWNED_CHANGE_IDS;
|
||||||
import static com.android.server.compat.overrides.AppCompatOverridesParser.FLAG_REMOVE_OVERRIDES;
|
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.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.compat.PackageOverride;
|
import android.app.compat.PackageOverride;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
@@ -73,7 +86,10 @@ import java.util.concurrent.Executor;
|
|||||||
@Presubmit
|
@Presubmit
|
||||||
public class AppCompatOverridesServiceTest {
|
public class AppCompatOverridesServiceTest {
|
||||||
private static final String NAMESPACE_1 = "namespace_1";
|
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_1 = "com.android.test1";
|
||||||
private static final String PACKAGE_2 = "com.android.test2";
|
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 static final String PACKAGE_5 = "com.android.test5";
|
||||||
|
|
||||||
private MockContext mMockContext;
|
private MockContext mMockContext;
|
||||||
|
private BroadcastReceiver mPackageReceiver;
|
||||||
private AppCompatOverridesService mService;
|
private AppCompatOverridesService mService;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@@ -112,6 +129,15 @@ public class AppCompatOverridesServiceTest {
|
|||||||
// Run on current thread
|
// Run on current thread
|
||||||
return Runnable::run;
|
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
|
@Before
|
||||||
@@ -120,6 +146,8 @@ public class AppCompatOverridesServiceTest {
|
|||||||
InstrumentationRegistry.getInstrumentation().getTargetContext());
|
InstrumentationRegistry.getInstrumentation().getTargetContext());
|
||||||
mService = new AppCompatOverridesService(mMockContext, mPlatformCompat,
|
mService = new AppCompatOverridesService(mMockContext, mPlatformCompat,
|
||||||
SUPPORTED_NAMESPACES);
|
SUPPORTED_NAMESPACES);
|
||||||
|
mService.registerPackageReceiver();
|
||||||
|
assertThat(mPackageReceiver).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -361,6 +389,282 @@ public class AppCompatOverridesServiceTest {
|
|||||||
any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
|
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)
|
private void mockGetApplicationInfo(String packageName, long versionCode)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())).thenReturn(
|
when(mPackageManager.getApplicationInfo(eq(packageName), anyInt())).thenReturn(
|
||||||
@@ -377,4 +681,8 @@ public class AppCompatOverridesServiceTest {
|
|||||||
appInfo.longVersionCode = versionCode;
|
appInfo.longVersionCode = versionCode;
|
||||||
return appInfo;
|
return appInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Intent createPackageIntent(String packageName, @Nullable String action) {
|
||||||
|
return new Intent(action, Uri.parse("package:" + packageName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user