Merge "Fix onPackageChanged handling of disabled packages" into tm-dev am: c65678a306
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17105465 Change-Id: I6207c3745a03ffa592f6ac01cc6219779abd0fee
This commit is contained in:
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.server.backup;
|
package com.android.server.backup;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||||
|
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.annotation.WorkerThread;
|
import android.annotation.WorkerThread;
|
||||||
@@ -28,7 +31,6 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
@@ -42,8 +44,8 @@ import com.android.internal.util.Preconditions;
|
|||||||
import com.android.server.backup.transport.BackupTransportClient;
|
import com.android.server.backup.transport.BackupTransportClient;
|
||||||
import com.android.server.backup.transport.OnTransportRegisteredListener;
|
import com.android.server.backup.transport.OnTransportRegisteredListener;
|
||||||
import com.android.server.backup.transport.TransportConnection;
|
import com.android.server.backup.transport.TransportConnection;
|
||||||
import com.android.server.backup.transport.TransportConnectionManager;
|
|
||||||
import com.android.server.backup.transport.TransportConnectionListener;
|
import com.android.server.backup.transport.TransportConnectionListener;
|
||||||
|
import com.android.server.backup.transport.TransportConnectionManager;
|
||||||
import com.android.server.backup.transport.TransportNotAvailableException;
|
import com.android.server.backup.transport.TransportNotAvailableException;
|
||||||
import com.android.server.backup.transport.TransportNotRegisteredException;
|
import com.android.server.backup.transport.TransportNotRegisteredException;
|
||||||
import com.android.server.backup.transport.TransportStats;
|
import com.android.server.backup.transport.TransportStats;
|
||||||
@@ -58,6 +60,7 @@ import java.util.function.Predicate;
|
|||||||
/** Handles in-memory bookkeeping of all BackupTransport objects. */
|
/** Handles in-memory bookkeeping of all BackupTransport objects. */
|
||||||
public class TransportManager {
|
public class TransportManager {
|
||||||
private static final String TAG = "BackupTransportManager";
|
private static final String TAG = "BackupTransportManager";
|
||||||
|
private static final boolean MORE_DEBUG = false;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
|
public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
|
||||||
@@ -130,14 +133,61 @@ public class TransportManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onPackageEnabled(String packageName) {
|
||||||
|
onPackageAdded(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPackageDisabled(String packageName) {
|
||||||
|
onPackageRemoved(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
void onPackageChanged(String packageName, String... components) {
|
void onPackageChanged(String packageName, String... components) {
|
||||||
|
// Determine if the overall package has changed and not just its
|
||||||
|
// components - see {@link EXTRA_CHANGED_COMPONENT_NAME_LIST}. When we
|
||||||
|
// know a package was enabled/disabled we'll handle that directly and
|
||||||
|
// not continue with onPackageChanged.
|
||||||
|
if (components.length == 1 && components[0].equals(packageName)) {
|
||||||
|
int enabled;
|
||||||
|
try {
|
||||||
|
enabled = mPackageManager.getApplicationEnabledSetting(packageName);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// packageName doesn't exist: likely due to a race with it being uninstalled.
|
||||||
|
if (MORE_DEBUG) {
|
||||||
|
Slog.d(TAG, "Package " + packageName + " was changed, but no longer exists.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (enabled) {
|
||||||
|
case COMPONENT_ENABLED_STATE_ENABLED: {
|
||||||
|
if (MORE_DEBUG) {
|
||||||
|
Slog.d(TAG, "Package " + packageName + " was enabled.");
|
||||||
|
}
|
||||||
|
onPackageEnabled(packageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case COMPONENT_ENABLED_STATE_DISABLED: {
|
||||||
|
if (MORE_DEBUG) {
|
||||||
|
Slog.d(TAG, "Package " + packageName + " was disabled.");
|
||||||
|
}
|
||||||
|
onPackageDisabled(packageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
Slog.w(TAG, "Package " + packageName + " enabled setting: " + enabled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Unfortunately this can't be atomic because we risk a deadlock if
|
// Unfortunately this can't be atomic because we risk a deadlock if
|
||||||
// registerTransportsFromPackage() is put inside the synchronized block
|
// registerTransportsFromPackage() is put inside the synchronized block
|
||||||
Set<ComponentName> transportComponents = new ArraySet<>(components.length);
|
Set<ComponentName> transportComponents = new ArraySet<>(components.length);
|
||||||
for (String componentName : components) {
|
for (String componentName : components) {
|
||||||
transportComponents.add(new ComponentName(packageName, componentName));
|
transportComponents.add(new ComponentName(packageName, componentName));
|
||||||
}
|
}
|
||||||
|
if (transportComponents.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
synchronized (mTransportLock) {
|
synchronized (mTransportLock) {
|
||||||
mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
|
mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.server.backup;
|
package com.android.server.backup;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
|
||||||
|
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||||
|
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
||||||
|
|
||||||
import static com.android.server.backup.testing.TransportData.genericTransport;
|
import static com.android.server.backup.testing.TransportData.genericTransport;
|
||||||
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
|
import static com.android.server.backup.testing.TransportTestUtils.mockTransport;
|
||||||
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
|
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
|
||||||
@@ -311,6 +315,86 @@ public class TransportManagerTest {
|
|||||||
.onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
|
.onTransportRegistered(mTransportA2.transportName, mTransportA2.transportDirName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPackageChanged_whenPackageChanged_packageDisabledUnregistersTransport()
|
||||||
|
throws Exception {
|
||||||
|
TransportManager transportManager =
|
||||||
|
createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
|
||||||
|
reset(mListener);
|
||||||
|
|
||||||
|
mContext.getPackageManager()
|
||||||
|
.setApplicationEnabledSetting(
|
||||||
|
PACKAGE_A,
|
||||||
|
Integer.valueOf(COMPONENT_ENABLED_STATE_DISABLED),
|
||||||
|
0 /*flags*/);
|
||||||
|
transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
|
||||||
|
|
||||||
|
assertRegisteredTransports(transportManager, singletonList(mTransportB1));
|
||||||
|
verify(mListener, never()).onTransportRegistered(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPackageChanged_whenPackageChanged_packageEnabledRegistersTransport()
|
||||||
|
throws Exception {
|
||||||
|
TransportManager transportManager =
|
||||||
|
createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
|
||||||
|
reset(mListener);
|
||||||
|
|
||||||
|
mContext.getPackageManager()
|
||||||
|
.setApplicationEnabledSetting(
|
||||||
|
PACKAGE_A,
|
||||||
|
Integer.valueOf(COMPONENT_ENABLED_STATE_DISABLED),
|
||||||
|
0 /*flags*/);
|
||||||
|
transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
|
||||||
|
|
||||||
|
assertRegisteredTransports(transportManager, singletonList(mTransportB1));
|
||||||
|
verify(mListener, never()).onTransportRegistered(any(), any());
|
||||||
|
|
||||||
|
mContext.getPackageManager()
|
||||||
|
.setApplicationEnabledSetting(
|
||||||
|
PACKAGE_A,
|
||||||
|
Integer.valueOf(COMPONENT_ENABLED_STATE_ENABLED),
|
||||||
|
0 /*flags*/);
|
||||||
|
transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
|
||||||
|
|
||||||
|
assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
|
||||||
|
verify(mListener)
|
||||||
|
.onTransportRegistered(mTransportA1.transportName, mTransportA1.transportDirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPackageChanged_whenPackageChanged_unknownComponentStateIsIgnored()
|
||||||
|
throws Exception {
|
||||||
|
TransportManager transportManager =
|
||||||
|
createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
|
||||||
|
reset(mListener);
|
||||||
|
|
||||||
|
mContext.getPackageManager()
|
||||||
|
.setApplicationEnabledSetting(
|
||||||
|
PACKAGE_A,
|
||||||
|
Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT),
|
||||||
|
0 /*flags*/);
|
||||||
|
transportManager.onPackageChanged(PACKAGE_A, PACKAGE_A);
|
||||||
|
|
||||||
|
assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
|
||||||
|
verify(mListener, never()).onTransportRegistered(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPackageChanged_whenPackageChanged_unknownPackageExceptionIsIgnored()
|
||||||
|
throws Exception {
|
||||||
|
TransportManager transportManager =
|
||||||
|
createTransportManagerWithRegisteredTransports(mTransportA1, mTransportB1);
|
||||||
|
reset(mListener);
|
||||||
|
|
||||||
|
// empty packageName triggers Robolectric ApplicationPackageManager to throw
|
||||||
|
// exception as if package does not exist.
|
||||||
|
transportManager.onPackageChanged("", "");
|
||||||
|
|
||||||
|
assertRegisteredTransports(transportManager, asList(mTransportA1, mTransportB1));
|
||||||
|
verify(mListener, never()).onTransportRegistered(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
|
public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
|
||||||
TransportManager transportManager =
|
TransportManager transportManager =
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.testing.shadows;
|
package com.android.server.testing.shadows;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
|
||||||
import static android.content.pm.PackageManager.NameNotFoundException;
|
import static android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
|
||||||
import android.app.ApplicationPackageManager;
|
import android.app.ApplicationPackageManager;
|
||||||
@@ -44,6 +45,7 @@ public class ShadowApplicationPackageManager
|
|||||||
private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
|
private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
|
||||||
private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
|
private static final Map<String, Integer> sPackageUids = new ArrayMap<>();
|
||||||
private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
|
private static final Map<Integer, Map<String, Integer>> sUserPackageUids = new ArrayMap<>();
|
||||||
|
private static final Map<String, Integer> sPackageAppEnabledStates = new ArrayMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the package {@code packageName} to be returned when invoking {@link
|
* Registers the package {@code packageName} to be returned when invoking {@link
|
||||||
@@ -53,6 +55,7 @@ public class ShadowApplicationPackageManager
|
|||||||
public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
|
public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
|
||||||
sPackageInfos.put(packageName, packageInfo);
|
sPackageInfos.put(packageName, packageInfo);
|
||||||
sInstalledPackages.add(packageInfo);
|
sInstalledPackages.add(packageInfo);
|
||||||
|
sPackageAppEnabledStates.put(packageName, Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,6 +79,22 @@ public class ShadowApplicationPackageManager
|
|||||||
sUserPackageUids.put(userId, userPackageUids);
|
sUserPackageUids.put(userId, userPackageUids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getApplicationEnabledSetting(String packageName) {
|
||||||
|
if (packageName.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Robo: Package '' does not exist.");
|
||||||
|
}
|
||||||
|
if (!sPackageAppEnabledStates.containsKey(packageName)) {
|
||||||
|
return COMPONENT_ENABLED_STATE_DEFAULT;
|
||||||
|
}
|
||||||
|
return sPackageAppEnabledStates.get(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setApplicationEnabledSetting(String packageName, int newState, int flags) {
|
||||||
|
sPackageAppEnabledStates.put(packageName, Integer.valueOf(newState)); // flags unused here.
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
|
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
|
||||||
throws NameNotFoundException {
|
throws NameNotFoundException {
|
||||||
@@ -115,6 +134,7 @@ public class ShadowApplicationPackageManager
|
|||||||
public static void reset() {
|
public static void reset() {
|
||||||
sPackageInfos.clear();
|
sPackageInfos.clear();
|
||||||
sInstalledPackages.clear();
|
sInstalledPackages.clear();
|
||||||
|
sPackageAppEnabledStates.clear();
|
||||||
org.robolectric.shadows.ShadowApplicationPackageManager.reset();
|
org.robolectric.shadows.ShadowApplicationPackageManager.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user