blob: d848b2dc75fe38f020b1f85c16dae0e788b7a01f [file] [log] [blame]
Narayan Kamathc034fe92019-01-23 10:48:17 +00001/*
2 * Copyright (C) 2019 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.rollback;
18
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNull;
22import static org.junit.Assert.assertTrue;
Narayan Kamathc034fe92019-01-23 10:48:17 +000023import static org.mockito.ArgumentMatchers.eq;
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000024import static org.mockito.Matchers.anyInt;
25import static org.mockito.Matchers.anyString;
Narayan Kamathc034fe92019-01-23 10:48:17 +000026import static org.mockito.Mockito.doReturn;
27import static org.mockito.Mockito.mock;
28import static org.mockito.Mockito.spy;
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000029import static org.mockito.Mockito.when;
Narayan Kamathc034fe92019-01-23 10:48:17 +000030
31import android.content.pm.VersionedPackage;
32import android.content.rollback.PackageRollbackInfo;
33import android.content.rollback.PackageRollbackInfo.RestoreInfo;
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000034import android.content.rollback.RollbackInfo;
Narayan Kamathc034fe92019-01-23 10:48:17 +000035import android.util.IntArray;
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000036import android.util.SparseLongArray;
Narayan Kamathc034fe92019-01-23 10:48:17 +000037
38import com.android.server.pm.Installer;
39
40import org.junit.Test;
41import org.junit.runner.RunWith;
42import org.junit.runners.JUnit4;
43import org.mockito.InOrder;
44import org.mockito.Mockito;
45
46import java.io.File;
47import java.util.ArrayList;
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000048import java.util.Arrays;
49import java.util.Collections;
50import java.util.List;
Narayan Kamathc034fe92019-01-23 10:48:17 +000051
52@RunWith(JUnit4.class)
53public class AppDataRollbackHelperTest {
54
55 @Test
56 public void testSnapshotAppData() throws Exception {
57 Installer installer = mock(Installer.class);
58 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
59
60 // All users are unlocked so we should snapshot data for them.
61 doReturn(true).when(helper).isUserCredentialLocked(eq(10));
62 doReturn(true).when(helper).isUserCredentialLocked(eq(11));
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000063 PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
64 helper.snapshotAppData(5, info);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000065
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000066 assertEquals(2, info.getPendingBackups().size());
67 assertEquals(10, info.getPendingBackups().get(0));
68 assertEquals(11, info.getPendingBackups().get(1));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000069
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000070 assertEquals(0, info.getCeSnapshotInodes().size());
Narayan Kamathc034fe92019-01-23 10:48:17 +000071
72 InOrder inOrder = Mockito.inOrder(installer);
73 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000074 eq("com.foo.bar"), eq(10), eq(5), eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +000075 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000076 eq("com.foo.bar"), eq(11), eq(5), eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +000077 inOrder.verifyNoMoreInteractions();
78
79 // One of the users is unlocked but the other isn't
80 doReturn(false).when(helper).isUserCredentialLocked(eq(10));
81 doReturn(true).when(helper).isUserCredentialLocked(eq(11));
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000082 when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L);
Narayan Kamathc034fe92019-01-23 10:48:17 +000083
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000084 PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
85 helper.snapshotAppData(7, info2);
86 assertEquals(1, info2.getPendingBackups().size());
87 assertEquals(11, info2.getPendingBackups().get(0));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000088
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000089 assertEquals(1, info2.getCeSnapshotInodes().size());
90 assertEquals(239L, info2.getCeSnapshotInodes().get(10));
Narayan Kamathc034fe92019-01-23 10:48:17 +000091
92 inOrder = Mockito.inOrder(installer);
93 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000094 eq("com.foo.bar"), eq(10), eq(7),
Narayan Kamathc034fe92019-01-23 10:48:17 +000095 eq(Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE));
96 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000097 eq("com.foo.bar"), eq(11), eq(7), eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +000098 inOrder.verifyNoMoreInteractions();
99 }
100
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000101 private static PackageRollbackInfo createPackageRollbackInfo(String packageName,
102 final int[] installedUsers) {
103 return new PackageRollbackInfo(
104 new VersionedPackage(packageName, 2), new VersionedPackage(packageName, 1),
105 new IntArray(), new ArrayList<>(), false, IntArray.wrap(installedUsers),
106 new SparseLongArray());
Narayan Kamathc034fe92019-01-23 10:48:17 +0000107 }
108
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000109 private static PackageRollbackInfo createPackageRollbackInfo(String packageName) {
110 return createPackageRollbackInfo(packageName, new int[] {});
Narayan Kamathc034fe92019-01-23 10:48:17 +0000111 }
112
113 @Test
114 public void testRestoreAppDataSnapshot_pendingBackupForUser() throws Exception {
115 Installer installer = mock(Installer.class);
116 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
117
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000118 PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
119 IntArray pendingBackups = info.getPendingBackups();
Narayan Kamathc034fe92019-01-23 10:48:17 +0000120 pendingBackups.add(10);
121 pendingBackups.add(11);
122
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000123 assertTrue(helper.restoreAppData(13 /* rollbackId */, info, 10 /* userId */, 1 /* appId */,
124 "seinfo"));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000125
126 // Should only require FLAG_STORAGE_DE here because we have a pending backup that we
127 // didn't manage to execute.
128 InOrder inOrder = Mockito.inOrder(installer);
129 inOrder.verify(installer).restoreAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000130 eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
131 eq(13) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000132 inOrder.verifyNoMoreInteractions();
133
134 assertEquals(1, pendingBackups.size());
135 assertEquals(11, pendingBackups.get(0));
136 }
137
138 @Test
139 public void testRestoreAppDataSnapshot_availableBackupForLockedUser() throws Exception {
140 Installer installer = mock(Installer.class);
141 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
142 doReturn(true).when(helper).isUserCredentialLocked(eq(10));
143
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000144 PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
Narayan Kamathc034fe92019-01-23 10:48:17 +0000145
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000146 assertTrue(helper.restoreAppData(73 /* rollbackId */, info, 10 /* userId */, 1 /* appId */,
147 "seinfo"));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000148
149 InOrder inOrder = Mockito.inOrder(installer);
150 inOrder.verify(installer).restoreAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000151 eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
152 eq(73) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000153 inOrder.verifyNoMoreInteractions();
154
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000155 ArrayList<RestoreInfo> pendingRestores = info.getPendingRestores();
Narayan Kamathc034fe92019-01-23 10:48:17 +0000156 assertEquals(1, pendingRestores.size());
157 assertEquals(10, pendingRestores.get(0).userId);
158 assertEquals(1, pendingRestores.get(0).appId);
159 assertEquals("seinfo", pendingRestores.get(0).seInfo);
160 }
161
162 @Test
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000163 public void testRestoreAppDataSnapshot_availableBackupForUnlockedUser() throws Exception {
Narayan Kamathc034fe92019-01-23 10:48:17 +0000164 Installer installer = mock(Installer.class);
165 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
166 doReturn(false).when(helper).isUserCredentialLocked(eq(10));
167
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000168 PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
169 assertFalse(helper.restoreAppData(101 /* rollbackId */, info, 10 /* userId */,
170 1 /* appId */, "seinfo"));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000171
172 InOrder inOrder = Mockito.inOrder(installer);
173 inOrder.verify(installer).restoreAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000174 eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
175 eq(101) /* rollbackId */,
Narayan Kamathc034fe92019-01-23 10:48:17 +0000176 eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
177 inOrder.verifyNoMoreInteractions();
178
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000179 ArrayList<RestoreInfo> pendingRestores = info.getPendingRestores();
Narayan Kamathc034fe92019-01-23 10:48:17 +0000180 assertEquals(0, pendingRestores.size());
181 }
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000182
183 @Test
184 public void destroyAppData() throws Exception {
185 Installer installer = mock(Installer.class);
186 AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000187
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000188 PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
189 info.putCeSnapshotInode(11, 239L);
190 helper.destroyAppDataSnapshot(5 /* rollbackId */, info, 10 /* userId */);
191 helper.destroyAppDataSnapshot(5 /* rollbackId */, info, 11 /* userId */);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000192
193 InOrder inOrder = Mockito.inOrder(installer);
194 inOrder.verify(installer).destroyAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000195 eq("com.foo.bar"), eq(10) /* userId */, eq(0L) /* ceSnapshotInode */,
196 eq(5) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000197 inOrder.verify(installer).destroyAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000198 eq("com.foo.bar"), eq(11) /* userId */, eq(239L) /* ceSnapshotInode */,
199 eq(5) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000200 inOrder.verifyNoMoreInteractions();
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000201
202 assertEquals(0, info.getCeSnapshotInodes().size());
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000203 }
204
205 @Test
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000206 public void commitPendingBackupAndRestoreForUser() throws Exception {
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000207 Installer installer = mock(Installer.class);
208 AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
209
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000210 when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(53L);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000211
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000212 // This one should be backed up.
213 PackageRollbackInfo pendingBackup = createPackageRollbackInfo("com.foo", new int[]{37, 73});
214 pendingBackup.addPendingBackup(37);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000215
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000216 // Nothing should be done for this one.
217 PackageRollbackInfo wasRecentlyRestored = createPackageRollbackInfo("com.bar",
218 new int[]{37, 73});
219 wasRecentlyRestored.addPendingBackup(37);
220 wasRecentlyRestored.getPendingRestores().add(
221 new RestoreInfo(37 /* userId */, 239 /* appId*/, "seInfo"));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000222
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000223 // This one should be restored
224 PackageRollbackInfo pendingRestore = createPackageRollbackInfo("com.abc",
225 new int[]{37, 73});
226 pendingRestore.putCeSnapshotInode(37, 1543L);
227 pendingRestore.getPendingRestores().add(
228 new RestoreInfo(37 /* userId */, 57 /* appId*/, "seInfo"));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000229
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000230 // This one shouldn't be processed, because it hasn't pending backups/restores for userId
231 // 37.
232 PackageRollbackInfo ignoredInfo = createPackageRollbackInfo("com.bar",
233 new int[]{3, 73});
234 wasRecentlyRestored.addPendingBackup(3);
235 wasRecentlyRestored.addPendingBackup(73);
236 wasRecentlyRestored.getPendingRestores().add(
237 new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo"));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000238
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000239 RollbackData dataWithPendingBackup = new RollbackData(101, new File("/does/not/exist"), -1,
240 true);
241 dataWithPendingBackup.packages.add(pendingBackup);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000242
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000243 RollbackData dataWithRecentRestore = new RollbackData(17239, new File("/does/not/exist"),
244 -1, true);
245 dataWithRecentRestore.packages.add(wasRecentlyRestored);
246
247 RollbackData dataForDifferentUser = new RollbackData(17239, new File("/does/not/exist"),
248 -1, true);
249 dataForDifferentUser.packages.add(ignoredInfo);
250
251 RollbackInfo rollbackInfo = new RollbackInfo(17239,
252 Arrays.asList(pendingRestore, wasRecentlyRestored), false);
253
254 List<RollbackData> changed = helper.commitPendingBackupAndRestoreForUser(37,
255 Arrays.asList(dataWithPendingBackup, dataWithRecentRestore, dataForDifferentUser),
256 Collections.singletonList(rollbackInfo));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000257 InOrder inOrder = Mockito.inOrder(installer);
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000258
259 // Check that pending backup and restore for the same package mutually destroyed each other.
260 assertEquals(-1, wasRecentlyRestored.getPendingBackups().indexOf(37));
261 assertNull(wasRecentlyRestored.getRestoreInfo(37));
262
263 // Check that backup was performed.
264 inOrder.verify(installer).snapshotAppData(eq("com.foo"), eq(37), eq(101),
265 eq(Installer.FLAG_STORAGE_CE));
266 assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37));
267 assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37));
268
269 // Check that changed returns correct RollbackData.
270 assertEquals(2, changed.size());
271 assertEquals(dataWithPendingBackup, changed.get(0));
272 assertEquals(dataWithRecentRestore, changed.get(1));
273
274 // Check that restore was performed.
275 inOrder.verify(installer).restoreAppDataSnapshot(
276 eq("com.abc"), eq(57) /* appId */, eq("seInfo"), eq(37) /* userId */,
277 eq(17239) /* rollbackId */, eq(Installer.FLAG_STORAGE_CE));
278 assertNull(pendingRestore.getRestoreInfo(37));
279
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000280 inOrder.verifyNoMoreInteractions();
281 }
Narayan Kamathc034fe92019-01-23 10:48:17 +0000282}