blob: 50dbaf570e9e61686a5231ed55fdff509a5ff81a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.rollback;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.util.IntArray;
import android.util.SparseLongArray;
import com.android.server.pm.Installer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.InOrder;
import org.mockito.Mockito;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@RunWith(JUnit4.class)
public class AppDataRollbackHelperTest {
@Test
public void testSnapshotAppData() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
// All users are unlocked so we should snapshot data for them.
doReturn(true).when(helper).isUserCredentialLocked(eq(10));
doReturn(true).when(helper).isUserCredentialLocked(eq(11));
AppDataRollbackHelper.SnapshotAppDataResult result = helper.snapshotAppData("com.foo.bar",
new int[]{10, 11});
assertEquals(2, result.pendingBackups.size());
assertEquals(10, result.pendingBackups.get(0));
assertEquals(11, result.pendingBackups.get(1));
assertEquals(0, result.ceSnapshotInodes.size());
InOrder inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).snapshotAppData(
eq("com.foo.bar"), eq(10), eq(Installer.FLAG_STORAGE_DE));
inOrder.verify(installer).snapshotAppData(
eq("com.foo.bar"), eq(11), eq(Installer.FLAG_STORAGE_DE));
inOrder.verifyNoMoreInteractions();
// One of the users is unlocked but the other isn't
doReturn(false).when(helper).isUserCredentialLocked(eq(10));
doReturn(true).when(helper).isUserCredentialLocked(eq(11));
when(installer.snapshotAppData(anyString(), anyInt(), anyInt())).thenReturn(239L);
result = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
assertEquals(1, result.pendingBackups.size());
assertEquals(11, result.pendingBackups.get(0));
assertEquals(1, result.ceSnapshotInodes.size());
assertEquals(239L, result.ceSnapshotInodes.get(10));
inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).snapshotAppData(
eq("com.foo.bar"), eq(10),
eq(Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE));
inOrder.verify(installer).snapshotAppData(
eq("com.foo.bar"), eq(11), eq(Installer.FLAG_STORAGE_DE));
inOrder.verifyNoMoreInteractions();
}
private static RollbackData createInProgressRollbackData(String packageName) {
RollbackData data = new RollbackData(1, new File("/does/not/exist"), -1, true);
data.packages.add(new PackageRollbackInfo(
new VersionedPackage(packageName, 1), new VersionedPackage(packageName, 1),
new IntArray(), new ArrayList<>(), false, new IntArray(), new SparseLongArray()));
data.inProgress = true;
return data;
}
@Test
public void testRestoreAppDataSnapshot_noRollbackData() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
assertFalse(helper.restoreAppData("com.foo", null, 0, 0, 0, "seinfo"));
verifyZeroInteractions(installer);
}
@Test
public void testRestoreAppDataSnapshot_noRollbackInProgress() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
RollbackData rd = createInProgressRollbackData("com.foo");
// Override the in progress flag.
rd.inProgress = false;
assertFalse(helper.restoreAppData("com.foo", rd, 0, 0, 0, "seinfo"));
verifyZeroInteractions(installer);
}
@Test
public void testRestoreAppDataSnapshot_pendingBackupForUser() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
RollbackData rd = createInProgressRollbackData("com.foo");
IntArray pendingBackups = rd.packages.get(0).getPendingBackups();
pendingBackups.add(10);
pendingBackups.add(11);
assertTrue(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
// Should only require FLAG_STORAGE_DE here because we have a pending backup that we
// didn't manage to execute.
InOrder inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).restoreAppDataSnapshot(
eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10), eq(Installer.FLAG_STORAGE_DE));
inOrder.verifyNoMoreInteractions();
assertEquals(1, pendingBackups.size());
assertEquals(11, pendingBackups.get(0));
}
@Test
public void testRestoreAppDataSnapshot_availableBackupForLockedUser() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
doReturn(true).when(helper).isUserCredentialLocked(eq(10));
RollbackData rd = createInProgressRollbackData("com.foo");
assertTrue(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
InOrder inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).restoreAppDataSnapshot(
eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10), eq(Installer.FLAG_STORAGE_DE));
inOrder.verifyNoMoreInteractions();
ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
assertEquals(1, pendingRestores.size());
assertEquals(10, pendingRestores.get(0).userId);
assertEquals(1, pendingRestores.get(0).appId);
assertEquals("seinfo", pendingRestores.get(0).seInfo);
}
@Test
public void testRestoreAppDataSnapshot_availableBackupForUnockedUser() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
doReturn(false).when(helper).isUserCredentialLocked(eq(10));
RollbackData rd = createInProgressRollbackData("com.foo");
assertFalse(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
InOrder inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).restoreAppDataSnapshot(
eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10),
eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
inOrder.verifyNoMoreInteractions();
ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
assertEquals(0, pendingRestores.size());
}
@Test
public void destroyAppData() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
SparseLongArray ceSnapshotInodes = new SparseLongArray();
ceSnapshotInodes.put(11, 239L);
helper.destroyAppDataSnapshot("com.foo.bar", 10, 0L);
helper.destroyAppDataSnapshot("com.foo.bar", 11, 239L);
InOrder inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).destroyAppDataSnapshot(
eq("com.foo.bar"), eq(10), eq(0L),
eq(Installer.FLAG_STORAGE_DE));
inOrder.verify(installer).destroyAppDataSnapshot(
eq("com.foo.bar"), eq(11), eq(239L),
eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
inOrder.verifyNoMoreInteractions();
}
@Test
public void commitPendingBackupAndRestoreForUser_updatesRollbackData() throws Exception {
Installer installer = mock(Installer.class);
AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
ArrayList<RollbackData> changedRollbackData = new ArrayList<>();
changedRollbackData.add(createInProgressRollbackData("com.foo.bar"));
when(installer.snapshotAppData(anyString(), anyInt(), anyInt())).thenReturn(239L);
ArrayList<String> pendingBackups = new ArrayList<>();
pendingBackups.add("com.foo.bar");
helper.commitPendingBackupAndRestoreForUser(11, pendingBackups,
new HashMap<>() /* pendingRestores */, changedRollbackData);
assertEquals(1, changedRollbackData.size());
assertEquals(1, changedRollbackData.get(0).packages.size());
PackageRollbackInfo info = changedRollbackData.get(0).packages.get(0);
assertEquals(1, info.getCeSnapshotInodes().size());
assertEquals(239L, info.getCeSnapshotInodes().get(11));
InOrder inOrder = Mockito.inOrder(installer);
inOrder.verify(installer).snapshotAppData("com.foo.bar", 11 /* userId */,
Installer.FLAG_STORAGE_CE);
inOrder.verifyNoMoreInteractions();
}
}