AsecTests.java revision a3de74555120cc4dc205a3f93ef44c843b8d64a8
1/*
2 * Copyright (C) 2006 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 android.os.storage;
18
19import android.content.Context;
20import android.os.Environment;
21import android.os.IBinder;
22import android.os.RemoteException;
23import android.os.ServiceManager;
24import android.test.AndroidTestCase;
25import android.util.Log;
26
27import java.io.File;
28import java.io.FileOutputStream;
29
30import junit.framework.Assert;
31
32public class AsecTests extends AndroidTestCase {
33    private static final boolean localLOGV = true;
34    public static final String TAG="AsecTests";
35
36    void failStr(String errMsg) {
37        Log.w(TAG, "errMsg="+errMsg);
38    }
39
40    void failStr(Exception e) {
41        Log.w(TAG, "e.getMessage="+e.getMessage());
42        Log.w(TAG, "e="+e);
43    }
44
45    @Override
46    protected void setUp() throws Exception {
47        super.setUp();
48        if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
49        cleanupContainers();
50    }
51
52    @Override
53    protected void tearDown() throws Exception {
54        super.tearDown();
55        if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
56        cleanupContainers();
57    }
58
59    private void cleanupContainers() throws RemoteException {
60        IMountService ms = getMs();
61        String[] containers = ms.getSecureContainerList();
62
63        for (int i = 0; i < containers.length; i++) {
64            if (containers[i].startsWith("com.android.unittests.AsecTests.")) {
65                ms.destroySecureContainer(containers[i], true);
66            }
67        }
68    }
69
70    private boolean containerExists(String localId) throws RemoteException {
71        IMountService ms = getMs();
72        String[] containers = ms.getSecureContainerList();
73        String fullId = "com.android.unittests.AsecTests." + localId;
74
75        for (int i = 0; i < containers.length; i++) {
76            if (containers[i].equals(fullId)) {
77                return true;
78            }
79        }
80        return false;
81    }
82
83    private int createContainer(String localId, int size, String key) throws RemoteException {
84        Assert.assertTrue(isMediaMounted());
85        String fullId = "com.android.unittests.AsecTests." + localId;
86
87        IMountService ms = getMs();
88        return ms.createSecureContainer(fullId, size, "fat", key, android.os.Process.myUid());
89    }
90
91    private int mountContainer(String localId, String key) throws RemoteException {
92        Assert.assertTrue(isMediaMounted());
93        String fullId = "com.android.unittests.AsecTests." + localId;
94
95        IMountService ms = getMs();
96        return ms.mountSecureContainer(fullId, key, android.os.Process.myUid());
97    }
98
99    private int renameContainer(String localId1, String localId2) throws RemoteException {
100        Assert.assertTrue(isMediaMounted());
101        String fullId1 = "com.android.unittests.AsecTests." + localId1;
102        String fullId2 = "com.android.unittests.AsecTests." + localId2;
103
104        IMountService ms = getMs();
105        return ms.renameSecureContainer(fullId1, fullId2);
106    }
107
108    private int unmountContainer(String localId, boolean force) throws RemoteException {
109        Assert.assertTrue(isMediaMounted());
110        String fullId = "com.android.unittests.AsecTests." + localId;
111
112        IMountService ms = getMs();
113        return ms.unmountSecureContainer(fullId, force);
114    }
115
116    private int destroyContainer(String localId, boolean force) throws RemoteException {
117        Assert.assertTrue(isMediaMounted());
118        String fullId = "com.android.unittests.AsecTests." + localId;
119
120        IMountService ms = getMs();
121        return ms.destroySecureContainer(fullId, force);
122    }
123
124    private boolean isContainerMounted(String localId) throws RemoteException {
125        Assert.assertTrue(isMediaMounted());
126        String fullId = "com.android.unittests.AsecTests." + localId;
127
128        IMountService ms = getMs();
129        return ms.isSecureContainerMounted(fullId);
130    }
131
132    private IMountService getMs() {
133        IBinder service = ServiceManager.getService("mount");
134        if (service != null) {
135            return IMountService.Stub.asInterface(service);
136        } else {
137            Log.e(TAG, "Can't get mount service");
138        }
139        return null;
140    }
141
142    private boolean isMediaMounted() {
143        try {
144        String mPath = Environment.getExternalStorageDirectory().toString();
145        String state = getMs().getVolumeState(mPath);
146        return Environment.MEDIA_MOUNTED.equals(state);
147        } catch (RemoteException e) {
148            failStr(e);
149            return false;
150        }
151    }
152
153    public void testCreateContainer() {
154        try {
155            Assert.assertEquals(StorageResultCode.OperationSucceeded,
156                    createContainer("testCreateContainer", 4, "none"));
157            Assert.assertEquals(true, containerExists("testCreateContainer"));
158        } catch (Exception e) {
159            failStr(e);
160        }
161    }
162
163    public void testCreateMinSizeContainer() {
164        try {
165            Assert.assertEquals(StorageResultCode.OperationSucceeded,
166                    createContainer("testCreateContainer", 1, "none"));
167            Assert.assertEquals(true, containerExists("testCreateContainer"));
168        } catch (Exception e) {
169            failStr(e);
170        }
171    }
172
173    public void testCreateZeroSizeContainer() {
174        try {
175            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
176                    createContainer("testCreateZeroContainer", 0, "none"));
177        } catch (Exception e) {
178            failStr(e);
179        }
180    }
181
182    public void testCreateDuplicateContainer() {
183        try {
184            Assert.assertEquals(StorageResultCode.OperationSucceeded,
185                    createContainer("testCreateDupContainer", 4, "none"));
186
187            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
188                    createContainer("testCreateDupContainer", 4, "none"));
189        } catch (Exception e) {
190            failStr(e);
191        }
192    }
193
194    public void testDestroyContainer() {
195        try {
196            Assert.assertEquals(StorageResultCode.OperationSucceeded,
197                    createContainer("testDestroyContainer", 4, "none"));
198            Assert.assertEquals(StorageResultCode.OperationSucceeded,
199                    destroyContainer("testDestroyContainer", false));
200        } catch (Exception e) {
201            failStr(e);
202        }
203    }
204
205    public void testMountContainer() {
206        try {
207            Assert.assertEquals(StorageResultCode.OperationSucceeded,
208                    createContainer("testMountContainer", 4, "none"));
209
210            Assert.assertEquals(StorageResultCode.OperationSucceeded,
211                    unmountContainer("testMountContainer", false));
212
213            Assert.assertEquals(StorageResultCode.OperationSucceeded,
214                    mountContainer("testMountContainer", "none"));
215        } catch (Exception e) {
216            failStr(e);
217        }
218    }
219
220    public void testMountBadKey() {
221        try {
222            Assert.assertEquals(StorageResultCode.OperationSucceeded,
223                    createContainer("testMountBadKey", 4, "00000000000000000000000000000000"));
224
225            Assert.assertEquals(StorageResultCode.OperationSucceeded,
226                    unmountContainer("testMountBadKey", false));
227
228            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
229                    mountContainer("testMountContainer", "000000000000000000000000000000001"));
230
231            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
232                    mountContainer("testMountContainer", "none"));
233        } catch (Exception e) {
234            failStr(e);
235        }
236    }
237
238    public void testNonExistPath() {
239        IMountService ms = getMs();
240        try {
241            String path = ms.getSecureContainerPath("jparks.broke.it");
242            failStr(path);
243        } catch (IllegalArgumentException e) {
244        } catch (Exception e) {
245            failStr(e);
246        }
247    }
248
249    public void testUnmountBusyContainer() {
250        IMountService ms = getMs();
251        try {
252            Assert.assertEquals(StorageResultCode.OperationSucceeded,
253                    createContainer("testUnmountBusyContainer", 4, "none"));
254
255            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer");
256
257            File f = new File(path, "reference");
258            FileOutputStream fos = new FileOutputStream(f);
259
260            Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy,
261                    unmountContainer("testUnmountBusyContainer", false));
262
263            fos.close();
264            Assert.assertEquals(StorageResultCode.OperationSucceeded,
265                    unmountContainer("testUnmountBusyContainer", false));
266        } catch (Exception e) {
267            failStr(e);
268        }
269    }
270
271    public void testDestroyBusyContainer() {
272        IMountService ms = getMs();
273        try {
274            Assert.assertEquals(StorageResultCode.OperationSucceeded,
275                    createContainer("testDestroyBusyContainer", 4, "none"));
276
277            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testDestroyBusyContainer");
278
279            File f = new File(path, "reference");
280            FileOutputStream fos = new FileOutputStream(f);
281
282            Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy,
283                    destroyContainer("testDestroyBusyContainer", false));
284
285            fos.close();
286            Assert.assertEquals(StorageResultCode.OperationSucceeded,
287                    destroyContainer("testDestroyBusyContainer", false));
288        } catch (Exception e) {
289            failStr(e);
290        }
291    }
292
293    public void testRenameContainer() {
294        try {
295            Assert.assertEquals(StorageResultCode.OperationSucceeded,
296                    createContainer("testRenameContainer.1", 4, "none"));
297
298            Assert.assertEquals(StorageResultCode.OperationSucceeded,
299                    unmountContainer("testRenameContainer.1", false));
300
301            Assert.assertEquals(StorageResultCode.OperationSucceeded,
302                    renameContainer("testRenameContainer.1", "testRenameContainer.2"));
303
304            Assert.assertEquals(false, containerExists("testRenameContainer.1"));
305            Assert.assertEquals(true, containerExists("testRenameContainer.2"));
306        } catch (Exception e) {
307            failStr(e);
308        }
309    }
310
311    public void testRenameSrcMountedContainer() {
312        try {
313            Assert.assertEquals(StorageResultCode.OperationSucceeded,
314                    createContainer("testRenameContainer.1", 4, "none"));
315
316            Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
317                    renameContainer("testRenameContainer.1", "testRenameContainer.2"));
318        } catch (Exception e) {
319            failStr(e);
320        }
321    }
322
323    public void testRenameDstMountedContainer() {
324        try {
325            Assert.assertEquals(StorageResultCode.OperationSucceeded,
326                    createContainer("testRenameContainer.1", 4, "none"));
327
328            Assert.assertEquals(StorageResultCode.OperationSucceeded,
329                    unmountContainer("testRenameContainer.1", false));
330
331            Assert.assertEquals(StorageResultCode.OperationSucceeded,
332                    createContainer("testRenameContainer.2", 4, "none"));
333
334            Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
335                    renameContainer("testRenameContainer.1", "testRenameContainer.2"));
336        } catch (Exception e) {
337            failStr(e);
338        }
339    }
340
341    public void testContainerSize() {
342        IMountService ms = getMs();
343        try {
344            Assert.assertEquals(StorageResultCode.OperationSucceeded,
345                    createContainer("testContainerSize", 1, "none"));
346            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer");
347
348            byte[] buf = new byte[4096];
349            File f = new File(path, "reference");
350            FileOutputStream fos = new FileOutputStream(f);
351            for (int i = 0; i < (1024 * 1024); i+= buf.length) {
352                fos.write(buf);
353            }
354            fos.close();
355        } catch (Exception e) {
356            failStr(e);
357        }
358    }
359
360    /*------------ Tests for unmounting volume ---*/
361    public final long MAX_WAIT_TIME=120*1000;
362    public final long WAIT_TIME_INCR=20*1000;
363    boolean getMediaState() {
364        try {
365        String mPath = Environment.getExternalStorageDirectory().toString();
366        String state = getMs().getVolumeState(mPath);
367        return Environment.MEDIA_MOUNTED.equals(state);
368        } catch (RemoteException e) {
369            return false;
370        }
371    }
372
373    boolean mountMedia() {
374        if (getMediaState()) {
375            return true;
376        }
377        try {
378        String mPath = Environment.getExternalStorageDirectory().toString();
379        int ret = getMs().mountVolume(mPath);
380        return ret == StorageResultCode.OperationSucceeded;
381        } catch (RemoteException e) {
382            return false;
383        }
384    }
385
386    class StorageListener extends StorageEventListener {
387        String oldState;
388        String newState;
389        String path;
390        private boolean doneFlag = false;
391
392        public void action() {
393            synchronized (this) {
394                doneFlag = true;
395                notifyAll();
396            }
397        }
398
399        public boolean isDone() {
400            return doneFlag;
401        }
402
403        @Override
404        public void onStorageStateChanged(String path, String oldState, String newState) {
405            if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState);
406            this.oldState = oldState;
407            this.newState = newState;
408            this.path = path;
409            action();
410        }
411    }
412
413    private boolean unmountMedia() {
414        if (!getMediaState()) {
415            return true;
416        }
417        String path = Environment.getExternalStorageDirectory().toString();
418        StorageListener observer = new StorageListener();
419        StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
420        sm.registerListener(observer);
421        try {
422            // Wait on observer
423            synchronized(observer) {
424                getMs().unmountVolume(path, false);
425                long waitTime = 0;
426                while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
427                    observer.wait(WAIT_TIME_INCR);
428                    waitTime += WAIT_TIME_INCR;
429                }
430                if(!observer.isDone()) {
431                    throw new Exception("Timed out waiting for packageInstalled callback");
432                }
433                return true;
434            }
435        } catch (Exception e) {
436            return false;
437        } finally {
438            sm.unregisterListener(observer);
439        }
440    }
441    public void testUnmount() {
442        boolean oldStatus = getMediaState();
443        Log.i(TAG, "oldStatus="+oldStatus);
444        try {
445            // Mount media firsts
446            if (!getMediaState()) {
447                mountMedia();
448            }
449            assertTrue(unmountMedia());
450        } finally {
451            // Restore old status
452            boolean currStatus = getMediaState();
453            if (oldStatus != currStatus) {
454                if (oldStatus) {
455                    // Mount media
456                    mountMedia();
457                } else {
458                    unmountMedia();
459                }
460            }
461        }
462    }
463
464    class MultipleStorageLis extends StorageListener {
465        int count = 0;
466        public void onStorageStateChanged(String path, String oldState, String newState) {
467            count++;
468            super.action();
469        }
470    }
471    /*
472     * This test invokes unmount multiple time and expects the call back
473     * to be invoked just once.
474     */
475    public void testUnmountMultiple() {
476        boolean oldStatus = getMediaState();
477        StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
478        MultipleStorageLis observer = new MultipleStorageLis();
479        try {
480            // Mount media firsts
481            if (!getMediaState()) {
482                mountMedia();
483            }
484            String path = Environment.getExternalStorageDirectory().toString();
485            sm.registerListener(observer);
486            // Wait on observer
487            synchronized(observer) {
488                for (int i = 0; i < 5; i++) {
489                    getMs().unmountVolume(path, false);
490                }
491                long waitTime = 0;
492                while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
493                    observer.wait(WAIT_TIME_INCR);
494                    waitTime += WAIT_TIME_INCR;
495                }
496                if(!observer.isDone()) {
497                    failStr("Timed out waiting for packageInstalled callback");
498                }
499            }
500            assertEquals(observer.count, 1);
501        } catch (Exception e) {
502            failStr(e);
503        } finally {
504            sm.unregisterListener(observer);
505            // Restore old status
506            boolean currStatus = getMediaState();
507            if (oldStatus != currStatus) {
508                if (oldStatus) {
509                    // Mount media
510                    mountMedia();
511                } else {
512                    unmountMedia();
513                }
514            }
515        }
516    }
517
518    class ShutdownObserver extends  IMountShutdownObserver.Stub{
519        private boolean doneFlag = false;
520        int statusCode;
521
522        public void action() {
523            synchronized (this) {
524                doneFlag = true;
525                notifyAll();
526            }
527        }
528
529        public boolean isDone() {
530            return doneFlag;
531        }
532        public void onShutDownComplete(int statusCode) throws RemoteException {
533            this.statusCode = statusCode;
534            action();
535        }
536
537    }
538
539    boolean invokeShutdown() {
540        IMountService ms = getMs();
541        ShutdownObserver observer = new ShutdownObserver();
542        synchronized (observer) {
543            try {
544                ms.shutdown(observer);
545                return true;
546            } catch (RemoteException e) {
547                failStr(e);
548            }
549        }
550        return false;
551    }
552
553    public void testShutdown() {
554        boolean oldStatus = getMediaState();
555        try {
556            // Mount media firsts
557            if (!getMediaState()) {
558                mountMedia();
559            }
560            assertTrue(invokeShutdown());
561        } finally {
562            // Restore old status
563            boolean currStatus = getMediaState();
564            if (oldStatus != currStatus) {
565                if (oldStatus) {
566                    // Mount media
567                    mountMedia();
568                } else {
569                    unmountMedia();
570                }
571            }
572        }
573    }
574
575    /*
576     * This test invokes unmount multiple time and expects the call back
577     * to be invoked just once.
578     */
579    public void testShutdownMultiple() {
580        boolean oldStatus = getMediaState();
581        try {
582            // Mount media firsts
583            if (!getMediaState()) {
584                mountMedia();
585            }
586            IMountService ms = getMs();
587            ShutdownObserver observer = new ShutdownObserver();
588            synchronized (observer) {
589                try {
590                    ms.shutdown(observer);
591                    for (int i = 0; i < 4; i++) {
592                        ms.shutdown(null);
593                    }
594                } catch (RemoteException e) {
595                    failStr(e);
596                }
597            }
598        } finally {
599            // Restore old status
600            boolean currStatus = getMediaState();
601            if (oldStatus != currStatus) {
602                if (oldStatus) {
603                    // Mount media
604                    mountMedia();
605                } else {
606                    unmountMedia();
607                }
608            }
609        }
610    }
611
612}
613