Merge "Update eligibility rules for adb backup"
This commit is contained in:
committed by
Android (Google) Code Review
commit
39ede62cbf
@@ -205,13 +205,16 @@ public class BackupManager {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
OperationType.BACKUP,
|
||||
OperationType.MIGRATION
|
||||
OperationType.MIGRATION,
|
||||
OperationType.ADB_BACKUP,
|
||||
})
|
||||
public @interface OperationType {
|
||||
// A regular backup / restore operation.
|
||||
// A backup / restore to / from an off-device location, e.g. cloud.
|
||||
int BACKUP = 0;
|
||||
// A full migration: all app data for non-system apps is eligible.
|
||||
// A direct transfer to another device.
|
||||
int MIGRATION = 1;
|
||||
// Backup via adb, data saved on the host machine.
|
||||
int ADB_BACKUP = 3;
|
||||
}
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@@ -4131,6 +4131,14 @@ public abstract class PackageManager {
|
||||
*/
|
||||
public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
|
||||
|
||||
/**
|
||||
* A manifest property to control app's participation in {@code adb backup}. Should only
|
||||
* be used by system / privileged apps.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String PROPERTY_ALLOW_ADB_BACKUP = "android.backup.ALLOW_ADB_BACKUP";
|
||||
|
||||
/** {@hide} */
|
||||
public int getUserId() {
|
||||
return UserHandle.myUserId();
|
||||
|
||||
@@ -10,5 +10,5 @@ java_library_static {
|
||||
defaults: ["platform_service_defaults"],
|
||||
srcs: [":services.backup-sources"],
|
||||
libs: ["services.core"],
|
||||
static_libs: ["backuplib"],
|
||||
static_libs: ["backuplib", "app-compat-annotations"],
|
||||
}
|
||||
|
||||
@@ -3030,9 +3030,11 @@ public class UserBackupManagerService {
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -24,6 +24,7 @@ import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
|
||||
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 @@ public class PerformAdbRestoreTask implements Runnable {
|
||||
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();
|
||||
|
||||
@@ -25,12 +25,16 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
|
||||
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.android.server.backup.transport.TransportClient;
|
||||
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -57,6 +62,15 @@ public class BackupEligibilityRules {
|
||||
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 @@ public class BackupEligibilityRules {
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@ android_test {
|
||||
"androidx.test.ext.truth",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.rules",
|
||||
"platform-compat-test-rules",
|
||||
"mockito-target-minus-junit4",
|
||||
"platform-test-annotations",
|
||||
"ShortcutManagerTestUtils",
|
||||
|
||||
@@ -18,14 +18,17 @@ package com.android.server.backup.utils;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.backup.BackupManager.OperationType;
|
||||
import android.compat.testing.PlatformCompatChangeRule;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.Property;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.Signature;
|
||||
@@ -38,9 +41,15 @@ import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.backup.UserBackupManagerService;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
|
||||
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
|
||||
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
@@ -50,17 +59,19 @@ import org.mockito.MockitoAnnotations;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BackupEligibilityRulesTest {
|
||||
private static final String CUSTOM_BACKUP_AGENT_NAME = "custom.backup.agent";
|
||||
private static final String TEST_PACKAGE_NAME = "test_package";
|
||||
private static final String TEST_PACKAGE_NAME = "com.android.frameworks.servicestests";
|
||||
|
||||
private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
|
||||
private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
|
||||
private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
|
||||
private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
|
||||
|
||||
@Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
|
||||
|
||||
@Mock private PackageManagerInternal mMockPackageManagerInternal;
|
||||
@Mock private PackageManager mPackageManager;
|
||||
private BackupEligibilityRules mBackupEligibilityRules;
|
||||
|
||||
private BackupEligibilityRules mBackupEligibilityRules;
|
||||
private int mUserId;
|
||||
|
||||
@Before
|
||||
@@ -225,7 +236,6 @@ public class BackupEligibilityRulesTest {
|
||||
throws Exception {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(Process.SYSTEM_UID,
|
||||
/* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
|
||||
|
||||
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
|
||||
OperationType.MIGRATION);
|
||||
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
|
||||
@@ -233,6 +243,82 @@ public class BackupEligibilityRulesTest {
|
||||
assertThat(isEligible).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
|
||||
public void appIsEligibleForBackup_adbBackupNotAllowed_returnsFalseForAdbBackup()
|
||||
throws Exception {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
|
||||
/* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
|
||||
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
|
||||
OperationType.ADB_BACKUP);
|
||||
when(mPackageManager.getProperty(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
|
||||
eq(TEST_PACKAGE_NAME))).thenReturn(getAdbBackupProperty(
|
||||
/* allowAdbBackup */ false));
|
||||
|
||||
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
|
||||
|
||||
assertThat(isEligible).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
|
||||
public void appIsEligibleForBackup_adbBackupAllowed_returnsTrueForAdbBackup()
|
||||
throws Exception {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
|
||||
/* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
|
||||
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
|
||||
OperationType.ADB_BACKUP);
|
||||
when(mPackageManager.getProperty(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
|
||||
eq(TEST_PACKAGE_NAME))).thenReturn(getAdbBackupProperty(
|
||||
/* allowAdbBackup */ true));
|
||||
|
||||
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
|
||||
|
||||
assertThat(isEligible).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
|
||||
public void appIsEligibleForBackup_debuggableNonPrivilegedApp_returnsTrueForAdbBackup()
|
||||
throws Exception {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
|
||||
/* flags */ ApplicationInfo.FLAG_DEBUGGABLE, CUSTOM_BACKUP_AGENT_NAME);
|
||||
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
|
||||
OperationType.ADB_BACKUP);
|
||||
|
||||
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
|
||||
|
||||
assertThat(isEligible).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
|
||||
public void appIsEligibleForBackup_allowBackupTrueBeforeS_returnsTrueForAdbBackup()
|
||||
throws Exception {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
|
||||
ApplicationInfo.FLAG_ALLOW_BACKUP, CUSTOM_BACKUP_AGENT_NAME);
|
||||
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
|
||||
OperationType.ADB_BACKUP);
|
||||
|
||||
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
|
||||
|
||||
assertThat(isEligible).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
|
||||
public void appIsEligibleForBackup_allowBackupFalseBeforeS_returnsFalseForAdbBackup()
|
||||
throws Exception {
|
||||
ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
|
||||
/* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
|
||||
BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
|
||||
OperationType.ADB_BACKUP);
|
||||
|
||||
boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
|
||||
|
||||
assertThat(isEligible).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appIsDisabled_stateDefaultManifestEnabled_returnsFalse() throws Exception {
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
@@ -789,10 +875,15 @@ public class BackupEligibilityRulesTest {
|
||||
private static ApplicationInfo getApplicationInfo(int appUid, int flags,
|
||||
String backupAgentName) {
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.flags = 0;
|
||||
applicationInfo.flags = flags;
|
||||
applicationInfo.packageName = TEST_PACKAGE_NAME;
|
||||
applicationInfo.uid = appUid;
|
||||
applicationInfo.backupAgentName = backupAgentName;
|
||||
return applicationInfo;
|
||||
}
|
||||
|
||||
private static Property getAdbBackupProperty(boolean allowAdbBackup) {
|
||||
return new Property(PackageManager.PROPERTY_ALLOW_ADB_BACKUP, allowAdbBackup,
|
||||
TEST_PACKAGE_NAME, /* className */ "");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user