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