MountServiceTests.java revision 4fbbda4cecb078bd3867f416b02cc75f5455284f
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
17package com.android.server;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.content.res.Resources.NotFoundException;
22import android.os.FileUtils;
23import android.os.storage.OnObbStateChangeListener;
24import android.os.storage.StorageManager;
25import android.test.AndroidTestCase;
26import android.test.ComparisonFailure;
27import android.test.suitebuilder.annotation.LargeTest;
28import android.util.Log;
29
30import static com.android.server.MountService.buildObbPath;
31
32import com.android.frameworks.servicestests.R;
33
34import java.io.File;
35import java.io.InputStream;
36
37public 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
46    protected void setUp() throws Exception {
47        super.setUp();
48    }
49
50    @Override
51    protected void tearDown() throws Exception {
52        super.tearDown();
53    }
54
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
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
78        public String getPath() {
79            assertTrue("Expected ObbObserver to have received a state change.", done);
80            return path;
81        }
82
83        public int getState() {
84            assertTrue("Expected ObbObserver to have received a state change.", done);
85            return state;
86        }
87
88        public void reset() {
89            this.path = null;
90            this.state = -1;
91            done = false;
92        }
93
94        public boolean isDone() {
95            return done;
96        }
97
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
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
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
136    private StorageManager getStorageManager() {
137        return (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
138    }
139
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
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
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
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
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
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
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
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
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
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