Home | History | Annotate | Download | only in server
      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
     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