diff options
6 files changed, 119 insertions, 41 deletions
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index b6dc32a29f04..7d09b992d080 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -253,7 +253,7 @@ public class Bmgr { try { boolean enable = Boolean.parseBoolean(arg); - mBmgr.setAutoRestore(enable); + mBmgr.setAutoRestoreForUser(userId, enable); System.out.println( "Auto restore is now " + (enable ? "enabled" : "disabled") diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java index 373677eccf62..11c9773a7a6c 100644 --- a/cmds/bu/src/com/android/commands/bu/Backup.java +++ b/cmds/bu/src/com/android/commands/bu/Backup.java @@ -56,6 +56,7 @@ public final class Backup { } public void run(String[] args) { + Log.d(TAG, "Called run() with args: " + String.join(" ", args)); if (mBackupManager == null) { Log.e(TAG, "Can't obtain Backup Manager binder"); return; @@ -70,6 +71,8 @@ public final class Backup { return; } + Log.d(TAG, "UserId : " + userId); + String arg = nextArg(); if (arg.equals("backup")) { doBackup(OsConstants.STDOUT_FILENO, userId); diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 3a7aa855ea90..7a3b1190cffa 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -813,7 +813,7 @@ public class BackupManagerService extends IBackupManager.Stub { } UserBackupManagerService userBackupManagerService = getServiceForUserIfCallerHasPermission( - UserHandle.USER_SYSTEM, "hasBackupPassword()"); + userId, "hasBackupPassword()"); return userBackupManagerService != null && userBackupManagerService.hasBackupPassword(); } @@ -1515,41 +1515,73 @@ public class BackupManagerService extends IBackupManager.Stub { @VisibleForTesting void dumpWithoutCheckingPermission(FileDescriptor fd, PrintWriter pw, String[] args) { - int userId = binderGetCallingUserId(); - if (!isUserReadyForBackup(userId)) { - pw.println("Inactive"); + int argIndex = 0; + + String op = nextArg(args, argIndex); + argIndex++; + + if ("--help".equals(op)) { + showDumpUsage(pw); return; } - - if (args != null) { - for (String arg : args) { - if ("-h".equals(arg)) { - pw.println("'dumpsys backup' optional arguments:"); - pw.println(" -h : this help text"); - pw.println(" a[gents] : dump information about defined backup agents"); - pw.println(" transportclients : dump information about transport clients"); - pw.println(" transportstats : dump transport statts"); - pw.println(" users : dump the list of users for which backup service " - + "is running"); - return; - } else if ("users".equals(arg.toLowerCase())) { - pw.print(DUMP_RUNNING_USERS_MESSAGE); - for (int i = 0; i < mUserServices.size(); i++) { - pw.print(" " + mUserServices.keyAt(i)); - } - pw.println(); - return; + if ("users".equals(op)) { + pw.print(DUMP_RUNNING_USERS_MESSAGE); + for (int i = 0; i < mUserServices.size(); i++) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), + "dump()"); + if (userBackupManagerService != null) { + pw.print(" " + userBackupManagerService.getUserId()); } } + pw.println(); + return; } - - for (int i = 0; i < mUserServices.size(); i++) { + if ("--user".equals(op)) { + String userArg = nextArg(args, argIndex); + argIndex++; + if (userArg == null) { + showDumpUsage(pw); + return; + } + int userId = UserHandle.parseUserArg(userArg); UserBackupManagerService userBackupManagerService = - getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), "dump()"); + getServiceForUserIfCallerHasPermission(userId, "dump()"); if (userBackupManagerService != null) { userBackupManagerService.dump(fd, pw, args); } + return; } + if (op == null || "agents".startsWith(op) || "transportclients".equals(op) + || "transportstats".equals(op)) { + for (int i = 0; i < mUserServices.size(); i++) { + UserBackupManagerService userBackupManagerService = + getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), "dump()"); + if (userBackupManagerService != null) { + userBackupManagerService.dump(fd, pw, args); + } + } + return; + } + + showDumpUsage(pw); + } + + private String nextArg(String[] args, int argIndex) { + if (argIndex >= args.length) { + return null; + } + return args[argIndex]; + } + + private static void showDumpUsage(PrintWriter pw) { + pw.println("'dumpsys backup' optional arguments:"); + pw.println(" --help : this help text"); + pw.println(" a[gents] : dump information about defined backup agents"); + pw.println(" transportclients : dump information about transport clients"); + pw.println(" transportstats : dump transport stats"); + pw.println(" users : dump the list of users for which backup service is running"); + pw.println(" --user <userId> : dump information for user userId"); } /** @@ -1654,7 +1686,7 @@ public class BackupManagerService extends IBackupManager.Stub { * @param message A message to include in the exception if it is thrown. */ void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) { - if (Binder.getCallingUserHandle().getIdentifier() != userId) { + if (binderGetCallingUserId() != userId) { mContext.enforceCallingOrSelfPermission( Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); } diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 324f6d7ce622..b7c0ea8b9134 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -2801,11 +2801,6 @@ public class UserBackupManagerService { boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup"); - final int callingUserHandle = UserHandle.getCallingUserId(); - if (callingUserHandle != UserHandle.USER_SYSTEM) { - throw new IllegalStateException("Backup supported only for the device owner"); - } - // Validate if (!doAllApps) { if (!includeShared) { @@ -2976,11 +2971,6 @@ public class UserBackupManagerService { public void adbRestore(ParcelFileDescriptor fd) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore"); - final int callingUserHandle = UserHandle.getCallingUserId(); - if (callingUserHandle != UserHandle.USER_SYSTEM) { - throw new IllegalStateException("Restore supported only for the device owner"); - } - final long oldId = Binder.clearCallingIdentity(); try { @@ -3089,7 +3079,7 @@ public class UserBackupManagerService { "com.android.backupconfirm.BackupRestoreConfirmation"); confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token); confIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM); + mContext.startActivityAsUser(confIntent, UserHandle.of(mUserId)); } catch (ActivityNotFoundException e) { return false; } diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java index 94ee0a871448..91dcd50f176a 100644 --- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java +++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import static org.testng.Assert.expectThrows; @@ -118,6 +119,10 @@ public class BackupManagerServiceRoboTest { mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0); mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 0); + when(mUserSystemService.getUserId()).thenReturn(UserHandle.USER_SYSTEM); + when(mUserOneService.getUserId()).thenReturn(mUserOneId); + when(mUserTwoService.getUserId()).thenReturn(mUserTwoId); + mShadowContext.grantPermissions(BACKUP); mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL); @@ -1469,9 +1474,9 @@ public class BackupManagerServiceRoboTest { File testFile = createTestFile(); FileDescriptor fileDescriptor = new FileDescriptor(); PrintWriter printWriter = new PrintWriter(testFile); - String[] args = {"1", "2"}; ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM)); + String[] args = {"--user", "0"}; backupManagerService.dump(fileDescriptor, printWriter, args); verify(mUserSystemService).dump(fileDescriptor, printWriter, args); @@ -1485,8 +1490,8 @@ public class BackupManagerServiceRoboTest { File testFile = createTestFile(); FileDescriptor fileDescriptor = new FileDescriptor(); PrintWriter printWriter = new PrintWriter(testFile); - String[] args = {"1", "2"}; + String[] args = {"--user", "10"}; backupManagerService.dump(fileDescriptor, printWriter, args); verify(mUserOneService, never()).dump(fileDescriptor, printWriter, args); diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java index b203cf640097..f99e156ed139 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java @@ -63,6 +63,7 @@ import com.android.server.SystemService; import com.android.server.backup.utils.RandomAccessFileUtils; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -615,6 +616,53 @@ public class BackupManagerServiceTest { verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any()); } + @Test + public void testDumpForOneUser_callerDoesNotHaveInteractAcrossUsersFullPermission_ignored() { + createBackupManagerServiceAndUnlockSystemUser(); + mService.setBackupServiceActive(NON_SYSTEM_USER, true); + simulateUserUnlocked(NON_SYSTEM_USER); + + doThrow(new SecurityException()) + .when(mContextMock) + .enforceCallingOrSelfPermission( + eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString()); + + String[] args = new String[]{"--user", Integer.toString(NON_SYSTEM_USER)}; + Assert.assertThrows(SecurityException.class, + () -> mService.dumpWithoutCheckingPermission(mFileDescriptorStub, mPrintWriterMock, + args)); + + verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any()); + } + + @Test + public void + testDumpForOneUser_callerHasInteractAcrossUsersFullPermission_dumpsOnlySpecifiedUser() { + createBackupManagerServiceAndUnlockSystemUser(); + mService.setBackupServiceActive(NON_SYSTEM_USER, true); + simulateUserUnlocked(NON_SYSTEM_USER); + + String[] args = new String[]{"--user", Integer.toString(UserHandle.USER_SYSTEM)}; + mService.dumpWithoutCheckingPermission(mFileDescriptorStub, mPrintWriterMock, args); + + verify(mSystemUserBackupManagerService).dump(any(), any(), any()); + } + + @Test + public void testDumpForAllUsers_callerHasInteractAcrossUsersFullPermission_dumpsAllUsers() { + createBackupManagerServiceAndUnlockSystemUser(); + mService.setBackupServiceActive(NON_SYSTEM_USER, true); + simulateUserUnlocked(NON_SYSTEM_USER); + + String[] args = new String[]{"users"}; + mService.dumpWithoutCheckingPermission(mFileDescriptorStub, mPrintWriterMock, args); + + // Check that dump() invocations are not called on user's Backup service, + // as 'dumpsys backup users' only list users for whom Backup service is running. + verify(mSystemUserBackupManagerService, never()).dump(any(), any(), any()); + verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any()); + } + /** * Test that {@link BackupManagerService#dump(FileDescriptor, PrintWriter, String[])} dumps * system user information before non-system user information. |