• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.content.res.Resources.NotFoundException;
22 import android.os.FileUtils;
23 import android.os.storage.OnObbStateChangeListener;
24 import android.os.storage.StorageManager;
25 import android.test.AndroidTestCase;
26 import android.test.ComparisonFailure;
27 import android.test.suitebuilder.annotation.LargeTest;
28 import android.util.Log;
29 
30 import static com.android.server.MountService.buildObbPath;
31 
32 import com.android.frameworks.servicestests.R;
33 
34 import java.io.File;
35 import java.io.InputStream;
36 
37 public class MountServiceTests extends AndroidTestCase {
38     private static final String TAG = "MountServiceTests";
39 
40     private static final long MAX_WAIT_TIME = 25*1000;
41     private static final long WAIT_TIME_INCR = 5*1000;
42 
43     private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
44 
45     @Override
setUp()46     protected void setUp() throws Exception {
47         super.setUp();
48     }
49 
50     @Override
tearDown()51     protected void tearDown() throws Exception {
52         super.tearDown();
53     }
54 
assertStartsWith(String message, String prefix, String actual)55     private static void assertStartsWith(String message, String prefix, String actual) {
56         if (!actual.startsWith(prefix)) {
57             throw new ComparisonFailure(message, prefix, actual);
58         }
59     }
60 
61     private static class ObbObserver extends OnObbStateChangeListener {
62         private String path;
63 
64         public int state = -1;
65         boolean done = false;
66 
67         @Override
onObbStateChange(String path, int state)68         public void onObbStateChange(String path, int state) {
69             Log.d(TAG, "Received message.  path=" + path + ", state=" + state);
70             synchronized (this) {
71                 this.path = path;
72                 this.state = state;
73                 done = true;
74                 notifyAll();
75             }
76         }
77 
getPath()78         public String getPath() {
79             assertTrue("Expected ObbObserver to have received a state change.", done);
80             return path;
81         }
82 
getState()83         public int getState() {
84             assertTrue("Expected ObbObserver to have received a state change.", done);
85             return state;
86         }
87 
reset()88         public void reset() {
89             this.path = null;
90             this.state = -1;
91             done = false;
92         }
93 
isDone()94         public boolean isDone() {
95             return done;
96         }
97 
waitForCompletion()98         public boolean waitForCompletion() {
99             long waitTime = 0;
100             synchronized (this) {
101                 while (!isDone() && waitTime < MAX_WAIT_TIME) {
102                     try {
103                         wait(WAIT_TIME_INCR);
104                         waitTime += WAIT_TIME_INCR;
105                     } catch (InterruptedException e) {
106                         Log.i(TAG, "Interrupted during sleep", e);
107                     }
108                 }
109             }
110 
111             return isDone();
112         }
113     }
114 
getFilePath(String name)115     private File getFilePath(String name) {
116         final File filesDir = mContext.getFilesDir();
117         final File outFile = new File(filesDir, name);
118         return outFile;
119     }
120 
copyRawToFile(int rawResId, File outFile)121     private void copyRawToFile(int rawResId, File outFile) {
122         Resources res = mContext.getResources();
123         InputStream is = null;
124         try {
125             is = res.openRawResource(rawResId);
126         } catch (NotFoundException e) {
127             fail("Failed to load resource with id: " + rawResId);
128         }
129         FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
130                 | FileUtils.S_IRWXO, -1, -1);
131         assertTrue(FileUtils.copyToFile(is, outFile));
132         FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
133                 | FileUtils.S_IRWXO, -1, -1);
134     }
135 
getStorageManager()136     private StorageManager getStorageManager() {
137         return (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
138     }
139 
mountObb(StorageManager sm, final int resource, final File file, int expectedState)140     private void mountObb(StorageManager sm, final int resource, final File file,
141             int expectedState) {
142         copyRawToFile(resource, file);
143 
144         final ObbObserver observer = new ObbObserver();
145         assertTrue("mountObb call on " + file.getPath() + " should succeed",
146                 sm.mountObb(file.getPath(), null, observer));
147 
148         assertTrue("Mount should have completed",
149                 observer.waitForCompletion());
150 
151         if (expectedState == OnObbStateChangeListener.MOUNTED) {
152             assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath()));
153         }
154 
155         assertEquals("Actual file and resolved file should be the same",
156                 file.getPath(), observer.getPath());
157 
158         assertEquals(expectedState, observer.getState());
159     }
160 
mountObbWithoutWait(final StorageManager sm, final int resource, final File file)161     private ObbObserver mountObbWithoutWait(final StorageManager sm, final int resource,
162             final File file) {
163         copyRawToFile(resource, file);
164 
165         final ObbObserver observer = new ObbObserver();
166         assertTrue("mountObb call on " + file.getPath() + " should succeed", sm.mountObb(file
167                 .getPath(), null, observer));
168 
169         return observer;
170     }
171 
waitForObbActionCompletion(final StorageManager sm, final File file, final ObbObserver observer, int expectedState, boolean checkPath)172     private void waitForObbActionCompletion(final StorageManager sm, final File file,
173             final ObbObserver observer, int expectedState, boolean checkPath) {
174         assertTrue("Mount should have completed", observer.waitForCompletion());
175 
176         assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath()));
177 
178         if (checkPath) {
179             assertEquals("Actual file and resolved file should be the same", file.getPath(),
180                     observer.getPath());
181         }
182 
183         assertEquals(expectedState, observer.getState());
184     }
185 
checkMountedPath(final StorageManager sm, final File file)186     private String checkMountedPath(final StorageManager sm, final File file) {
187         final String mountPath = sm.getMountedObbPath(file.getPath());
188         assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX,
189                 OBB_MOUNT_PREFIX,
190                 mountPath);
191         return mountPath;
192     }
193 
unmountObb(final StorageManager sm, final File file, int expectedState)194     private void unmountObb(final StorageManager sm, final File file, int expectedState) {
195         final ObbObserver observer = new ObbObserver();
196 
197         assertTrue("unmountObb call on test1.obb should succeed",
198  sm.unmountObb(file.getPath(),
199                 false, observer));
200 
201         assertTrue("Unmount should have completed",
202                 observer.waitForCompletion());
203 
204         assertEquals(expectedState, observer.getState());
205 
206         if (expectedState == OnObbStateChangeListener.UNMOUNTED) {
207             assertFalse("OBB should not be mounted", sm.isObbMounted(file.getPath()));
208         }
209     }
210 
211     @LargeTest
testMountAndUnmountObbNormal()212     public void testMountAndUnmountObbNormal() {
213         StorageManager sm = getStorageManager();
214 
215         final File outFile = getFilePath("test1.obb");
216 
217         mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED);
218 
219         mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
220 
221         final String mountPath = checkMountedPath(sm, outFile);
222         final File mountDir = new File(mountPath);
223 
224         assertTrue("OBB mounted path should be a directory",
225                 mountDir.isDirectory());
226 
227         unmountObb(sm, outFile, OnObbStateChangeListener.UNMOUNTED);
228     }
229 
230     @LargeTest
testAttemptMountNonObb()231     public void testAttemptMountNonObb() {
232         StorageManager sm = getStorageManager();
233 
234         final File outFile = getFilePath("test1_nosig.obb");
235 
236         mountObb(sm, R.raw.test1_nosig, outFile, OnObbStateChangeListener.ERROR_INTERNAL);
237 
238         assertFalse("OBB should not be mounted",
239                 sm.isObbMounted(outFile.getPath()));
240 
241         assertNull("OBB's mounted path should be null",
242                 sm.getMountedObbPath(outFile.getPath()));
243     }
244 
245     @LargeTest
testAttemptMountObbWrongPackage()246     public void testAttemptMountObbWrongPackage() {
247         StorageManager sm = getStorageManager();
248 
249         final File outFile = getFilePath("test1_wrongpackage.obb");
250 
251         mountObb(sm, R.raw.test1_wrongpackage, outFile,
252                 OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
253 
254         assertFalse("OBB should not be mounted",
255                 sm.isObbMounted(outFile.getPath()));
256 
257         assertNull("OBB's mounted path should be null",
258                 sm.getMountedObbPath(outFile.getPath()));
259     }
260 
261     @LargeTest
testMountAndUnmountTwoObbs()262     public void testMountAndUnmountTwoObbs() {
263         StorageManager sm = getStorageManager();
264 
265         final File file1 = getFilePath("test1.obb");
266         final File file2 = getFilePath("test2.obb");
267 
268         ObbObserver oo1 = mountObbWithoutWait(sm, R.raw.test1, file1);
269         ObbObserver oo2 = mountObbWithoutWait(sm, R.raw.test1, file2);
270 
271         Log.d(TAG, "Waiting for OBB #1 to complete mount");
272         waitForObbActionCompletion(sm, file1, oo1, OnObbStateChangeListener.MOUNTED, false);
273         Log.d(TAG, "Waiting for OBB #2 to complete mount");
274         waitForObbActionCompletion(sm, file2, oo2, OnObbStateChangeListener.MOUNTED, false);
275 
276         final String mountPath1 = checkMountedPath(sm, file1);
277         final File mountDir1 = new File(mountPath1);
278         assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory());
279 
280         final String mountPath2 = checkMountedPath(sm, file2);
281         final File mountDir2 = new File(mountPath2);
282         assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory());
283 
284         unmountObb(sm, file1, OnObbStateChangeListener.UNMOUNTED);
285         unmountObb(sm, file2, OnObbStateChangeListener.UNMOUNTED);
286     }
287 
testBuildObbPath()288     public void testBuildObbPath() {
289         final int userId = 10;
290 
291         // Paths outside external storage should remain untouched
292         assertEquals("/storage/random/foo",
293                 buildObbPath("/storage/random/foo", userId, true));
294         assertEquals("/storage/random/foo",
295                 buildObbPath("/storage/random/foo", userId, false));
296 
297         // Paths on user-specific emulated storage
298         assertEquals("/mnt/shell/emulated/10/foo",
299                 buildObbPath("/storage/emulated_legacy/foo", userId, true));
300         assertEquals("/storage/emulated/10/foo",
301                 buildObbPath("/storage/emulated_legacy/foo", userId, false));
302         assertEquals("/mnt/shell/emulated/10/foo",
303                 buildObbPath("/storage/emulated/10/foo", userId, true));
304         assertEquals("/storage/emulated/10/foo",
305                 buildObbPath("/storage/emulated/10/foo", userId, false));
306 
307         // Paths on shared OBB emulated storage
308         assertEquals("/mnt/shell/emulated/obb/foo",
309                 buildObbPath("/storage/emulated_legacy/Android/obb/foo", userId, true));
310         assertEquals("/storage/emulated/0/Android/obb/foo",
311                 buildObbPath("/storage/emulated_legacy/Android/obb/foo", userId, false));
312         assertEquals("/mnt/shell/emulated/obb/foo",
313                 buildObbPath("/storage/emulated/10/Android/obb/foo", userId, true));
314         assertEquals("/storage/emulated/0/Android/obb/foo",
315                 buildObbPath("/storage/emulated/10/Android/obb/foo", userId, false));
316     }
317 }
318