blob: 3668350c6616def623915190306dc1dbcf433330 [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
19import static com.android.server.backup.testing.TransportData.backupTransport;
20import static com.android.server.backup.testing.TransportTestUtils.setUpTransport;
21
22import static com.google.common.truth.Truth.assertThat;
23
24import static org.junit.Assert.fail;
25import static org.mockito.ArgumentMatchers.any;
26import static org.mockito.ArgumentMatchers.anyInt;
27import static org.mockito.ArgumentMatchers.argThat;
28import static org.mockito.ArgumentMatchers.eq;
29import static org.mockito.Mockito.mock;
30import static org.mockito.Mockito.spy;
31import static org.mockito.Mockito.verify;
32import static org.mockito.Mockito.when;
33import static org.robolectric.Shadows.shadowOf;
34
35import static java.util.Collections.emptyList;
36import static java.util.stream.Collectors.toCollection;
37import static java.util.stream.Collectors.toList;
38
39import android.app.Application;
40import android.app.IActivityManager;
41import android.app.IBackupAgent;
42import android.app.backup.BackupAgent;
43import android.app.backup.BackupDataOutput;
44import android.app.backup.FullBackupDataOutput;
45import android.app.backup.IBackupManager;
46import android.app.backup.IBackupManagerMonitor;
47import android.app.backup.IBackupObserver;
48import android.content.Context;
49import android.content.pm.ApplicationInfo;
50import android.content.pm.PackageInfo;
51import android.content.pm.PackageManager;
52import android.os.Handler;
53import android.os.HandlerThread;
54import android.os.Looper;
55import android.os.Message;
56import android.os.PowerManager;
57import android.os.RemoteException;
58import android.platform.test.annotations.Presubmit;
59import android.util.Pair;
60import android.util.SparseArray;
61
62import com.android.internal.backup.IBackupTransport;
63import com.android.server.backup.internal.BackupHandler;
64import com.android.server.backup.internal.BackupRequest;
65import com.android.server.backup.internal.OnTaskFinishedListener;
66import com.android.server.backup.internal.PerformBackupTask;
67import com.android.server.backup.testing.TransportData;
68import com.android.server.backup.testing.TransportTestUtils.TransportMock;
69import com.android.server.backup.transport.TransportClient;
70import com.android.server.testing.FrameworkRobolectricTestRunner;
71import com.android.server.testing.SystemLoaderClasses;
72import com.android.server.testing.shadows.FrameworkShadowPackageManager;
73import com.android.server.testing.shadows.ShadowBackupDataInput;
74import com.android.server.testing.shadows.ShadowBackupDataOutput;
75
76import org.junit.Before;
77import org.junit.Test;
78import org.junit.runner.RunWith;
79import org.mockito.ArgumentMatcher;
80import org.mockito.Mock;
81import org.mockito.MockitoAnnotations;
82import org.robolectric.RuntimeEnvironment;
83import org.robolectric.annotation.Config;
84import org.robolectric.shadow.api.Shadow;
85import org.robolectric.shadows.ShadowLooper;
86import org.robolectric.shadows.ShadowPackageManager;
87import org.robolectric.shadows.ShadowQueuedWork;
88
89import java.io.File;
90import java.util.ArrayList;
91import java.util.List;
92import java.util.stream.Stream;
93
94@RunWith(FrameworkRobolectricTestRunner.class)
95@Config(
96 manifest = Config.NONE,
97 sdk = 26,
98 shadows = {
99 FrameworkShadowPackageManager.class,
100 ShadowBackupDataInput.class,
101 ShadowBackupDataOutput.class,
102 ShadowQueuedWork.class
103 }
104)
105@SystemLoaderClasses({
106 PerformBackupTask.class,
107 BackupDataOutput.class,
108 FullBackupDataOutput.class,
109 TransportManager.class,
110 BackupAgent.class,
111 IBackupTransport.class,
112 IBackupAgent.class,
113 PackageInfo.class
114})
115@Presubmit
116public class PerformBackupTaskTest {
117 private static final String PACKAGE_1 = "com.example.package1";
118 private static final String PACKAGE_2 = "com.example.package2";
119
120 @Mock private RefactoredBackupManagerService mBackupManagerService;
121 @Mock private TransportManager mTransportManager;
122 @Mock private DataChangedJournal mDataChangedJournal;
123 @Mock private IBackupObserver mObserver;
124 @Mock private IBackupManagerMonitor mMonitor;
125 @Mock private OnTaskFinishedListener mListener;
126 private TransportData mTransport;
127 private IBackupTransport mTransportBinder;
128 private TransportClient mTransportClient;
129 private ShadowLooper mShadowBackupLooper;
130 private BackupHandler mBackupHandler;
131 private PowerManager.WakeLock mWakeLock;
132 private ShadowPackageManager mShadowPackageManager;
133 private FakeIBackupManager mBackupManager;
134
135 @Before
136 public void setUp() throws Exception {
137 MockitoAnnotations.initMocks(this);
138
139 mTransport = backupTransport();
140 TransportMock transportMock = setUpTransport(mTransportManager, mTransport);
141 mTransportBinder = transportMock.transport;
142 mTransportClient = transportMock.transportClient;
143
144 Application application = RuntimeEnvironment.application;
145 File cacheDir = application.getCacheDir();
146 File baseStateDir = new File(cacheDir, "base_state_dir");
147 File dataDir = new File(cacheDir, "data_dir");
148 File stateDir = new File(baseStateDir, mTransport.transportDirName);
149 assertThat(baseStateDir.mkdir()).isTrue();
150 assertThat(dataDir.mkdir()).isTrue();
151 assertThat(stateDir.mkdir()).isTrue();
152
153 PackageManager packageManager = application.getPackageManager();
154 mShadowPackageManager = Shadow.extract(packageManager);
155
156 PowerManager powerManager =
157 (PowerManager) application.getSystemService(Context.POWER_SERVICE);
158 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
159
160 // Robolectric simulates multi-thread in a single-thread to avoid flakiness
161 HandlerThread backupThread = new HandlerThread("backup");
162 backupThread.setUncaughtExceptionHandler(
163 (t, e) -> fail("Uncaught exception " + e.getMessage()));
164 backupThread.start();
165 Looper backupLooper = backupThread.getLooper();
166 mShadowBackupLooper = shadowOf(backupLooper);
167 mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper);
168
169 mBackupManager = spy(FakeIBackupManager.class);
170
171 when(mBackupManagerService.getTransportManager()).thenReturn(mTransportManager);
172 when(mBackupManagerService.getContext()).thenReturn(application);
173 when(mBackupManagerService.getPackageManager()).thenReturn(packageManager);
174 when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock);
175 when(mBackupManagerService.getCurrentOpLock()).thenReturn(new Object());
176 when(mBackupManagerService.getQueueLock()).thenReturn(new Object());
177 when(mBackupManagerService.getBaseStateDir()).thenReturn(baseStateDir);
178 when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
179 when(mBackupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
180 when(mBackupManagerService.getBackupHandler()).thenReturn(mBackupHandler);
181 when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
182 when(mBackupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class));
183 }
184
185 @Test
186 public void testRunTask_whenTransportProvidesFlags_passesThemToTheAgent() throws Exception {
187 BackupAgent agent = setUpAgent(PACKAGE_1);
188 int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
189 when(mTransportBinder.getTransportFlags()).thenReturn(flags);
190 PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
191
192 runTask(task);
193
194 verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
195 }
196
197 @Test
198 public void testRunTask_whenTransportDoesNotProvidesFlags() throws Exception {
199 BackupAgent agent = setUpAgent(PACKAGE_1);
200 PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
201
202 runTask(task);
203
204 verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
205 }
206
207 @Test
208 public void testRunTask_whenTransportProvidesFlagsAndMultipleAgents_passesToAll()
209 throws Exception {
210 List<BackupAgent> agents = setUpAgents(PACKAGE_1, PACKAGE_2);
211 BackupAgent agent1 = agents.get(0);
212 BackupAgent agent2 = agents.get(1);
213 int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
214 when(mTransportBinder.getTransportFlags()).thenReturn(flags);
215 PerformBackupTask task =
216 createPerformBackupTask(emptyList(), false, true, PACKAGE_1, PACKAGE_2);
217
218 runTask(task);
219
220 verify(agent1).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
221 verify(agent2).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
222 }
223
224 @Test
225 public void testRunTask_whenTransportChangeFlagsAfterTaskCreation() throws Exception {
226 BackupAgent agent = setUpAgent(PACKAGE_1);
227 PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
228 int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
229 when(mTransportBinder.getTransportFlags()).thenReturn(flags);
230
231 runTask(task);
232
233 verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
234 }
235
236 private void runTask(PerformBackupTask task) {
237 Message message = mBackupHandler.obtainMessage(BackupHandler.MSG_BACKUP_RESTORE_STEP, task);
238 mBackupHandler.sendMessage(message);
239 while (mShadowBackupLooper.getScheduler().areAnyRunnable()) {
240 mShadowBackupLooper.runToEndOfTasks();
241 }
242 }
243
244 private List<BackupAgent> setUpAgents(String... packageNames) {
245 return Stream.of(packageNames).map(this::setUpAgent).collect(toList());
246 }
247
248 private BackupAgent setUpAgent(String packageName) {
249 PackageInfo packageInfo = new PackageInfo();
250 packageInfo.packageName = packageName;
251 packageInfo.applicationInfo = new ApplicationInfo();
252 packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_ALLOW_BACKUP;
253 packageInfo.applicationInfo.backupAgentName = "BackupAgent" + packageName;
254 packageInfo.applicationInfo.packageName = packageName;
255 mShadowPackageManager.setApplicationEnabledSetting(
256 packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
257 mShadowPackageManager.addPackage(packageInfo);
258 BackupAgent backupAgent = spy(BackupAgent.class);
259 IBackupAgent backupAgentBinder = IBackupAgent.Stub.asInterface(backupAgent.onBind());
260 when(mBackupManagerService.bindToAgentSynchronous(
261 eq(packageInfo.applicationInfo), anyInt()))
262 .thenReturn(backupAgentBinder);
263 return backupAgent;
264 }
265
266 private PerformBackupTask createPerformBackupTask(
267 List<String> pendingFullBackups,
268 boolean userInitiated,
269 boolean nonIncremental,
270 String... packages) {
271 ArrayList<BackupRequest> backupRequests =
272 Stream.of(packages).map(BackupRequest::new).collect(toCollection(ArrayList::new));
273 mWakeLock.acquire();
274 PerformBackupTask task =
275 new PerformBackupTask(
276 mBackupManagerService,
277 mTransportClient,
278 mTransport.transportDirName,
279 backupRequests,
280 mDataChangedJournal,
281 mObserver,
282 mMonitor,
283 mListener,
284 pendingFullBackups,
285 userInitiated,
286 nonIncremental);
287 mBackupManager.setUp(mBackupHandler, task);
288 return task;
289 }
290
291 private ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
292 return dataOutput -> dataOutput.getTransportFlags() == flags;
293 }
294
295 private abstract static class FakeIBackupManager extends IBackupManager.Stub {
296 private Handler mBackupHandler;
297 private BackupRestoreTask mTask;
298
299 public FakeIBackupManager() {}
300
301 private void setUp(Handler backupHandler, BackupRestoreTask task) {
302 mBackupHandler = backupHandler;
303 mTask = task;
304 }
305
306 @Override
307 public void opComplete(int token, long result) throws RemoteException {
308 assertThat(mTask).isNotNull();
309 Message message =
310 mBackupHandler.obtainMessage(
311 BackupHandler.MSG_OP_COMPLETE, Pair.create(mTask, result));
312 mBackupHandler.sendMessage(message);
313 }
314 }
315}