summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/backup/backuplib/java/com/android/server/backup/TransportManager.java54
-rw-r--r--services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java84
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java20
3 files changed, 156 insertions, 2 deletions
diff --git a/services/backup/backuplib/java/com/android/server/backup/TransportManager.java b/services/backup/backuplib/java/com/android/server/backup/TransportManager.java
index 21a22f44f3dd..930f49e4d117 100644
--- a/services/backup/backuplib/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/backuplib/java/com/android/server/backup/TransportManager.java
@@ -16,6 +16,9 @@
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.UserIdInt;
import android.annotation.WorkerThread;
@@ -28,7 +31,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
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.OnTransportRegisteredListener;
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.TransportConnectionManager;
import com.android.server.backup.transport.TransportNotAvailableException;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.backup.transport.TransportStats;
@@ -58,6 +60,7 @@ import java.util.function.Predicate;
/** Handles in-memory bookkeeping of all BackupTransport objects. */
public class TransportManager {
private static final String TAG = "BackupTransportManager";
+ private static final boolean MORE_DEBUG = false;
@VisibleForTesting
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
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
// registerTransportsFromPackage() is put inside the synchronized block
Set<ComponentName> transportComponents = new ArraySet<>(components.length);
for (String componentName : components) {
transportComponents.add(new ComponentName(packageName, componentName));
}
+ if (transportComponents.isEmpty()) {
+ return;
+ }
synchronized (mTransportLock) {
mRegisteredTransportsDescriptionMap.keySet().removeIf(transportComponents::contains);
}
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index b7f8c00896d4..8a9845b1c2d2 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -16,6 +16,10 @@
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.TransportTestUtils.mockTransport;
import static com.android.server.backup.testing.TransportTestUtils.setUpTransportsForTransportManager;
@@ -312,6 +316,86 @@ public class TransportManagerTest {
}
@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
public void testRegisterAndSelectTransport_whenTransportRegistered() throws Exception {
TransportManager transportManager =
createTransportManagerWithRegisteredTransports(null, mTransportA1);
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
index aea36e555ad7..4a9948668bc4 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -16,6 +16,7 @@
package com.android.server.testing.shadows;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.NameNotFoundException;
import android.app.ApplicationPackageManager;
@@ -44,6 +45,7 @@ public class ShadowApplicationPackageManager
private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
private static final Map<String, Integer> sPackageUids = 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
@@ -53,6 +55,7 @@ public class ShadowApplicationPackageManager
public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
sPackageInfos.put(packageName, packageInfo);
sInstalledPackages.add(packageInfo);
+ sPackageAppEnabledStates.put(packageName, Integer.valueOf(COMPONENT_ENABLED_STATE_DEFAULT));
}
/**
@@ -77,6 +80,22 @@ public class ShadowApplicationPackageManager
}
@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
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
if (!sPackageInfos.containsKey(packageName)) {
@@ -115,6 +134,7 @@ public class ShadowApplicationPackageManager
public static void reset() {
sPackageInfos.clear();
sInstalledPackages.clear();
+ sPackageAppEnabledStates.clear();
org.robolectric.shadows.ShadowApplicationPackageManager.reset();
}
}