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