Update eligibility rules for adb backup
1. Adb backup is enabled by default for "android" package that corresponds to SystemBackupAgent (no change from current behavior)
2. System and privileged apps can use android.backup.ALLOW_ADB_BACKUP manifest property to enable / disable adb backup. Disabled by default.
3. Other apps can only use adb backup when running in debuggable mode.
Bug: 171032338
Test: 1. atest BackupEligibilityRulesTest
2.1. Run adb backup / restore for SystemBackupAgent and verify
success (running in system_server)
2.2. Run adb backup / restore for NexusLauncher with
"allowAdbBackup=true" and verify success (privileged app)
2.3. Run adb backup / restore for a non-privileged debuggable app
and verify success.
Change-Id: Ifefe6d888377d3ac9482928b27c86b2e562ad8fa
diff --git a/services/backup/Android.bp b/services/backup/Android.bp
index b5444f4..68376c5 100644
--- a/services/backup/Android.bp
+++ b/services/backup/Android.bp
@@ -10,5 +10,5 @@
defaults: ["platform_service_defaults"],
srcs: [":services.backup-sources"],
libs: ["services.core"],
- static_libs: ["backuplib"],
+ static_libs: ["backuplib", "app-compat-annotations"],
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2ff66b5..136cd22f 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3030,9 +3030,11 @@
}
Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup..."));
+ BackupEligibilityRules eligibilityRules = getEligibilityRulesForOperation(
+ OperationType.ADB_BACKUP);
AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
- pkgList, mScheduledBackupEligibility);
+ pkgList, eligibilityRules);
final int token = generateRandomIntegerToken();
synchronized (mAdbBackupRestoreConfirmations) {
mAdbBackupRestoreConfirmations.put(token, params);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index c94286f..e03150e 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -24,6 +24,7 @@
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
+import android.app.backup.BackupManager;
import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.PackageManagerInternal;
import android.os.ParcelFileDescriptor;
@@ -104,11 +105,13 @@
return;
}
+ BackupEligibilityRules eligibilityRules = new BackupEligibilityRules(
+ mBackupManagerService.getPackageManager(),
+ LocalServices.getService(PackageManagerInternal.class),
+ mBackupManagerService.getUserId(), BackupManager.OperationType.ADB_BACKUP);
FullRestoreEngine mEngine = new FullRestoreEngine(mBackupManagerService, null,
mObserver, null, null, true, 0 /*unused*/, true,
- BackupEligibilityRules.forBackup(mBackupManagerService.getPackageManager(),
- LocalServices.getService(PackageManagerInternal.class),
- mBackupManagerService.getUserId()));
+ eligibilityRules);
FullRestoreEngineThread mEngineThread = new FullRestoreEngineThread(mEngine,
tarInputStream);
mEngineThread.run();
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 73ba1f1..2078492 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -25,12 +25,16 @@
import android.annotation.Nullable;
import android.app.backup.BackupManager.OperationType;
import android.app.backup.BackupTransport;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.app.compat.CompatChanges;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
+import android.os.Build;
import android.os.UserHandle;
import android.util.Slog;
@@ -41,6 +45,7 @@
import com.google.android.collect.Sets;
+import java.util.Objects;
import java.util.Set;
/**
@@ -57,6 +62,15 @@
private final int mUserId;
@OperationType private final int mOperationType;
+ /**
+ * When this change is enabled, {@code adb backup} is automatically turned on for apps
+ * running as debuggable ({@code android:debuggable} set to {@code true}) and unavailable to
+ * any other apps.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ static final long RESTRICT_ADB_BACKUP = 171032338L;
+
public static BackupEligibilityRules forBackup(PackageManager packageManager,
PackageManagerInternal packageManagerInternal,
int userId) {
@@ -134,12 +148,53 @@
* @return boolean indicating whether backup is allowed.
*/
public boolean isAppBackupAllowed(ApplicationInfo app) {
- if (mOperationType == OperationType.MIGRATION && !UserHandle.isCore(app.uid)) {
- // Backup / restore of all apps is force allowed during device-to-device migration.
- return true;
- }
+ boolean isSystemApp = UserHandle.isCore(app.uid);
+ boolean allowBackup = (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+ switch (mOperationType) {
+ case OperationType.MIGRATION:
+ // Backup / restore of all non-system apps is force allowed during
+ // device-to-device migration.
+ return !isSystemApp || allowBackup;
+ case OperationType.ADB_BACKUP:
+ String packageName = app.packageName;
+ if (packageName == null) {
+ Slog.w(TAG, "Invalid ApplicationInfo object");
+ return false;
+ }
- return (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+ if (!CompatChanges.isChangeEnabled(RESTRICT_ADB_BACKUP, packageName,
+ UserHandle.of(mUserId))) {
+ return allowBackup;
+ }
+
+ if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+ // Always enable adb backup for SystemBackupAgent in "android" package (this is
+ // done to avoid breaking existing integration tests and might change in the
+ // future).
+ return true;
+ }
+
+ boolean isPrivileged = (app.flags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ boolean isDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ if (isSystemApp || isPrivileged) {
+ try {
+ return mPackageManager.getProperty(PackageManager.PROPERTY_ALLOW_ADB_BACKUP,
+ packageName).getBoolean();
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Failed to read allowAdbBackup property for + "
+ + packageName);
+ return false;
+ }
+ } else {
+ // All other apps can use adb backup only when running in debuggable mode.
+ return isDebuggable;
+ }
+ case OperationType.BACKUP:
+ return allowBackup;
+ default:
+ Slog.w(TAG, "Unknown operation type:" + mOperationType);
+ return false;
+ }
}
/**