1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.backup; 18 19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyBoolean; 26 import static org.mockito.ArgumentMatchers.anyInt; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.Mockito.never; 29 import static org.mockito.Mockito.reset; 30 import static org.mockito.Mockito.spy; 31 import static org.mockito.Mockito.verify; 32 import static org.mockito.Mockito.when; 33 34 import android.app.ActivityManager; 35 import android.app.ActivityManagerInternal; 36 import android.app.ApplicationThreadConstants; 37 import android.app.IActivityManager; 38 import android.app.IBackupAgent; 39 import android.app.backup.BackupAnnotations.BackupDestination; 40 import android.app.backup.BackupAnnotations.OperationType; 41 import android.compat.testing.PlatformCompatChangeRule; 42 import android.content.pm.ApplicationInfo; 43 import android.content.pm.PackageManager; 44 import android.os.Process; 45 import android.os.UserHandle; 46 import android.platform.test.annotations.DisableFlags; 47 import android.platform.test.annotations.EnableFlags; 48 import android.platform.test.annotations.Presubmit; 49 import android.platform.test.flag.junit.SetFlagsRule; 50 51 import androidx.test.runner.AndroidJUnit4; 52 53 import com.android.server.LocalServices; 54 import com.android.server.backup.internal.LifecycleOperationStorage; 55 56 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; 57 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 58 59 import com.google.common.collect.ImmutableSet; 60 61 import org.junit.After; 62 import org.junit.Before; 63 import org.junit.Rule; 64 import org.junit.Test; 65 import org.junit.rules.TestRule; 66 import org.junit.runner.RunWith; 67 import org.mockito.Mock; 68 import org.mockito.MockitoAnnotations; 69 import org.mockito.MockitoSession; 70 import org.mockito.quality.Strictness; 71 72 import java.util.Set; 73 74 @Presubmit 75 @RunWith(AndroidJUnit4.class) 76 public class BackupAgentConnectionManagerTest { 77 private static final String TEST_PACKAGE = "com.test.package"; 78 79 @Rule 80 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 81 @Rule 82 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 83 84 @Mock 85 IActivityManager mActivityManager; 86 @Mock 87 ActivityManagerInternal mActivityManagerInternal; 88 @Mock 89 LifecycleOperationStorage mOperationStorage; 90 @Mock 91 UserBackupManagerService mUserBackupManagerService; 92 @Mock 93 IBackupAgent.Stub mBackupAgentStub; 94 @Mock 95 PackageManager mPackageManager; 96 97 private BackupAgentConnectionManager mConnectionManager; 98 private MockitoSession mSession; 99 private ApplicationInfo mTestApplicationInfo; 100 private IBackupAgent mBackupAgentResult; 101 private Thread mTestThread; 102 103 @Before setUp()104 public void setUp() throws Exception { 105 mSession = mockitoSession().initMocks(this).mockStatic(ActivityManager.class).mockStatic( 106 LocalServices.class).strictness(Strictness.LENIENT).startMocking(); 107 MockitoAnnotations.initMocks(this); 108 109 doReturn(mActivityManager).when(ActivityManager::getService); 110 doReturn(mActivityManagerInternal).when( 111 () -> LocalServices.getService(ActivityManagerInternal.class)); 112 // Real package manager throws if a property is not defined. 113 when(mPackageManager.getPropertyAsUser(any(), any(), any(), anyInt())).thenThrow( 114 new PackageManager.NameNotFoundException()); 115 116 mConnectionManager = spy( 117 new BackupAgentConnectionManager(mOperationStorage, mPackageManager, 118 mUserBackupManagerService, UserHandle.USER_SYSTEM)); 119 120 mTestApplicationInfo = new ApplicationInfo(); 121 mTestApplicationInfo.packageName = TEST_PACKAGE; 122 mTestApplicationInfo.processName = TEST_PACKAGE; 123 mTestApplicationInfo.uid = Process.FIRST_APPLICATION_UID + 1; 124 125 mBackupAgentResult = null; 126 mTestThread = null; 127 } 128 129 @After tearDown()130 public void tearDown() { 131 if (mSession != null) { 132 mSession.finishMocking(); 133 } 134 } 135 136 @Test bindToAgentSynchronous_amReturnsFailure_returnsNullAndClearsPendingBackups()137 public void bindToAgentSynchronous_amReturnsFailure_returnsNullAndClearsPendingBackups() 138 throws Exception { 139 when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 140 anyBoolean())).thenReturn(false); 141 142 IBackupAgent result = mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 143 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 144 145 assertThat(result).isNull(); 146 verify(mActivityManagerInternal).clearPendingBackup(UserHandle.USER_SYSTEM); 147 } 148 149 @Test bindToAgentSynchronous_agentDisconnectedCalled_returnsNullAndClearsPendingBackups()150 public void bindToAgentSynchronous_agentDisconnectedCalled_returnsNullAndClearsPendingBackups() 151 throws Exception { 152 when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 153 anyBoolean())).thenReturn(true); 154 // This is so that IBackupAgent.Stub.asInterface() works. 155 when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub); 156 when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID); 157 158 // This is going to block until it receives the callback so we need to run it on a 159 // separate thread. 160 Thread testThread = new Thread(() -> setBackupAgentResult( 161 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 162 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)), 163 "backup-agent-connection-manager-test"); 164 testThread.start(); 165 // Give the testThread a head start, otherwise agentConnected() might run before 166 // bindToAgentSynchronous() is called. 167 Thread.sleep(500); 168 mConnectionManager.agentDisconnected(TEST_PACKAGE); 169 testThread.join(); 170 171 assertThat(mBackupAgentResult).isNull(); 172 verify(mActivityManagerInternal).clearPendingBackup(UserHandle.USER_SYSTEM); 173 } 174 175 @Test bindToAgentSynchronous_agentConnectedCalled_returnsBackupAgent()176 public void bindToAgentSynchronous_agentConnectedCalled_returnsBackupAgent() throws Exception { 177 bindAndConnectToTestAppAgent(ApplicationThreadConstants.BACKUP_MODE_FULL); 178 179 assertThat(mBackupAgentResult).isEqualTo(mBackupAgentStub); 180 verify(mActivityManagerInternal, never()).clearPendingBackup(anyInt()); 181 } 182 183 @Test bindToAgentSynchronous_unexpectedAgentConnected_doesNotReturnWrongAgent()184 public void bindToAgentSynchronous_unexpectedAgentConnected_doesNotReturnWrongAgent() 185 throws Exception { 186 when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 187 anyBoolean())).thenReturn(true); 188 // This is so that IBackupAgent.Stub.asInterface() works. 189 when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub); 190 when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID); 191 192 // This is going to block until it receives the callback so we need to run it on a 193 // separate thread. 194 Thread testThread = new Thread(() -> setBackupAgentResult( 195 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 196 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD)), 197 "backup-agent-connection-manager-test"); 198 testThread.start(); 199 // Give the testThread a head start, otherwise agentConnected() might run before 200 // bindToAgentSynchronous() is called. 201 Thread.sleep(500); 202 mConnectionManager.agentConnected("com.other.package", mBackupAgentStub); 203 testThread.join(100); // Avoid waiting the full timeout. 204 205 assertThat(mBackupAgentResult).isNull(); 206 } 207 208 @Test 209 @DisableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode()210 public void bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode() 211 throws Exception { 212 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 213 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 214 215 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 216 /* useRestrictedMode= */ eq(true)); 217 // Make sure we never hit the code that checks the property. 218 verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt()); 219 } 220 221 @Test 222 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) bindToAgentSynchronous_keyValueBackup_shouldNotUseRestrictedMode()223 public void bindToAgentSynchronous_keyValueBackup_shouldNotUseRestrictedMode() 224 throws Exception { 225 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 226 ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, BackupDestination.CLOUD); 227 228 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 229 /* useRestrictedMode= */ eq(false)); 230 // Make sure we never hit the code that checks the property. 231 verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt()); 232 } 233 234 @Test 235 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) bindToAgentSynchronous_keyValueRestore_shouldNotUseRestrictedMode()236 public void bindToAgentSynchronous_keyValueRestore_shouldNotUseRestrictedMode() 237 throws Exception { 238 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 239 ApplicationThreadConstants.BACKUP_MODE_RESTORE, BackupDestination.CLOUD); 240 241 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 242 /* useRestrictedMode= */ eq(false)); 243 // Make sure we never hit the code that checks the property. 244 verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt()); 245 } 246 247 @Test 248 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) bindToAgentSynchronous_packageOptedIn_shouldUseRestrictedMode()249 public void bindToAgentSynchronous_packageOptedIn_shouldUseRestrictedMode() throws Exception { 250 reset(mPackageManager); 251 when(mPackageManager.getPropertyAsUser( 252 eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(), 253 anyInt())).thenReturn(new PackageManager.Property( 254 PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ true, 255 TEST_PACKAGE, /* className= */ null)); 256 257 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 258 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 259 260 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 261 /* useRestrictedMode= */ eq(true)); 262 } 263 264 @Test 265 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) bindToAgentSynchronous_packageOptedOut_shouldNotUseRestrictedMode()266 public void bindToAgentSynchronous_packageOptedOut_shouldNotUseRestrictedMode() 267 throws Exception { 268 reset(mPackageManager); 269 when(mPackageManager.getPropertyAsUser( 270 eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(), 271 anyInt())).thenReturn(new PackageManager.Property( 272 PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ false, 273 TEST_PACKAGE, /* className= */ null)); 274 275 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 276 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 277 278 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 279 /* useRestrictedMode= */ eq(false)); 280 } 281 282 @Test 283 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) 284 @DisableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE}) bindToAgentSynchronous_targetSdkBelowB_shouldUseRestrictedMode()285 public void bindToAgentSynchronous_targetSdkBelowB_shouldUseRestrictedMode() throws Exception { 286 reset(mPackageManager); 287 // Mock that the app has not explicitly set the property. 288 when(mPackageManager.getPropertyAsUser( 289 eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(), 290 anyInt())).thenThrow(new PackageManager.NameNotFoundException()); 291 292 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 293 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 294 295 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 296 /* useRestrictedMode= */ eq(true)); 297 } 298 299 @Test 300 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) 301 @EnableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE}) bindToAgentSynchronous_targetSdkB_notInList_shouldUseRestrictedMode()302 public void bindToAgentSynchronous_targetSdkB_notInList_shouldUseRestrictedMode() 303 throws Exception { 304 reset(mPackageManager); 305 // Mock that the app has not explicitly set the property. 306 when(mPackageManager.getPropertyAsUser( 307 eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(), 308 anyInt())).thenThrow(new PackageManager.NameNotFoundException()); 309 mConnectionManager.clearNoRestrictedModePackages(); 310 311 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 312 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 313 314 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 315 /* useRestrictedMode= */ eq(true)); 316 } 317 318 @Test 319 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) 320 @EnableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE}) bindToAgentSynchronous_forRestore_targetSdkB_inList_shouldNotUseRestrictedMode()321 public void bindToAgentSynchronous_forRestore_targetSdkB_inList_shouldNotUseRestrictedMode() 322 throws Exception { 323 reset(mPackageManager); 324 // Mock that the app has not explicitly set the property. 325 when(mPackageManager.getPropertyAsUser( 326 eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(), 327 anyInt())).thenThrow(new PackageManager.NameNotFoundException()); 328 mConnectionManager.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.RESTORE); 329 330 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 331 ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, BackupDestination.CLOUD); 332 333 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 334 /* useRestrictedMode= */ eq(false)); 335 } 336 337 @Test 338 @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) 339 @EnableCompatChanges({BackupAgentConnectionManager.OS_DECIDES_BACKUP_RESTRICTED_MODE}) bindToAgentSynchronous_forBackup_targetSdkB_inList_shouldNotUseRestrictedMode()340 public void bindToAgentSynchronous_forBackup_targetSdkB_inList_shouldNotUseRestrictedMode() 341 throws Exception { 342 reset(mPackageManager); 343 // Mock that the app has not explicitly set the property. 344 when(mPackageManager.getPropertyAsUser( 345 eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), eq(TEST_PACKAGE), any(), 346 anyInt())).thenThrow(new PackageManager.NameNotFoundException()); 347 mConnectionManager.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.BACKUP); 348 349 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, 350 ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); 351 352 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 353 /* useRestrictedMode= */ eq(false)); 354 } 355 356 @Test agentDisconnected_cancelsCurrentOperations()357 public void agentDisconnected_cancelsCurrentOperations() throws Exception { 358 when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID); 359 when(mOperationStorage.operationTokensForPackage(eq(TEST_PACKAGE))).thenReturn( 360 ImmutableSet.of(123, 456, 789)); 361 when(mConnectionManager.getThreadForCancellation(any())).thenAnswer(invocation -> { 362 Thread testThread = new Thread((Runnable) invocation.getArgument(0), 363 "agent-disconnected-test"); 364 setTestThread(testThread); 365 return testThread; 366 }); 367 368 mConnectionManager.agentDisconnected(TEST_PACKAGE); 369 370 mTestThread.join(); 371 verify(mUserBackupManagerService).handleCancel(eq(123), eq(true)); 372 verify(mUserBackupManagerService).handleCancel(eq(456), eq(true)); 373 verify(mUserBackupManagerService).handleCancel(eq(789), eq(true)); 374 } 375 376 @Test unbindAgent_callsAmUnbindBackupAgent()377 public void unbindAgent_callsAmUnbindBackupAgent() throws Exception { 378 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ false); 379 380 verify(mActivityManager).unbindBackupAgent(eq(mTestApplicationInfo)); 381 } 382 383 @Test unbindAgent_doNotAllowKill_doesNotKillApp()384 public void unbindAgent_doNotAllowKill_doesNotKillApp() throws Exception { 385 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ false); 386 387 verify(mActivityManager, never()).killApplicationProcess(any(), anyInt()); 388 } 389 390 @Test unbindAgent_allowKill_isCoreApp_doesNotKillApp()391 public void unbindAgent_allowKill_isCoreApp_doesNotKillApp() throws Exception { 392 mTestApplicationInfo.uid = 1000; 393 394 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ true); 395 396 verify(mActivityManager, never()).killApplicationProcess(any(), anyInt()); 397 } 398 399 @Test unbindAgent_allowKill_notCurrentConnection_killsApp()400 public void unbindAgent_allowKill_notCurrentConnection_killsApp() throws Exception { 401 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ true); 402 403 verify(mActivityManager).killApplicationProcess(eq(TEST_PACKAGE), anyInt()); 404 } 405 406 @Test unbindAgent_allowKill_inRestrictedMode_killsApp()407 public void unbindAgent_allowKill_inRestrictedMode_killsApp() throws Exception { 408 bindAndConnectToTestAppAgent(ApplicationThreadConstants.BACKUP_MODE_FULL); 409 410 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ true); 411 412 verify(mActivityManager).killApplicationProcess(eq(TEST_PACKAGE), anyInt()); 413 } 414 415 @Test unbindAgent_allowKill_notInRestrictedMode_doesNotKillApp()416 public void unbindAgent_allowKill_notInRestrictedMode_doesNotKillApp() throws Exception { 417 bindAndConnectToTestAppAgent(ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); 418 419 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ true); 420 421 verify(mActivityManager, never()).killApplicationProcess(any(), anyInt()); 422 } 423 424 @Test unbindAgent_allowKill_isRestore_noKillAfterRestore_doesNotKillApp()425 public void unbindAgent_allowKill_isRestore_noKillAfterRestore_doesNotKillApp() 426 throws Exception { 427 bindAndConnectToTestAppAgent(ApplicationThreadConstants.BACKUP_MODE_RESTORE); 428 mTestApplicationInfo.flags = 0; 429 verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 430 /* useRestrictedMode= */ eq(false)); 431 432 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ true); 433 434 verify(mActivityManager, never()).killApplicationProcess(any(), anyInt()); 435 } 436 437 @Test unbindAgent_allowKill_isRestore_killAfterRestore_killsApp()438 public void unbindAgent_allowKill_isRestore_killAfterRestore_killsApp() throws Exception { 439 bindAndConnectToTestAppAgent(ApplicationThreadConstants.BACKUP_MODE_RESTORE); 440 mTestApplicationInfo.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 441 442 mConnectionManager.unbindAgent(mTestApplicationInfo, /* allowKill= */ true); 443 444 verify(mActivityManager).killApplicationProcess(eq(TEST_PACKAGE), anyInt()); 445 } 446 447 // Needed because variables can't be assigned directly inside lambdas in Java. setBackupAgentResult(IBackupAgent result)448 private void setBackupAgentResult(IBackupAgent result) { 449 mBackupAgentResult = result; 450 } 451 452 // Needed because variables can't be assigned directly inside lambdas in Java. setTestThread(Thread thread)453 private void setTestThread(Thread thread) { 454 mTestThread = thread; 455 } 456 bindAndConnectToTestAppAgent(int backupMode)457 private void bindAndConnectToTestAppAgent(int backupMode) throws Exception { 458 when(mActivityManager.bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), 459 anyBoolean())).thenReturn(true); 460 // This is going to block until it receives the callback so we need to run it on a 461 // separate thread. 462 Thread testThread = new Thread(() -> setBackupAgentResult( 463 mConnectionManager.bindToAgentSynchronous(mTestApplicationInfo, backupMode, 464 BackupDestination.CLOUD)), "backup-agent-connection-manager-test"); 465 testThread.start(); 466 // Give the testThread a head start, otherwise agentConnected() might run before 467 // bindToAgentSynchronous() is called. 468 Thread.sleep(500); 469 when(mConnectionManager.getCallingUid()).thenReturn(Process.SYSTEM_UID); 470 // This is so that IBackupAgent.Stub.asInterface() works. 471 when(mBackupAgentStub.queryLocalInterface(any())).thenReturn(mBackupAgentStub); 472 mConnectionManager.agentConnected(TEST_PACKAGE, mBackupAgentStub); 473 testThread.join(); 474 } 475 } 476