| /* |
| * Copyright (C) 2017 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.pm; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Matchers.isNull; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.content.Context; |
| import android.content.pm.UserInfo; |
| import android.os.FileUtils; |
| import android.os.storage.StorageManager; |
| import android.os.storage.VolumeInfo; |
| import android.platform.test.annotations.Presubmit; |
| |
| import androidx.test.InstrumentationRegistry; |
| import androidx.test.filters.SmallTest; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.Mock; |
| import org.mockito.MockitoAnnotations; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.nio.charset.Charset; |
| import java.util.Arrays; |
| import java.util.Collections; |
| |
| /** |
| * <p>Run with:<pre> |
| * m FrameworksServicesTests && |
| * adb install \ |
| * -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && |
| * adb shell am instrument -e class com.android.server.pm.UserDataPreparerTest \ |
| * -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner |
| * </pre> |
| */ |
| @RunWith(AndroidJUnit4.class) |
| @Presubmit |
| @SmallTest |
| public class UserDataPreparerTest { |
| |
| private static final int TEST_USER_SERIAL = 1000; |
| private static final int TEST_USER_ID = 10; |
| |
| private TestUserDataPreparer mUserDataPreparer; |
| |
| @Mock |
| private StorageManager mStorageManagerMock; |
| |
| @Mock |
| private Context mContextMock; |
| |
| @Mock |
| private Installer mInstaller; |
| |
| private Object mInstallLock; |
| |
| @Before |
| public void setup() { |
| Context ctx = InstrumentationRegistry.getContext(); |
| FileUtils.deleteContents(ctx.getCacheDir()); |
| mInstallLock = new Object(); |
| MockitoAnnotations.initMocks(this); |
| mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock, false, |
| ctx.getCacheDir()); |
| when(mContextMock.getSystemServiceName(StorageManager.class)) |
| .thenReturn(Context.STORAGE_SERVICE); |
| when(mContextMock.getSystemService(eq(Context.STORAGE_SERVICE))) |
| .thenReturn(mStorageManagerMock); |
| VolumeInfo testVolume = new VolumeInfo("testuuid", VolumeInfo.TYPE_PRIVATE, null, null); |
| when(mStorageManagerMock.getWritablePrivateVolumes()).thenReturn(Arrays.asList(testVolume)); |
| } |
| |
| @Test |
| public void testPrepareUserData_De() throws Exception { |
| File userDeDir = mUserDataPreparer.getDataUserDeDirectory(null, TEST_USER_ID); |
| userDeDir.mkdirs(); |
| File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID); |
| systemDeDir.mkdirs(); |
| mUserDataPreparer |
| .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_DE); |
| verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), |
| eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE)); |
| verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID), |
| eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE)); |
| int serialNumber = UserDataPreparer.getSerialNumber(userDeDir); |
| assertEquals(TEST_USER_SERIAL, serialNumber); |
| serialNumber = UserDataPreparer.getSerialNumber(systemDeDir); |
| assertEquals(TEST_USER_SERIAL, serialNumber); |
| } |
| |
| @Test |
| public void testPrepareUserData_Ce() throws Exception { |
| File userCeDir = mUserDataPreparer.getDataUserCeDirectory(null, TEST_USER_ID); |
| userCeDir.mkdirs(); |
| File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID); |
| systemCeDir.mkdirs(); |
| mUserDataPreparer |
| .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_CE); |
| verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), |
| eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE)); |
| verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID), |
| eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE)); |
| int serialNumber = UserDataPreparer.getSerialNumber(userCeDir); |
| assertEquals(TEST_USER_SERIAL, serialNumber); |
| serialNumber = UserDataPreparer.getSerialNumber(systemCeDir); |
| assertEquals(TEST_USER_SERIAL, serialNumber); |
| } |
| |
| @Test |
| public void testDestroyUserData() throws Exception { |
| // Add file in CE |
| File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID); |
| systemCeDir.mkdirs(); |
| File ceFile = new File(systemCeDir, "file"); |
| writeFile(ceFile, "-----" ); |
| testDestroyUserData_De(); |
| // CE directory should be preserved |
| assertEquals(Collections.singletonList(ceFile), Arrays.asList(FileUtils.listFilesOrEmpty( |
| systemCeDir))); |
| |
| testDestroyUserData_Ce(); |
| |
| // Verify that testDir is empty |
| assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty( |
| mUserDataPreparer.testDir))); |
| } |
| |
| @Test |
| public void testDestroyUserData_De() throws Exception { |
| File systemDir = mUserDataPreparer.getUserSystemDirectory(TEST_USER_ID); |
| systemDir.mkdirs(); |
| writeFile(new File(systemDir, "file"), "-----" ); |
| File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID); |
| systemDeDir.mkdirs(); |
| writeFile(new File(systemDeDir, "file"), "-----" ); |
| |
| mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE); |
| |
| verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID), |
| eq(StorageManager.FLAG_STORAGE_DE)); |
| verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID), |
| eq(StorageManager.FLAG_STORAGE_DE)); |
| |
| assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(systemDir))); |
| assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty( |
| systemDeDir))); |
| } |
| |
| @Test |
| public void testDestroyUserData_Ce() throws Exception { |
| File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID); |
| systemCeDir.mkdirs(); |
| writeFile(new File(systemCeDir, "file"), "-----" ); |
| |
| mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE); |
| |
| verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID), |
| eq(StorageManager.FLAG_STORAGE_CE)); |
| verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID), |
| eq(StorageManager.FLAG_STORAGE_CE)); |
| |
| assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty( |
| systemCeDir))); |
| } |
| |
| @Test |
| public void testReconcileUsers() throws Exception { |
| UserInfo u1 = new UserInfo(1, "u1", 0); |
| UserInfo u2 = new UserInfo(2, "u2", 0); |
| File testDir = mUserDataPreparer.testDir; |
| File dir1 = new File(testDir, "1"); |
| dir1.mkdirs(); |
| File dir2 = new File(testDir, "2"); |
| dir2.mkdirs(); |
| File dir3 = new File(testDir, "3"); |
| dir3.mkdirs(); |
| |
| mUserDataPreparer |
| .reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL, Arrays.asList(u1, u2), |
| Arrays.asList(dir1, dir2, dir3)); |
| // Verify that user 3 data is removed |
| verify(mInstaller).destroyUserData(isNull(String.class), eq(3), |
| eq(StorageManager.FLAG_STORAGE_DE|StorageManager.FLAG_STORAGE_CE)); |
| } |
| |
| private static void writeFile(File file, String content) throws IOException { |
| try (FileOutputStream os = new FileOutputStream(file)) { |
| os.write(content.getBytes(Charset.defaultCharset())); |
| } |
| } |
| |
| private static class TestUserDataPreparer extends UserDataPreparer { |
| File testDir; |
| |
| TestUserDataPreparer(Installer installer, Object installLock, Context context, |
| boolean onlyCore, File testDir) { |
| super(installer, installLock, context, onlyCore); |
| this.testDir = testDir; |
| } |
| |
| @Override |
| protected File getDataMiscCeDirectory(int userId) { |
| return new File(testDir, "misc_ce_" + userId); |
| } |
| |
| @Override |
| protected File getDataSystemCeDirectory(int userId) { |
| return new File(testDir, "system_ce_" + userId); |
| } |
| |
| @Override |
| protected File getDataMiscDeDirectory(int userId) { |
| return new File(testDir, "misc_de_" + userId); |
| } |
| |
| @Override |
| protected File getUserSystemDirectory(int userId) { |
| return new File(testDir, "user_system_" + userId); |
| } |
| |
| @Override |
| protected File getDataUserCeDirectory(String volumeUuid, int userId) { |
| return new File(testDir, "user_ce_" + userId); |
| } |
| |
| @Override |
| protected File getDataSystemDeDirectory(int userId) { |
| return new File(testDir, "system_de_" + userId); |
| } |
| |
| @Override |
| protected File getDataUserDeDirectory(String volumeUuid, int userId) { |
| return new File(testDir, "user_de_" + userId); |
| } |
| |
| @Override |
| protected boolean isFileEncryptedEmulatedOnly() { |
| return false; |
| } |
| } |
| |
| } |