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