blob: 949c504d64dcd3a94a30561816a7cdf3b1fe0314 [file] [log] [blame]
Robert Berry39194c02018-01-11 13:50:56 +00001/*
2 * Copyright (C) 2018 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
17package com.android.server.backup;
18
Bernardo Rufino8553d272018-02-13 11:16:37 +000019import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
20import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
21import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
Bernardo Rufinocea93532018-02-28 11:05:18 +000022
Robert Berry39194c02018-01-11 13:50:56 +000023import static com.android.server.backup.testing.TransportData.backupTransport;
Robert Berry39194c02018-01-11 13:50:56 +000024
25import static com.google.common.truth.Truth.assertThat;
26
Robert Berry39194c02018-01-11 13:50:56 +000027import static org.mockito.ArgumentMatchers.any;
28import static org.mockito.ArgumentMatchers.anyInt;
Bernardo Rufino228a6492018-02-10 13:08:52 +000029import static org.mockito.ArgumentMatchers.anyLong;
Robert Berry39194c02018-01-11 13:50:56 +000030import static org.mockito.ArgumentMatchers.argThat;
31import static org.mockito.ArgumentMatchers.eq;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +000032import static org.mockito.Mockito.doAnswer;
33import static org.mockito.Mockito.doNothing;
Bernardo Rufino228a6492018-02-10 13:08:52 +000034import static org.mockito.Mockito.never;
Robert Berry39194c02018-01-11 13:50:56 +000035import static org.mockito.Mockito.spy;
Bernardo Rufino228a6492018-02-10 13:08:52 +000036import static org.mockito.Mockito.times;
Robert Berry39194c02018-01-11 13:50:56 +000037import static org.mockito.Mockito.verify;
38import static org.mockito.Mockito.when;
39import static org.robolectric.Shadows.shadowOf;
40
41import static java.util.Collections.emptyList;
42import static java.util.stream.Collectors.toCollection;
43import static java.util.stream.Collectors.toList;
44
45import android.app.Application;
Robert Berry39194c02018-01-11 13:50:56 +000046import android.app.IBackupAgent;
47import android.app.backup.BackupAgent;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +000048import android.app.backup.BackupDataInput;
Robert Berry39194c02018-01-11 13:50:56 +000049import android.app.backup.BackupDataOutput;
Bernardo Rufino228a6492018-02-10 13:08:52 +000050import android.app.backup.BackupManager;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +000051import android.app.backup.BackupTransport;
Robert Berry39194c02018-01-11 13:50:56 +000052import android.app.backup.IBackupManager;
53import android.app.backup.IBackupManagerMonitor;
54import android.app.backup.IBackupObserver;
Robert Berry39194c02018-01-11 13:50:56 +000055import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageInfo;
57import android.content.pm.PackageManager;
58import android.os.Handler;
Robert Berry39194c02018-01-11 13:50:56 +000059import android.os.Looper;
60import android.os.Message;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +000061import android.os.ParcelFileDescriptor;
Robert Berry39194c02018-01-11 13:50:56 +000062import android.os.PowerManager;
63import android.os.RemoteException;
64import android.platform.test.annotations.Presubmit;
65import android.util.Pair;
Robert Berry39194c02018-01-11 13:50:56 +000066
67import com.android.internal.backup.IBackupTransport;
68import com.android.server.backup.internal.BackupHandler;
69import com.android.server.backup.internal.BackupRequest;
70import com.android.server.backup.internal.OnTaskFinishedListener;
71import com.android.server.backup.internal.PerformBackupTask;
72import com.android.server.backup.testing.TransportData;
Bernardo Rufino228a6492018-02-10 13:08:52 +000073import com.android.server.backup.testing.TransportTestUtils;
Robert Berry39194c02018-01-11 13:50:56 +000074import com.android.server.backup.testing.TransportTestUtils.TransportMock;
75import com.android.server.backup.transport.TransportClient;
76import com.android.server.testing.FrameworkRobolectricTestRunner;
77import com.android.server.testing.SystemLoaderClasses;
Bernardo Rufino03b76772018-01-30 17:43:47 +000078import com.android.server.testing.SystemLoaderPackages;
Robert Berry39194c02018-01-11 13:50:56 +000079import com.android.server.testing.shadows.ShadowBackupDataInput;
80import com.android.server.testing.shadows.ShadowBackupDataOutput;
81
82import org.junit.Before;
Andreas Gampecea9e6d2018-02-22 18:06:44 -080083import org.junit.Ignore;
Robert Berry39194c02018-01-11 13:50:56 +000084import org.junit.Test;
85import org.junit.runner.RunWith;
86import org.mockito.ArgumentMatcher;
87import org.mockito.Mock;
88import org.mockito.MockitoAnnotations;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +000089import org.mockito.invocation.InvocationOnMock;
90import org.mockito.stubbing.Answer;
Robert Berry39194c02018-01-11 13:50:56 +000091import org.robolectric.RuntimeEnvironment;
92import org.robolectric.annotation.Config;
Robert Berry39194c02018-01-11 13:50:56 +000093import org.robolectric.shadows.ShadowLooper;
94import org.robolectric.shadows.ShadowPackageManager;
95import org.robolectric.shadows.ShadowQueuedWork;
96
97import java.io.File;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +000098import java.io.IOException;
Robert Berry39194c02018-01-11 13:50:56 +000099import java.util.ArrayList;
100import java.util.List;
101import java.util.stream.Stream;
102
103@RunWith(FrameworkRobolectricTestRunner.class)
104@Config(
105 manifest = Config.NONE,
106 sdk = 26,
Bernardo Rufinocea93532018-02-28 11:05:18 +0000107 shadows = {ShadowBackupDataInput.class, ShadowBackupDataOutput.class, ShadowQueuedWork.class}
Robert Berry39194c02018-01-11 13:50:56 +0000108)
Michal Karpinskib5e09312018-02-19 13:55:23 +0000109@SystemLoaderPackages({"com.android.server.backup", "android.app.backup"})
Bernardo Rufinocea93532018-02-28 11:05:18 +0000110@SystemLoaderClasses({IBackupTransport.class, IBackupAgent.class, PackageInfo.class})
Robert Berry39194c02018-01-11 13:50:56 +0000111@Presubmit
112public class PerformBackupTaskTest {
113 private static final String PACKAGE_1 = "com.example.package1";
114 private static final String PACKAGE_2 = "com.example.package2";
115
Michal Karpinskife4ae0c2018-01-25 15:24:00 +0000116 @Mock private BackupManagerService mBackupManagerService;
Robert Berry39194c02018-01-11 13:50:56 +0000117 @Mock private TransportManager mTransportManager;
118 @Mock private DataChangedJournal mDataChangedJournal;
119 @Mock private IBackupObserver mObserver;
120 @Mock private IBackupManagerMonitor mMonitor;
121 @Mock private OnTaskFinishedListener mListener;
122 private TransportData mTransport;
Robert Berry39194c02018-01-11 13:50:56 +0000123 private ShadowLooper mShadowBackupLooper;
124 private BackupHandler mBackupHandler;
125 private PowerManager.WakeLock mWakeLock;
126 private ShadowPackageManager mShadowPackageManager;
127 private FakeIBackupManager mBackupManager;
Bernardo Rufino228a6492018-02-10 13:08:52 +0000128 private File mBaseStateDir;
Robert Berry39194c02018-01-11 13:50:56 +0000129
130 @Before
131 public void setUp() throws Exception {
132 MockitoAnnotations.initMocks(this);
133
134 mTransport = backupTransport();
Robert Berry39194c02018-01-11 13:50:56 +0000135
136 Application application = RuntimeEnvironment.application;
137 File cacheDir = application.getCacheDir();
Bernardo Rufino228a6492018-02-10 13:08:52 +0000138 mBaseStateDir = new File(cacheDir, "base_state_dir");
Robert Berry39194c02018-01-11 13:50:56 +0000139 File dataDir = new File(cacheDir, "data_dir");
Bernardo Rufino228a6492018-02-10 13:08:52 +0000140 assertThat(mBaseStateDir.mkdir()).isTrue();
Robert Berry39194c02018-01-11 13:50:56 +0000141 assertThat(dataDir.mkdir()).isTrue();
Robert Berry39194c02018-01-11 13:50:56 +0000142
143 PackageManager packageManager = application.getPackageManager();
Bernardo Rufinoff589c92018-02-25 12:51:25 +0000144 mShadowPackageManager = shadowOf(packageManager);
Robert Berry39194c02018-01-11 13:50:56 +0000145
Bernardo Rufino8553d272018-02-13 11:16:37 +0000146 mWakeLock = createBackupWakeLock(application);
Robert Berry39194c02018-01-11 13:50:56 +0000147
Bernardo Rufino8553d272018-02-13 11:16:37 +0000148 Looper backupLooper = startBackupThreadAndGetLooper();
Robert Berry39194c02018-01-11 13:50:56 +0000149 mShadowBackupLooper = shadowOf(backupLooper);
Annie Meng92892162018-03-15 14:45:46 +0000150
151 Handler mainHandler = new Handler(Looper.getMainLooper());
152 BackupAgentTimeoutParameters agentTimeoutParameters =
153 new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver());
154 agentTimeoutParameters.start();
155
156 // We need to mock BMS timeout parameters before initializing the BackupHandler since
157 // the constructor of BackupHandler relies on the timeout parameters.
158 when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
Robert Berry39194c02018-01-11 13:50:56 +0000159 mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper);
160
161 mBackupManager = spy(FakeIBackupManager.class);
162
Bernardo Rufino8553d272018-02-13 11:16:37 +0000163 setUpBackupManagerServiceBasics(
164 mBackupManagerService,
165 application,
166 mTransportManager,
167 packageManager,
168 mBackupHandler,
Annie Meng92892162018-03-15 14:45:46 +0000169 mWakeLock,
170 agentTimeoutParameters);
Bernardo Rufino228a6492018-02-10 13:08:52 +0000171 when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
Robert Berry39194c02018-01-11 13:50:56 +0000172 when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
Robert Berry39194c02018-01-11 13:50:56 +0000173 when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
Robert Berry39194c02018-01-11 13:50:56 +0000174 }
175
176 @Test
177 public void testRunTask_whenTransportProvidesFlags_passesThemToTheAgent() throws Exception {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000178 TransportMock transportMock = setUpTransport(mTransport);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000179 AgentMock agentMock = setUpAgent(PACKAGE_1);
Robert Berry39194c02018-01-11 13:50:56 +0000180 int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
Bernardo Rufino228a6492018-02-10 13:08:52 +0000181 when(transportMock.transport.getTransportFlags()).thenReturn(flags);
182 PerformBackupTask task =
183 createPerformBackupTask(
184 transportMock.transportClient,
185 mTransport.transportDirName,
186 emptyList(),
187 PACKAGE_1);
Robert Berry39194c02018-01-11 13:50:56 +0000188
189 runTask(task);
190
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000191 verify(agentMock.agent)
192 .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
Robert Berry39194c02018-01-11 13:50:56 +0000193 }
194
195 @Test
196 public void testRunTask_whenTransportDoesNotProvidesFlags() throws Exception {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000197 TransportMock transportMock = setUpTransport(mTransport);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000198 AgentMock agentMock = setUpAgent(PACKAGE_1);
Bernardo Rufino228a6492018-02-10 13:08:52 +0000199 PerformBackupTask task =
200 createPerformBackupTask(
201 transportMock.transportClient,
202 mTransport.transportDirName,
203 emptyList(),
204 PACKAGE_1);
Robert Berry39194c02018-01-11 13:50:56 +0000205
206 runTask(task);
207
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000208 verify(agentMock.agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
Robert Berry39194c02018-01-11 13:50:56 +0000209 }
210
211 @Test
212 public void testRunTask_whenTransportProvidesFlagsAndMultipleAgents_passesToAll()
213 throws Exception {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000214 TransportMock transportMock = setUpTransport(mTransport);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000215 List<AgentMock> agentMocks = setUpAgents(PACKAGE_1, PACKAGE_2);
216 BackupAgent agent1 = agentMocks.get(0).agent;
217 BackupAgent agent2 = agentMocks.get(1).agent;
Robert Berry39194c02018-01-11 13:50:56 +0000218 int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
Bernardo Rufino228a6492018-02-10 13:08:52 +0000219 when(transportMock.transport.getTransportFlags()).thenReturn(flags);
Robert Berry39194c02018-01-11 13:50:56 +0000220 PerformBackupTask task =
Bernardo Rufino228a6492018-02-10 13:08:52 +0000221 createPerformBackupTask(
222 transportMock.transportClient,
223 mTransport.transportDirName,
224 emptyList(),
225 PACKAGE_1,
226 PACKAGE_2);
Robert Berry39194c02018-01-11 13:50:56 +0000227
228 runTask(task);
229
230 verify(agent1).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
231 verify(agent2).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
232 }
233
234 @Test
235 public void testRunTask_whenTransportChangeFlagsAfterTaskCreation() throws Exception {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000236 TransportMock transportMock = setUpTransport(mTransport);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000237 AgentMock agentMock = setUpAgent(PACKAGE_1);
Bernardo Rufino228a6492018-02-10 13:08:52 +0000238 PerformBackupTask task =
239 createPerformBackupTask(
240 transportMock.transportClient,
241 mTransport.transportDirName,
242 emptyList(),
243 PACKAGE_1);
Robert Berry39194c02018-01-11 13:50:56 +0000244 int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
Bernardo Rufino228a6492018-02-10 13:08:52 +0000245 when(transportMock.transport.getTransportFlags()).thenReturn(flags);
Robert Berry39194c02018-01-11 13:50:56 +0000246
247 runTask(task);
248
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000249 verify(agentMock.agent)
250 .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
251 }
252
253 @Test
Bernardo Rufino228a6492018-02-10 13:08:52 +0000254 public void testRunTask_callsListenerAndObserver() throws Exception {
255 TransportMock transportMock = setUpTransport(mTransport);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000256 setUpAgent(PACKAGE_1);
Bernardo Rufino228a6492018-02-10 13:08:52 +0000257 PerformBackupTask task =
258 createPerformBackupTask(
259 transportMock.transportClient,
260 mTransport.transportDirName,
261 emptyList(),
262 PACKAGE_1);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000263
264 runTask(task);
265
266 verify(mListener).onFinished(any());
Bernardo Rufino228a6492018-02-10 13:08:52 +0000267 verify(mObserver).backupFinished(eq(BackupManager.SUCCESS));
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000268 }
269
270 @Test
Bernardo Rufino8553d272018-02-13 11:16:37 +0000271 public void testRunTask_releasesWakeLock() throws Exception {
272 TransportMock transportMock = setUpTransport(mTransport);
273 setUpAgent(PACKAGE_1);
274 PerformBackupTask task =
275 createPerformBackupTask(
276 transportMock.transportClient,
277 mTransport.transportDirName,
278 emptyList(),
279 PACKAGE_1);
280
281 runTask(task);
282
283 assertThat(mWakeLock.isHeld()).isFalse();
284 }
285
286 @Test
Bernardo Rufino228a6492018-02-10 13:08:52 +0000287 public void testRunTask_callsTransportPerformBackupWithAgentData() throws Exception {
288 TransportMock transportMock = setUpTransport(mTransport);
289 IBackupTransport transportBinder = transportMock.transport;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000290 AgentMock agentMock = setUpAgent(PACKAGE_1);
291 agentOnBackupDo(
292 agentMock.agent,
293 (oldState, dataOutput, newState) -> {
294 writeData(dataOutput, "key1", "foo".getBytes());
295 writeData(dataOutput, "key2", "bar".getBytes());
296 });
Bernardo Rufino228a6492018-02-10 13:08:52 +0000297 PerformBackupTask task =
298 createPerformBackupTask(
299 transportMock.transportClient,
300 mTransport.transportDirName,
301 emptyList(),
302 PACKAGE_1);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000303 // We need to verify at call time because the file is deleted right after
Bernardo Rufino228a6492018-02-10 13:08:52 +0000304 when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000305 .then(this::mockAndVerifyTransportPerformBackupData);
306
307 runTask(task);
308
309 // Already verified data in mockAndVerifyPerformBackupData
Bernardo Rufino228a6492018-02-10 13:08:52 +0000310 verify(transportBinder).performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000311 }
312
313 private int mockAndVerifyTransportPerformBackupData(InvocationOnMock invocation)
314 throws IOException {
315 ParcelFileDescriptor data = invocation.getArgument(1);
316
317 // Verifying that what we passed to the transport is what the agent wrote
318 BackupDataInput dataInput = new BackupDataInput(data.getFileDescriptor());
319
320 // "key1" => "foo"
321 assertThat(dataInput.readNextHeader()).isTrue();
322 assertThat(dataInput.getKey()).isEqualTo("key1");
323 int size1 = dataInput.getDataSize();
324 byte[] data1 = new byte[size1];
325 dataInput.readEntityData(data1, 0, size1);
326 assertThat(data1).isEqualTo("foo".getBytes());
327
328 // "key2" => "bar"
329 assertThat(dataInput.readNextHeader()).isTrue();
330 assertThat(dataInput.getKey()).isEqualTo("key2");
331 int size2 = dataInput.getDataSize();
332 byte[] data2 = new byte[size2];
333 dataInput.readEntityData(data2, 0, size2);
334 assertThat(data2).isEqualTo("bar".getBytes());
335
336 // No more
337 assertThat(dataInput.readNextHeader()).isFalse();
338
339 return BackupTransport.TRANSPORT_OK;
340 }
341
342 @Test
343 public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
344 throws Exception {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000345 TransportMock transportMock = setUpTransport(mTransport);
346 IBackupTransport transportBinder = transportMock.transport;
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000347 setUpAgent(PACKAGE_1);
Bernardo Rufino228a6492018-02-10 13:08:52 +0000348 PerformBackupTask task =
349 createPerformBackupTask(
350 transportMock.transportClient,
351 mTransport.transportDirName,
352 emptyList(),
353 PACKAGE_1);
354 when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000355 .thenReturn(BackupTransport.TRANSPORT_OK);
356
357 runTask(task);
358
Bernardo Rufino228a6492018-02-10 13:08:52 +0000359 verify(transportBinder).finishBackup();
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000360 }
361
362 @Test
363 public void testRunTask_whenProhibitedKey_failsAgent() throws Exception {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000364 TransportMock transportMock = setUpTransport(mTransport);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000365 AgentMock agentMock = setUpAgent(PACKAGE_1);
366 agentOnBackupDo(
367 agentMock.agent,
368 (oldState, dataOutput, newState) -> {
369 char prohibitedChar = 0xff00;
370 writeData(dataOutput, prohibitedChar + "key", "foo".getBytes());
371 });
Bernardo Rufino228a6492018-02-10 13:08:52 +0000372 PerformBackupTask task =
373 createPerformBackupTask(
374 transportMock.transportClient,
375 mTransport.transportDirName,
376 emptyList(),
377 PACKAGE_1);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000378
379 runTask(task);
380
Bernardo Rufino228a6492018-02-10 13:08:52 +0000381 // TODO: Should it not call mListener.onFinished()? PerformBackupTask:891 return?
382 // verify(mListener).onFinished(any());
383 verify(mObserver).onResult(eq(PACKAGE_1), eq(BackupManager.ERROR_AGENT_FAILURE));
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000384 verify(agentMock.agentBinder).fail(any());
Robert Berry39194c02018-01-11 13:50:56 +0000385 }
386
Bernardo Rufino228a6492018-02-10 13:08:52 +0000387 @Test
388 public void testRunTask_whenTransportUnavailable() throws Exception {
389 TransportMock transportMock = setUpTransport(mTransport.unavailable());
390 setUpAgent(PACKAGE_1);
391 PerformBackupTask task =
392 createPerformBackupTask(
393 transportMock.transportClient,
394 mTransport.transportDirName,
395 emptyList(),
396 PACKAGE_1);
397
398 runTask(task);
399
400 verify(mListener).onFinished(any());
401 // TODO: Should it be 2 times? (PBT.beginBackup() and PBT.finalizeBackup())
402 verify(mObserver, times(2)).backupFinished(eq(BackupManager.ERROR_TRANSPORT_ABORTED));
403 }
404
405 @Test
406 public void testRunTask_whenTransportRejectsPackage() throws Exception {
407 TransportMock transportMock = setUpTransport(mTransport);
408 setUpAgent(PACKAGE_1);
409 when(transportMock.transport.performBackup(
410 argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
411 .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
412 PerformBackupTask task =
413 createPerformBackupTask(
414 transportMock.transportClient,
415 mTransport.transportDirName,
416 emptyList(),
417 PACKAGE_1);
418
419 runTask(task);
420
421 verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
422 verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
423 }
424
425 @Test
426 public void testRunTask_whenTransportRejectsFirstPackageButLastSucceeds() throws Exception {
427 TransportMock transportMock = setUpTransport(mTransport);
428 IBackupTransport transportBinder = transportMock.transport;
429 setUpAgents(PACKAGE_1, PACKAGE_2);
430 when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
431 .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
432 when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
433 .thenReturn(BackupTransport.TRANSPORT_OK);
434 PerformBackupTask task =
435 createPerformBackupTask(
436 transportMock.transportClient,
437 mTransport.transportDirName,
438 emptyList(),
439 PACKAGE_1,
440 PACKAGE_2);
441
442 runTask(task);
443
444 verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
445 verify(mObserver).onResult(PACKAGE_2, BackupManager.SUCCESS);
446 verify(mObserver).backupFinished(BackupManager.SUCCESS);
447 }
448
449 @Test
450 public void testRunTask_whenTransportRejectsLastPackageButFirstSucceeds() throws Exception {
451 TransportMock transportMock = setUpTransport(mTransport);
452 IBackupTransport transportBinder = transportMock.transport;
453 setUpAgents(PACKAGE_1, PACKAGE_2);
454 when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
455 .thenReturn(BackupTransport.TRANSPORT_OK);
456 when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
457 .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
458 PerformBackupTask task =
459 createPerformBackupTask(
460 transportMock.transportClient,
461 mTransport.transportDirName,
462 emptyList(),
463 PACKAGE_1,
464 PACKAGE_2);
465
466 runTask(task);
467
468 verify(mObserver).onResult(PACKAGE_1, BackupManager.SUCCESS);
469 verify(mObserver).onResult(PACKAGE_2, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
470 // TODO: Should we return the status of the last?
471 verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
472 }
473
474 @Test
475 public void testRunTask_whenTransportReturnsQuotaExceeded() throws Exception {
476 TransportMock transportMock = setUpTransport(mTransport);
477 AgentMock agentMock = setUpAgent(PACKAGE_1);
478 when(transportMock.transport.performBackup(
479 argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
480 .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
481 PerformBackupTask task =
482 createPerformBackupTask(
483 transportMock.transportClient,
484 mTransport.transportDirName,
485 emptyList(),
486 PACKAGE_1);
487
488 runTask(task);
489
490 verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
491 verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
492 verify(agentMock.agent).onQuotaExceeded(anyLong(), anyLong());
493 }
494
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800495 @Test
Bernardo Rufino228a6492018-02-10 13:08:52 +0000496 public void testRunTask_whenAgentUnknown() throws Exception {
497 // Not calling setUpAgent()
498 TransportMock transportMock = setUpTransport(mTransport);
499 PerformBackupTask task =
500 createPerformBackupTask(
501 transportMock.transportClient,
502 mTransport.transportDirName,
503 emptyList(),
504 PACKAGE_1);
505
506 runTask(task);
507
508 verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
509 verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_PACKAGE_NOT_FOUND);
510 verify(mObserver).backupFinished(BackupManager.SUCCESS);
511 }
512
Robert Berry39194c02018-01-11 13:50:56 +0000513 private void runTask(PerformBackupTask task) {
514 Message message = mBackupHandler.obtainMessage(BackupHandler.MSG_BACKUP_RESTORE_STEP, task);
515 mBackupHandler.sendMessage(message);
516 while (mShadowBackupLooper.getScheduler().areAnyRunnable()) {
517 mShadowBackupLooper.runToEndOfTasks();
518 }
519 }
520
Bernardo Rufino228a6492018-02-10 13:08:52 +0000521 private TransportMock setUpTransport(TransportData transport) throws Exception {
522 TransportMock transportMock =
523 TransportTestUtils.setUpTransport(mTransportManager, transport);
524 File stateDir = new File(mBaseStateDir, transport.transportDirName);
525 assertThat(stateDir.mkdir()).isTrue();
526 return transportMock;
527 }
528
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000529 private List<AgentMock> setUpAgents(String... packageNames) {
Robert Berry39194c02018-01-11 13:50:56 +0000530 return Stream.of(packageNames).map(this::setUpAgent).collect(toList());
531 }
532
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000533 private AgentMock setUpAgent(String packageName) {
534 try {
535 PackageInfo packageInfo = new PackageInfo();
536 packageInfo.packageName = packageName;
537 packageInfo.applicationInfo = new ApplicationInfo();
538 packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_ALLOW_BACKUP;
539 packageInfo.applicationInfo.backupAgentName = "BackupAgent" + packageName;
540 packageInfo.applicationInfo.packageName = packageName;
541 mShadowPackageManager.setApplicationEnabledSetting(
542 packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
543 mShadowPackageManager.addPackage(packageInfo);
544 BackupAgent backupAgent = spy(BackupAgent.class);
545 IBackupAgent backupAgentBinder =
546 spy(IBackupAgent.Stub.asInterface(backupAgent.onBind()));
547 // Don't crash our only process (in production code this would crash the app, not us)
548 doNothing().when(backupAgentBinder).fail(any());
549 when(mBackupManagerService.bindToAgentSynchronous(
550 eq(packageInfo.applicationInfo), anyInt()))
551 .thenReturn(backupAgentBinder);
552 return new AgentMock(backupAgentBinder, backupAgent);
553 } catch (RemoteException e) {
554 // Never happens, compiler happy
555 throw new AssertionError(e);
556 }
Robert Berry39194c02018-01-11 13:50:56 +0000557 }
558
559 private PerformBackupTask createPerformBackupTask(
Bernardo Rufino228a6492018-02-10 13:08:52 +0000560 TransportClient transportClient,
561 String transportDirName,
Robert Berry39194c02018-01-11 13:50:56 +0000562 List<String> pendingFullBackups,
Robert Berry39194c02018-01-11 13:50:56 +0000563 String... packages) {
564 ArrayList<BackupRequest> backupRequests =
565 Stream.of(packages).map(BackupRequest::new).collect(toCollection(ArrayList::new));
566 mWakeLock.acquire();
567 PerformBackupTask task =
568 new PerformBackupTask(
569 mBackupManagerService,
Bernardo Rufino228a6492018-02-10 13:08:52 +0000570 transportClient,
571 transportDirName,
Robert Berry39194c02018-01-11 13:50:56 +0000572 backupRequests,
573 mDataChangedJournal,
574 mObserver,
575 mMonitor,
576 mListener,
577 pendingFullBackups,
Bernardo Rufino228a6492018-02-10 13:08:52 +0000578 /* userInitiated */ false,
579 /* nonIncremental */ true);
Robert Berry39194c02018-01-11 13:50:56 +0000580 mBackupManager.setUp(mBackupHandler, task);
581 return task;
582 }
583
Bernardo Rufinocea93532018-02-28 11:05:18 +0000584 /** Matches {@link PackageInfo} whose package name is {@code packageName}. */
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000585 private static ArgumentMatcher<PackageInfo> packageInfo(String packageName) {
Bernardo Rufino228a6492018-02-10 13:08:52 +0000586 // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat().
587 // E.g. if you do:
588 //
589 // 1. when(object.method(argThat(str -> str.equals("foo")))).thenReturn(0)
590 // 2. when(object.method(argThat(str -> str.equals("bar")))).thenReturn(2)
591 //
592 // The second line will throw NPE because it will call lambda 1 with null, since argThat()
593 // returns null. So we guard against that by checking for null.
594 return packageInfo -> packageInfo != null && packageName.equals(packageInfo.packageName);
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000595 }
596
597 private static ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
Robert Berry39194c02018-01-11 13:50:56 +0000598 return dataOutput -> dataOutput.getTransportFlags() == flags;
599 }
600
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000601 private static void writeData(BackupDataOutput dataOutput, String key, byte[] data)
602 throws IOException {
603 dataOutput.writeEntityHeader(key, data.length);
604 dataOutput.writeEntityData(data, data.length);
605 }
606
607 private static void agentOnBackupDo(BackupAgent agent, BackupAgentOnBackup function)
608 throws Exception {
609 doAnswer(function).when(agent).onBackup(any(), any(), any());
610 }
611
612 @FunctionalInterface
613 private interface BackupAgentOnBackup extends Answer<Void> {
614 void onBackup(
615 ParcelFileDescriptor oldState,
616 BackupDataOutput dataOutput,
617 ParcelFileDescriptor newState)
618 throws IOException;
619
620 @Override
621 default Void answer(InvocationOnMock invocation) throws Throwable {
622 onBackup(
623 invocation.getArgument(0),
624 invocation.getArgument(1),
625 invocation.getArgument(2));
626 return null;
627 }
628 }
629
630 private static class AgentMock {
631 private final IBackupAgent agentBinder;
632 private final BackupAgent agent;
633
Bernardo Rufino228a6492018-02-10 13:08:52 +0000634 private AgentMock(IBackupAgent agentBinder, BackupAgent agent) {
Bernardo Rufinob97ea7e2018-02-08 15:26:15 +0000635 this.agentBinder = agentBinder;
636 this.agent = agent;
637 }
638 }
639
Robert Berry39194c02018-01-11 13:50:56 +0000640 private abstract static class FakeIBackupManager extends IBackupManager.Stub {
641 private Handler mBackupHandler;
642 private BackupRestoreTask mTask;
643
644 public FakeIBackupManager() {}
645
646 private void setUp(Handler backupHandler, BackupRestoreTask task) {
647 mBackupHandler = backupHandler;
648 mTask = task;
649 }
650
651 @Override
652 public void opComplete(int token, long result) throws RemoteException {
653 assertThat(mTask).isNotNull();
654 Message message =
655 mBackupHandler.obtainMessage(
656 BackupHandler.MSG_OP_COMPLETE, Pair.create(mTask, result));
657 mBackupHandler.sendMessage(message);
658 }
659 }
660}