1 /*
2  * Copyright (C) 2017 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 
17 package com.android.server.pm;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.Matchers.eq;
23 import static org.mockito.Matchers.isNull;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.content.Context;
28 import android.content.pm.UserInfo;
29 import android.os.FileUtils;
30 import android.os.storage.StorageManager;
31 import android.os.storage.VolumeInfo;
32 import android.platform.test.annotations.Presubmit;
33 
34 import androidx.test.InstrumentationRegistry;
35 import androidx.test.filters.SmallTest;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.Mock;
42 import org.mockito.MockitoAnnotations;
43 
44 import java.io.File;
45 import java.io.FileOutputStream;
46 import java.io.IOException;
47 import java.nio.charset.Charset;
48 import java.util.Arrays;
49 import java.util.Collections;
50 
51 // atest PackageManagerServiceTest:com.android.server.pm.UserDataPreparerTest
52 @RunWith(AndroidJUnit4.class)
53 @Presubmit
54 @SmallTest
55 public class UserDataPreparerTest {
56 
57     private static final int TEST_USER_SERIAL = 1000;
58     private static final int TEST_USER_ID = 10;
59 
60     private TestUserDataPreparer mUserDataPreparer;
61 
62     @Mock
63     private StorageManager mStorageManagerMock;
64 
65     @Mock
66     private Context mContextMock;
67 
68     @Mock
69     private Installer mInstaller;
70 
71     private Object mInstallLock;
72 
73     @Before
setup()74     public void setup() {
75         Context ctx = InstrumentationRegistry.getContext();
76         FileUtils.deleteContents(ctx.getCacheDir());
77         mInstallLock = new Object();
78         MockitoAnnotations.initMocks(this);
79         mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock,
80                 ctx.getCacheDir());
81         when(mContextMock.getSystemServiceName(StorageManager.class))
82                 .thenReturn(Context.STORAGE_SERVICE);
83         when(mContextMock.getSystemService(eq(Context.STORAGE_SERVICE)))
84                 .thenReturn(mStorageManagerMock);
85         VolumeInfo testVolume = new VolumeInfo("testuuid", VolumeInfo.TYPE_PRIVATE, null, null);
86         when(mStorageManagerMock.getWritablePrivateVolumes()).thenReturn(Arrays.asList(testVolume));
87     }
88 
89     @Test
testPrepareUserData_De()90     public void testPrepareUserData_De() throws Exception {
91         File userDeDir = mUserDataPreparer.getDataUserDeDirectory(null, TEST_USER_ID);
92         userDeDir.mkdirs();
93         File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
94         systemDeDir.mkdirs();
95         mUserDataPreparer
96                 .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_DE);
97         verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
98                 eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
99         verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
100                 eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
101         int serialNumber = UserDataPreparer.getSerialNumber(userDeDir);
102         assertEquals(TEST_USER_SERIAL, serialNumber);
103         serialNumber = UserDataPreparer.getSerialNumber(systemDeDir);
104         assertEquals(TEST_USER_SERIAL, serialNumber);
105     }
106 
107     @Test
testPrepareUserData_Ce()108     public void testPrepareUserData_Ce() throws Exception {
109         File userCeDir = mUserDataPreparer.getDataUserCeDirectory(null, TEST_USER_ID);
110         userCeDir.mkdirs();
111         File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
112         systemCeDir.mkdirs();
113         mUserDataPreparer
114                 .prepareUserData(TEST_USER_ID, TEST_USER_SERIAL, StorageManager.FLAG_STORAGE_CE);
115         verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
116                 eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
117         verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
118                 eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
119         int serialNumber = UserDataPreparer.getSerialNumber(userCeDir);
120         assertEquals(TEST_USER_SERIAL, serialNumber);
121         serialNumber = UserDataPreparer.getSerialNumber(systemCeDir);
122         assertEquals(TEST_USER_SERIAL, serialNumber);
123     }
124 
125     @Test
testDestroyUserData_De_DoesNotDestroyCe()126     public void testDestroyUserData_De_DoesNotDestroyCe() throws Exception {
127         // Add file in CE storage
128         File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
129         systemCeDir.mkdirs();
130         File ceFile = new File(systemCeDir, "file");
131         writeFile(ceFile, "-----" );
132         // Destroy DE storage, then verify that CE storage wasn't destroyed too.
133         mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
134         assertEquals(Collections.singletonList(ceFile), Arrays.asList(FileUtils.listFilesOrEmpty(
135                 systemCeDir)));
136     }
137 
138     @Test
testDestroyUserData_De()139     public void testDestroyUserData_De() throws Exception {
140         File systemDir = mUserDataPreparer.getUserSystemDirectory(TEST_USER_ID);
141         systemDir.mkdirs();
142         writeFile(new File(systemDir, "file"), "-----" );
143         File systemDeDir = mUserDataPreparer.getDataSystemDeDirectory(TEST_USER_ID);
144         systemDeDir.mkdirs();
145         writeFile(new File(systemDeDir, "file"), "-----" );
146 
147         mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_DE);
148 
149         verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
150                         eq(StorageManager.FLAG_STORAGE_DE));
151         verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
152                         eq(StorageManager.FLAG_STORAGE_DE));
153 
154         // systemDir (normal path: /data/system/users/$userId) should have been deleted.
155         assertFalse(systemDir.exists());
156         // systemDeDir (normal path: /data/system_de/$userId) should still exist but be empty, since
157         // UserDataPreparer itself is responsible for deleting the contents of this directory, but
158         // it delegates to StorageManager.destroyUserStorage() for deleting the directory itself.
159         // We've mocked out StorageManager, so StorageManager.destroyUserStorage() will be a no-op.
160         assertTrue(systemDeDir.exists());
161         assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
162                 systemDeDir)));
163     }
164 
165     @Test
testDestroyUserData_Ce()166     public void testDestroyUserData_Ce() throws Exception {
167         File systemCeDir = mUserDataPreparer.getDataSystemCeDirectory(TEST_USER_ID);
168         systemCeDir.mkdirs();
169         writeFile(new File(systemCeDir, "file"), "-----" );
170 
171         mUserDataPreparer.destroyUserData(TEST_USER_ID, StorageManager.FLAG_STORAGE_CE);
172 
173         verify(mInstaller).destroyUserData(isNull(String.class), eq(TEST_USER_ID),
174                 eq(StorageManager.FLAG_STORAGE_CE));
175         verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
176                 eq(StorageManager.FLAG_STORAGE_CE));
177 
178         // systemCeDir (normal path: /data/system_ce/$userId) should still exist but be empty, since
179         // UserDataPreparer itself is responsible for deleting the contents of this directory, but
180         // it delegates to StorageManager.destroyUserStorage() for deleting the directory itself.
181         // We've mocked out StorageManager, so StorageManager.destroyUserStorage() will be a no-op.
182         assertTrue(systemCeDir.exists());
183         assertEquals(Collections.emptyList(), Arrays.asList(FileUtils.listFilesOrEmpty(
184                 systemCeDir)));
185     }
186 
187     @Test
testReconcileUsers()188     public void testReconcileUsers() throws Exception {
189         UserInfo u1 = new UserInfo(1, "u1", 0);
190         UserInfo u2 = new UserInfo(2, "u2", 0);
191         File testDir = mUserDataPreparer.testDir;
192         File dir1 = new File(testDir, "1");
193         dir1.mkdirs();
194         File dir2 = new File(testDir, "2");
195         dir2.mkdirs();
196         File dir3 = new File(testDir, "3");
197         dir3.mkdirs();
198 
199         mUserDataPreparer
200                 .reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL, Arrays.asList(u1, u2),
201                         Arrays.asList(dir1, dir2, dir3));
202         // Verify that user 3 data is removed
203         verify(mInstaller).destroyUserData(isNull(String.class), eq(3),
204                 eq(StorageManager.FLAG_STORAGE_DE|StorageManager.FLAG_STORAGE_CE));
205     }
206 
writeFile(File file, String content)207     private static void writeFile(File file, String content) throws IOException {
208         try (FileOutputStream os = new FileOutputStream(file)) {
209             os.write(content.getBytes(Charset.defaultCharset()));
210         }
211     }
212 
213     private static class TestUserDataPreparer extends UserDataPreparer {
214         File testDir;
215 
TestUserDataPreparer(Installer installer, Object installLock, Context context, File testDir)216         TestUserDataPreparer(Installer installer, Object installLock, Context context,
217                 File testDir) {
218             super(installer, installLock, context);
219             this.testDir = testDir;
220         }
221 
222         @Override
getDataMiscCeDirectory(int userId)223         protected File getDataMiscCeDirectory(int userId) {
224             return new File(testDir, "misc_ce_" + userId);
225         }
226 
227         @Override
getDataSystemCeDirectory(int userId)228         protected File getDataSystemCeDirectory(int userId) {
229             return new File(testDir, "system_ce_" + userId);
230         }
231 
232         @Override
getDataMiscDeDirectory(int userId)233         protected File getDataMiscDeDirectory(int userId) {
234             return new File(testDir, "misc_de_" + userId);
235         }
236 
237         @Override
getUserSystemDirectory(int userId)238         protected File getUserSystemDirectory(int userId) {
239             return new File(testDir, "user_system_" + userId);
240         }
241 
242         @Override
getDataUserCeDirectory(String volumeUuid, int userId)243         protected File getDataUserCeDirectory(String volumeUuid, int userId) {
244             return new File(testDir, "user_ce_" + userId);
245         }
246 
247         @Override
getDataSystemDeDirectory(int userId)248         protected File getDataSystemDeDirectory(int userId) {
249             return new File(testDir, "system_de_" + userId);
250         }
251 
252         @Override
getDataUserDeDirectory(String volumeUuid, int userId)253         protected File getDataUserDeDirectory(String volumeUuid, int userId) {
254             return new File(testDir, "user_de_" + userId);
255         }
256     }
257 
258 }
259