blob: 3ceaac207680793a7ac7d5871c510903609f8f85 [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;
Oli Lan7bbd8b42020-01-14 10:11:42 +000030import static org.mockito.MockitoAnnotations.initMocks;
Narayan Kamathc034fe92019-01-23 10:48:17 +000031
32import android.content.pm.VersionedPackage;
33import android.content.rollback.PackageRollbackInfo;
34import android.content.rollback.PackageRollbackInfo.RestoreInfo;
35import android.util.IntArray;
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000036import android.util.SparseLongArray;
Narayan Kamathc034fe92019-01-23 10:48:17 +000037
Oli Lan7bbd8b42020-01-14 10:11:42 +000038import com.android.server.pm.ApexManager;
Narayan Kamathc034fe92019-01-23 10:48:17 +000039import com.android.server.pm.Installer;
40
Oli Lan7bbd8b42020-01-14 10:11:42 +000041import org.junit.Before;
Narayan Kamathc034fe92019-01-23 10:48:17 +000042import org.junit.Test;
43import org.junit.runner.RunWith;
44import org.junit.runners.JUnit4;
45import org.mockito.InOrder;
Oli Lan7bbd8b42020-01-14 10:11:42 +000046import org.mockito.Mock;
Narayan Kamathc034fe92019-01-23 10:48:17 +000047import org.mockito.Mockito;
48
49import java.io.File;
50import java.util.ArrayList;
51
52@RunWith(JUnit4.class)
53public class AppDataRollbackHelperTest {
54
Oli Lan7bbd8b42020-01-14 10:11:42 +000055 @Mock private ApexManager mApexManager;
56
57 @Before
58 public void setUp() {
59 initMocks(this);
60 }
61
Narayan Kamathc034fe92019-01-23 10:48:17 +000062 @Test
63 public void testSnapshotAppData() throws Exception {
64 Installer installer = mock(Installer.class);
Oli Lan7bbd8b42020-01-14 10:11:42 +000065 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager));
Narayan Kamathc034fe92019-01-23 10:48:17 +000066
67 // All users are unlocked so we should snapshot data for them.
68 doReturn(true).when(helper).isUserCredentialLocked(eq(10));
69 doReturn(true).when(helper).isUserCredentialLocked(eq(11));
Oli Lan48f3cf42019-08-09 10:25:49 +010070 PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
71 helper.snapshotAppData(5, info, new int[]{10, 11});
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000072
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000073 assertEquals(2, info.getPendingBackups().size());
74 assertEquals(10, info.getPendingBackups().get(0));
75 assertEquals(11, info.getPendingBackups().get(1));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000076
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000077 assertEquals(0, info.getCeSnapshotInodes().size());
Narayan Kamathc034fe92019-01-23 10:48:17 +000078
79 InOrder inOrder = Mockito.inOrder(installer);
80 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000081 eq("com.foo.bar"), eq(10), eq(5), eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +000082 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000083 eq("com.foo.bar"), eq(11), eq(5), eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +000084 inOrder.verifyNoMoreInteractions();
85
86 // One of the users is unlocked but the other isn't
87 doReturn(false).when(helper).isUserCredentialLocked(eq(10));
88 doReturn(true).when(helper).isUserCredentialLocked(eq(11));
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000089 when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L);
Narayan Kamathc034fe92019-01-23 10:48:17 +000090
Oli Lan48f3cf42019-08-09 10:25:49 +010091 PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar");
92 helper.snapshotAppData(7, info2, new int[]{10, 11});
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000093 assertEquals(1, info2.getPendingBackups().size());
94 assertEquals(11, info2.getPendingBackups().get(0));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +000095
Nikita Ioffe5dcd17972019-02-04 11:08:13 +000096 assertEquals(1, info2.getCeSnapshotInodes().size());
97 assertEquals(239L, info2.getCeSnapshotInodes().get(10));
Narayan Kamathc034fe92019-01-23 10:48:17 +000098
99 inOrder = Mockito.inOrder(installer);
100 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000101 eq("com.foo.bar"), eq(10), eq(7),
Narayan Kamathc034fe92019-01-23 10:48:17 +0000102 eq(Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE));
103 inOrder.verify(installer).snapshotAppData(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000104 eq("com.foo.bar"), eq(11), eq(7), eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000105 inOrder.verifyNoMoreInteractions();
106 }
107
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000108 private static PackageRollbackInfo createPackageRollbackInfo(String packageName,
109 final int[] installedUsers) {
110 return new PackageRollbackInfo(
111 new VersionedPackage(packageName, 2), new VersionedPackage(packageName, 1),
Mohammad Samiul Islam3fcecfc2019-12-20 17:46:01 +0000112 new IntArray(), new ArrayList<>(), false, false, IntArray.wrap(installedUsers),
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000113 new SparseLongArray());
Narayan Kamathc034fe92019-01-23 10:48:17 +0000114 }
115
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000116 private static PackageRollbackInfo createPackageRollbackInfo(String packageName) {
117 return createPackageRollbackInfo(packageName, new int[] {});
Narayan Kamathc034fe92019-01-23 10:48:17 +0000118 }
119
Gavin Corkery0987cb02019-10-07 10:46:55 +0100120 private static Rollback createRollbackForId(int rollbackId) {
121 return new Rollback(rollbackId, new File("/does/not/exist"), -1,
122 0, "com.xyz");
123 }
124
Narayan Kamathc034fe92019-01-23 10:48:17 +0000125 @Test
126 public void testRestoreAppDataSnapshot_pendingBackupForUser() throws Exception {
127 Installer installer = mock(Installer.class);
Oli Lan7bbd8b42020-01-14 10:11:42 +0000128 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000129
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000130 PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
131 IntArray pendingBackups = info.getPendingBackups();
Narayan Kamathc034fe92019-01-23 10:48:17 +0000132 pendingBackups.add(10);
133 pendingBackups.add(11);
134
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000135 assertTrue(helper.restoreAppData(13 /* rollbackId */, info, 10 /* userId */, 1 /* appId */,
136 "seinfo"));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000137
138 // Should only require FLAG_STORAGE_DE here because we have a pending backup that we
139 // didn't manage to execute.
140 InOrder inOrder = Mockito.inOrder(installer);
141 inOrder.verify(installer).restoreAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000142 eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
143 eq(13) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000144 inOrder.verifyNoMoreInteractions();
145
146 assertEquals(1, pendingBackups.size());
147 assertEquals(11, pendingBackups.get(0));
148 }
149
150 @Test
151 public void testRestoreAppDataSnapshot_availableBackupForLockedUser() throws Exception {
152 Installer installer = mock(Installer.class);
Oli Lan7bbd8b42020-01-14 10:11:42 +0000153 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000154 doReturn(true).when(helper).isUserCredentialLocked(eq(10));
155
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000156 PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
Narayan Kamathc034fe92019-01-23 10:48:17 +0000157
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000158 assertTrue(helper.restoreAppData(73 /* rollbackId */, info, 10 /* userId */, 1 /* appId */,
159 "seinfo"));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000160
161 InOrder inOrder = Mockito.inOrder(installer);
162 inOrder.verify(installer).restoreAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000163 eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
164 eq(73) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000165 inOrder.verifyNoMoreInteractions();
166
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000167 ArrayList<RestoreInfo> pendingRestores = info.getPendingRestores();
Narayan Kamathc034fe92019-01-23 10:48:17 +0000168 assertEquals(1, pendingRestores.size());
169 assertEquals(10, pendingRestores.get(0).userId);
170 assertEquals(1, pendingRestores.get(0).appId);
171 assertEquals("seinfo", pendingRestores.get(0).seInfo);
172 }
173
174 @Test
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000175 public void testRestoreAppDataSnapshot_availableBackupForUnlockedUser() throws Exception {
Narayan Kamathc034fe92019-01-23 10:48:17 +0000176 Installer installer = mock(Installer.class);
Oli Lan7bbd8b42020-01-14 10:11:42 +0000177 AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000178 doReturn(false).when(helper).isUserCredentialLocked(eq(10));
179
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000180 PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
181 assertFalse(helper.restoreAppData(101 /* rollbackId */, info, 10 /* userId */,
182 1 /* appId */, "seinfo"));
Narayan Kamathc034fe92019-01-23 10:48:17 +0000183
184 InOrder inOrder = Mockito.inOrder(installer);
185 inOrder.verify(installer).restoreAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000186 eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
187 eq(101) /* rollbackId */,
Narayan Kamathc034fe92019-01-23 10:48:17 +0000188 eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
189 inOrder.verifyNoMoreInteractions();
190
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000191 ArrayList<RestoreInfo> pendingRestores = info.getPendingRestores();
Narayan Kamathc034fe92019-01-23 10:48:17 +0000192 assertEquals(0, pendingRestores.size());
193 }
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000194
195 @Test
196 public void destroyAppData() throws Exception {
197 Installer installer = mock(Installer.class);
Oli Lan7bbd8b42020-01-14 10:11:42 +0000198 AppDataRollbackHelper helper = new AppDataRollbackHelper(installer, mApexManager);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000199
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000200 PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
201 info.putCeSnapshotInode(11, 239L);
202 helper.destroyAppDataSnapshot(5 /* rollbackId */, info, 10 /* userId */);
203 helper.destroyAppDataSnapshot(5 /* rollbackId */, info, 11 /* userId */);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000204
205 InOrder inOrder = Mockito.inOrder(installer);
206 inOrder.verify(installer).destroyAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000207 eq("com.foo.bar"), eq(10) /* userId */, eq(0L) /* ceSnapshotInode */,
208 eq(5) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000209 inOrder.verify(installer).destroyAppDataSnapshot(
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000210 eq("com.foo.bar"), eq(11) /* userId */, eq(239L) /* ceSnapshotInode */,
211 eq(5) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000212 inOrder.verifyNoMoreInteractions();
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000213
214 assertEquals(0, info.getCeSnapshotInodes().size());
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000215 }
216
217 @Test
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000218 public void commitPendingBackupAndRestoreForUser() throws Exception {
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000219 Installer installer = mock(Installer.class);
Oli Lan7bbd8b42020-01-14 10:11:42 +0000220 AppDataRollbackHelper helper = new AppDataRollbackHelper(installer, mApexManager);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000221
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000222 when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(53L);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000223
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000224 // This one should be backed up.
225 PackageRollbackInfo pendingBackup = createPackageRollbackInfo("com.foo", new int[]{37, 73});
226 pendingBackup.addPendingBackup(37);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000227
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000228 // Nothing should be done for this one.
229 PackageRollbackInfo wasRecentlyRestored = createPackageRollbackInfo("com.bar",
230 new int[]{37, 73});
231 wasRecentlyRestored.addPendingBackup(37);
232 wasRecentlyRestored.getPendingRestores().add(
233 new RestoreInfo(37 /* userId */, 239 /* appId*/, "seInfo"));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000234
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000235 // This one should be restored
236 PackageRollbackInfo pendingRestore = createPackageRollbackInfo("com.abc",
237 new int[]{37, 73});
238 pendingRestore.putCeSnapshotInode(37, 1543L);
239 pendingRestore.getPendingRestores().add(
240 new RestoreInfo(37 /* userId */, 57 /* appId*/, "seInfo"));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000241
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000242 // This one shouldn't be processed, because it hasn't pending backups/restores for userId
243 // 37.
244 PackageRollbackInfo ignoredInfo = createPackageRollbackInfo("com.bar",
245 new int[]{3, 73});
246 wasRecentlyRestored.addPendingBackup(3);
247 wasRecentlyRestored.addPendingBackup(73);
248 wasRecentlyRestored.getPendingRestores().add(
249 new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo"));
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000250
Gavin Corkery0987cb02019-10-07 10:46:55 +0100251 Rollback dataWithPendingBackup = createRollbackForId(101);
Richard Uhlercca637a2019-02-27 11:50:48 +0000252 dataWithPendingBackup.info.getPackages().add(pendingBackup);
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000253
Gavin Corkery0987cb02019-10-07 10:46:55 +0100254 Rollback dataWithRecentRestore = createRollbackForId(17239);
Richard Uhlercca637a2019-02-27 11:50:48 +0000255 dataWithRecentRestore.info.getPackages().add(wasRecentlyRestored);
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000256
Gavin Corkery0987cb02019-10-07 10:46:55 +0100257 Rollback dataForDifferentUser = createRollbackForId(17239);
Richard Uhlercca637a2019-02-27 11:50:48 +0000258 dataForDifferentUser.info.getPackages().add(ignoredInfo);
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000259
Gavin Corkery0987cb02019-10-07 10:46:55 +0100260 Rollback dataForRestore = createRollbackForId(17239);
Richard Uhler6f8a33b2019-02-26 10:40:36 +0000261 dataForRestore.info.getPackages().add(pendingRestore);
262 dataForRestore.info.getPackages().add(wasRecentlyRestored);
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000263
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000264 InOrder inOrder = Mockito.inOrder(installer);
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000265
266 // Check that pending backup and restore for the same package mutually destroyed each other.
Oli Lan31f453f2019-09-11 09:58:39 +0100267 assertTrue(helper.commitPendingBackupAndRestoreForUser(37, dataWithRecentRestore));
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000268 assertEquals(-1, wasRecentlyRestored.getPendingBackups().indexOf(37));
269 assertNull(wasRecentlyRestored.getRestoreInfo(37));
270
271 // Check that backup was performed.
Oli Lan31f453f2019-09-11 09:58:39 +0100272 assertTrue(helper.commitPendingBackupAndRestoreForUser(37, dataWithPendingBackup));
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000273 inOrder.verify(installer).snapshotAppData(eq("com.foo"), eq(37), eq(101),
274 eq(Installer.FLAG_STORAGE_CE));
275 assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37));
276 assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37));
277
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000278 // Check that restore was performed.
Oli Lan31f453f2019-09-11 09:58:39 +0100279 assertTrue(helper.commitPendingBackupAndRestoreForUser(37, dataForRestore));
Nikita Ioffe5dcd17972019-02-04 11:08:13 +0000280 inOrder.verify(installer).restoreAppDataSnapshot(
281 eq("com.abc"), eq(57) /* appId */, eq("seInfo"), eq(37) /* userId */,
282 eq(17239) /* rollbackId */, eq(Installer.FLAG_STORAGE_CE));
283 assertNull(pendingRestore.getRestoreInfo(37));
284
Nikita Ioffe952aa7b2019-01-28 19:49:56 +0000285 inOrder.verifyNoMoreInteractions();
286 }
Narayan Kamathc034fe92019-01-23 10:48:17 +0000287}