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 android.os.storage; 18 19import android.content.Context; 20import android.os.Environment; 21import android.os.ProxyFileDescriptorCallback; 22import android.os.ParcelFileDescriptor; 23import android.system.ErrnoException; 24import android.system.Os; 25import android.test.InstrumentationTestCase; 26import android.test.suitebuilder.annotation.LargeTest; 27import android.test.suitebuilder.annotation.Suppress; 28import android.util.Log; 29 30import com.android.frameworks.coretests.R; 31import com.android.internal.os.FuseAppLoop; 32import java.io.DataInputStream; 33import java.io.IOException; 34import java.util.concurrent.ThreadFactory; 35import java.io.File; 36import java.io.FileInputStream; 37 38import junit.framework.AssertionFailedError; 39 40public class StorageManagerIntegrationTest extends StorageManagerBaseTest { 41 42 private static String LOG_TAG = "StorageManagerBaseTest.StorageManagerIntegrationTest"; 43 protected File mFile = null; 44 45 /** 46 * {@inheritDoc} 47 */ 48 @Override 49 public void setUp() throws Exception { 50 super.setUp(); 51 mContext = getInstrumentation().getContext(); 52 mFile = null; 53 } 54 55 /** 56 * {@inheritDoc} 57 */ 58 @Override 59 protected void tearDown() throws Exception { 60 if (mFile != null) { 61 mFile.delete(); 62 mFile = null; 63 } 64 super.tearDown(); 65 } 66 67 /** 68 * Tests mounting a single OBB file and verifies its contents. 69 */ 70 @LargeTest 71 public void testMountSingleObb() { 72 mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); 73 String filePath = mFile.getAbsolutePath(); 74 mountObb(filePath); 75 verifyObb1Contents(filePath); 76 unmountObb(filePath, DONT_FORCE); 77 } 78 79 /** 80 * Tests mounting several OBB files and verifies its contents. 81 */ 82 @LargeTest 83 public void testMountMultipleObb() { 84 File file1 = null; 85 File file2 = null; 86 File file3 = null; 87 try { 88 file1 = createObbFile(OBB_FILE_1, R.raw.obb_file1); 89 String filePath1 = file1.getAbsolutePath(); 90 mountObb(filePath1); 91 verifyObb1Contents(filePath1); 92 93 file2 = createObbFile(OBB_FILE_2, R.raw.obb_file2); 94 String filePath2 = file2.getAbsolutePath(); 95 mountObb(filePath2); 96 verifyObb2Contents(filePath2); 97 98 file3 = createObbFile(OBB_FILE_3, R.raw.obb_file3); 99 String filePath3 = file3.getAbsolutePath(); 100 mountObb(filePath3); 101 verifyObb3Contents(filePath3); 102 103 unmountObb(filePath1, DONT_FORCE); 104 unmountObb(filePath2, DONT_FORCE); 105 unmountObb(filePath3, DONT_FORCE); 106 } finally { 107 if (file1 != null) { 108 file1.delete(); 109 } 110 if (file2 != null) { 111 file2.delete(); 112 } 113 if (file3 != null) { 114 file3.delete(); 115 } 116 } 117 } 118 119 /** 120 * Tests mounting a single encrypted OBB file and verifies its contents. 121 */ 122 @LargeTest 123 public void testMountSingleEncryptedObb() { 124 mFile = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3); 125 String filePath = mFile.getAbsolutePath(); 126 mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED); 127 verifyObb3Contents(filePath); 128 unmountObb(filePath, DONT_FORCE); 129 } 130 131 /** 132 * Tests mounting a single encrypted OBB file using an invalid password. 133 */ 134 @LargeTest 135 @Suppress // Failing. 136 public void testMountSingleEncryptedObbInvalidPassword() { 137 mFile = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3); 138 String filePath = mFile.getAbsolutePath(); 139 mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 140 unmountObb(filePath, DONT_FORCE); 141 } 142 143 /** 144 * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents. 145 */ 146 @LargeTest 147 public void testMountTwoEncryptedObb() { 148 File file3 = null; 149 File file1 = null; 150 try { 151 file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3); 152 String filePath3 = file3.getAbsolutePath(); 153 mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED); 154 verifyObb3Contents(filePath3); 155 156 file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1); 157 String filePath1 = file1.getAbsolutePath(); 158 mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED); 159 verifyObb1Contents(filePath1); 160 161 unmountObb(filePath3, DONT_FORCE); 162 unmountObb(filePath1, DONT_FORCE); 163 } finally { 164 if (file3 != null) { 165 file3.delete(); 166 } 167 if (file1 != null) { 168 file1.delete(); 169 } 170 } 171 } 172 173 /** 174 * Tests that we can not force unmount when a file is currently open on the OBB. 175 */ 176 @LargeTest 177 public void testUnmount_DontForce() { 178 mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); 179 String obbFilePath = mFile.getAbsolutePath(); 180 181 MountingObbThread mountingThread = new MountingObbThread(obbFilePath, 182 OBB_FILE_1_CONTENTS_1); 183 184 try { 185 mountingThread.start(); 186 187 long waitTime = 0; 188 while (!mountingThread.isFileOpenOnObb()) { 189 synchronized (mountingThread) { 190 Log.i(LOG_TAG, "Waiting for file to be opened on OBB..."); 191 mountingThread.wait(WAIT_TIME_INCR); 192 waitTime += WAIT_TIME_INCR; 193 if (waitTime > MAX_WAIT_TIME) { 194 fail("Timed out waiting for file file to be opened on OBB!"); 195 } 196 } 197 } 198 199 unmountObb(obbFilePath, DONT_FORCE); 200 201 // verify still mounted 202 assertTrue("mounted path should not be null!", obbFilePath != null); 203 assertTrue("mounted path should still be mounted!", mSm.isObbMounted(obbFilePath)); 204 205 // close the opened file 206 mountingThread.doStop(); 207 208 // try unmounting again (should succeed this time) 209 unmountObb(obbFilePath, DONT_FORCE); 210 assertFalse("mounted path should no longer be mounted!", 211 mSm.isObbMounted(obbFilePath)); 212 } catch (InterruptedException e) { 213 fail("Timed out waiting for file on OBB to be opened..."); 214 } 215 } 216 217 /** 218 * Tests mounting a single OBB that isn't signed. 219 */ 220 @LargeTest 221 public void testMountUnsignedObb() { 222 mFile = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign); 223 String filePath = mFile.getAbsolutePath(); 224 mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL); 225 } 226 227 /** 228 * Tests mounting a single OBB that is signed with a different package. 229 */ 230 @LargeTest 231 public void testMountBadPackageNameObb() { 232 mFile = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename); 233 String filePath = mFile.getAbsolutePath(); 234 mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME, 235 OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 236 } 237 238 /** 239 * Tests remounting a single OBB that has already been mounted. 240 */ 241 @LargeTest 242 public void testRemountObb() { 243 mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); 244 String filePath = mFile.getAbsolutePath(); 245 mountObb(filePath); 246 verifyObb1Contents(filePath); 247 mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 248 verifyObb1Contents(filePath); 249 unmountObb(filePath, DONT_FORCE); 250 } 251 252 @LargeTest 253 public void testOpenProxyFileDescriptor() throws Exception { 254 final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() { 255 @Override 256 public long onGetSize() throws ErrnoException { 257 return 0; 258 } 259 260 @Override 261 public void onRelease() {} 262 }; 263 264 final MyThreadFactory factory = new MyThreadFactory(); 265 int firstMountId; 266 try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor( 267 ParcelFileDescriptor.MODE_READ_ONLY, callback, null, factory)) { 268 assertNotSame(Thread.State.TERMINATED, factory.thread.getState()); 269 firstMountId = mSm.getProxyFileDescriptorMountPointId(); 270 assertNotSame(-1, firstMountId); 271 } 272 273 // After closing descriptor, the loop should terminate. 274 factory.thread.join(3000); 275 assertEquals(Thread.State.TERMINATED, factory.thread.getState()); 276 277 // StorageManager should mount another bridge on the next open request. 278 try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor( 279 ParcelFileDescriptor.MODE_WRITE_ONLY, callback, null, factory)) { 280 assertNotSame(Thread.State.TERMINATED, factory.thread.getState()); 281 assertNotSame(firstMountId, mSm.getProxyFileDescriptorMountPointId()); 282 } 283 } 284 285 private static class MyThreadFactory implements ThreadFactory { 286 Thread thread = null; 287 288 @Override 289 public Thread newThread(Runnable r) { 290 thread = new Thread(r); 291 return thread; 292 } 293 } 294}