Merge changes from topic "br-cts-hsum" into udc-dev

* changes:
  Modifying Backup code to support HSUM mode.
  Improve `dumpsys backup`
This commit is contained in:
Piyush Mehrotra
2023-05-09 22:49:06 +00:00
committed by Android (Google) Code Review
6 changed files with 119 additions and 41 deletions

View File

@@ -253,7 +253,7 @@ public class Bmgr {
try { try {
boolean enable = Boolean.parseBoolean(arg); boolean enable = Boolean.parseBoolean(arg);
mBmgr.setAutoRestore(enable); mBmgr.setAutoRestoreForUser(userId, enable);
System.out.println( System.out.println(
"Auto restore is now " "Auto restore is now "
+ (enable ? "enabled" : "disabled") + (enable ? "enabled" : "disabled")

View File

@@ -56,6 +56,7 @@ public final class Backup {
} }
public void run(String[] args) { public void run(String[] args) {
Log.d(TAG, "Called run() with args: " + String.join(" ", args));
if (mBackupManager == null) { if (mBackupManager == null) {
Log.e(TAG, "Can't obtain Backup Manager binder"); Log.e(TAG, "Can't obtain Backup Manager binder");
return; return;
@@ -70,6 +71,8 @@ public final class Backup {
return; return;
} }
Log.d(TAG, "UserId : " + userId);
String arg = nextArg(); String arg = nextArg();
if (arg.equals("backup")) { if (arg.equals("backup")) {
doBackup(OsConstants.STDOUT_FILENO, userId); doBackup(OsConstants.STDOUT_FILENO, userId);

View File

@@ -813,7 +813,7 @@ public class BackupManagerService extends IBackupManager.Stub {
} }
UserBackupManagerService userBackupManagerService = UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission( getServiceForUserIfCallerHasPermission(
UserHandle.USER_SYSTEM, "hasBackupPassword()"); userId, "hasBackupPassword()");
return userBackupManagerService != null && userBackupManagerService.hasBackupPassword(); return userBackupManagerService != null && userBackupManagerService.hasBackupPassword();
} }
@@ -1515,41 +1515,73 @@ public class BackupManagerService extends IBackupManager.Stub {
@VisibleForTesting @VisibleForTesting
void dumpWithoutCheckingPermission(FileDescriptor fd, PrintWriter pw, String[] args) { void dumpWithoutCheckingPermission(FileDescriptor fd, PrintWriter pw, String[] args) {
int userId = binderGetCallingUserId(); int argIndex = 0;
if (!isUserReadyForBackup(userId)) {
pw.println("Inactive"); String op = nextArg(args, argIndex);
argIndex++;
if ("--help".equals(op)) {
showDumpUsage(pw);
return; return;
} }
if ("users".equals(op)) {
if (args != null) { pw.print(DUMP_RUNNING_USERS_MESSAGE);
for (String arg : args) { for (int i = 0; i < mUserServices.size(); i++) {
if ("-h".equals(arg)) { UserBackupManagerService userBackupManagerService =
pw.println("'dumpsys backup' optional arguments:"); getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i),
pw.println(" -h : this help text"); "dump()");
pw.println(" a[gents] : dump information about defined backup agents"); if (userBackupManagerService != null) {
pw.println(" transportclients : dump information about transport clients"); pw.print(" " + userBackupManagerService.getUserId());
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;
} }
} }
pw.println();
return;
} }
if ("--user".equals(op)) {
for (int i = 0; i < mUserServices.size(); i++) { String userArg = nextArg(args, argIndex);
argIndex++;
if (userArg == null) {
showDumpUsage(pw);
return;
}
int userId = UserHandle.parseUserArg(userArg);
UserBackupManagerService userBackupManagerService = UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), "dump()"); getServiceForUserIfCallerHasPermission(userId, "dump()");
if (userBackupManagerService != null) { if (userBackupManagerService != null) {
userBackupManagerService.dump(fd, pw, args); 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. * @param message A message to include in the exception if it is thrown.
*/ */
void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) { void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
if (Binder.getCallingUserHandle().getIdentifier() != userId) { if (binderGetCallingUserId() != userId) {
mContext.enforceCallingOrSelfPermission( mContext.enforceCallingOrSelfPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
} }

View File

@@ -2797,11 +2797,6 @@ public class UserBackupManagerService {
boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList) { boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup"); 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 // Validate
if (!doAllApps) { if (!doAllApps) {
if (!includeShared) { if (!includeShared) {
@@ -2972,11 +2967,6 @@ public class UserBackupManagerService {
public void adbRestore(ParcelFileDescriptor fd) { public void adbRestore(ParcelFileDescriptor fd) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbRestore"); 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(); final long oldId = Binder.clearCallingIdentity();
try { try {
@@ -3085,7 +3075,7 @@ public class UserBackupManagerService {
"com.android.backupconfirm.BackupRestoreConfirmation"); "com.android.backupconfirm.BackupRestoreConfirmation");
confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token); confIntent.putExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, token);
confIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); confIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
mContext.startActivityAsUser(confIntent, UserHandle.SYSTEM); mContext.startActivityAsUser(confIntent, UserHandle.of(mUserId));
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
return false; return false;
} }

View File

@@ -33,6 +33,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf; import static org.robolectric.Shadows.shadowOf;
import static org.testng.Assert.expectThrows; import static org.testng.Assert.expectThrows;
@@ -118,6 +119,10 @@ public class BackupManagerServiceRoboTest {
mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0); mShadowUserManager.addUser(mUserOneId, "mUserOneId", 0);
mShadowUserManager.addUser(mUserTwoId, "mUserTwoId", 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(BACKUP);
mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL); mShadowContext.grantPermissions(INTERACT_ACROSS_USERS_FULL);
@@ -1469,9 +1474,9 @@ public class BackupManagerServiceRoboTest {
File testFile = createTestFile(); File testFile = createTestFile();
FileDescriptor fileDescriptor = new FileDescriptor(); FileDescriptor fileDescriptor = new FileDescriptor();
PrintWriter printWriter = new PrintWriter(testFile); PrintWriter printWriter = new PrintWriter(testFile);
String[] args = {"1", "2"};
ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM)); ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM));
String[] args = {"--user", "0"};
backupManagerService.dump(fileDescriptor, printWriter, args); backupManagerService.dump(fileDescriptor, printWriter, args);
verify(mUserSystemService).dump(fileDescriptor, printWriter, args); verify(mUserSystemService).dump(fileDescriptor, printWriter, args);
@@ -1485,8 +1490,8 @@ public class BackupManagerServiceRoboTest {
File testFile = createTestFile(); File testFile = createTestFile();
FileDescriptor fileDescriptor = new FileDescriptor(); FileDescriptor fileDescriptor = new FileDescriptor();
PrintWriter printWriter = new PrintWriter(testFile); PrintWriter printWriter = new PrintWriter(testFile);
String[] args = {"1", "2"};
String[] args = {"--user", "10"};
backupManagerService.dump(fileDescriptor, printWriter, args); backupManagerService.dump(fileDescriptor, printWriter, args);
verify(mUserOneService, never()).dump(fileDescriptor, printWriter, args); verify(mUserOneService, never()).dump(fileDescriptor, printWriter, args);

View File

@@ -63,6 +63,7 @@ import com.android.server.SystemService;
import com.android.server.backup.utils.RandomAccessFileUtils; import com.android.server.backup.utils.RandomAccessFileUtils;
import org.junit.After; import org.junit.After;
import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -615,6 +616,53 @@ public class BackupManagerServiceTest {
verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any()); 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 * Test that {@link BackupManagerService#dump(FileDescriptor, PrintWriter, String[])} dumps
* system user information before non-system user information. * system user information before non-system user information.