1 /* 2 * Copyright (C) 2012 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.cts.externalstorageapp; 18 19 import android.content.Context; 20 import android.os.Environment; 21 import android.test.AndroidTestCase; 22 import android.util.Log; 23 24 import java.io.DataInputStream; 25 import java.io.DataOutputStream; 26 import java.io.File; 27 import java.io.FileInputStream; 28 import java.io.FileOutputStream; 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 34 /** 35 * Tests common functionality that should be supported regardless of external 36 * storage status. 37 */ 38 public class CommonExternalStorageTest extends AndroidTestCase { 39 public static final String TAG = "CommonExternalStorageTest"; 40 41 public static final String PACKAGE_NONE = "com.android.cts.externalstorageapp"; 42 public static final String PACKAGE_READ = "com.android.cts.readexternalstorageapp"; 43 public static final String PACKAGE_WRITE = "com.android.cts.writeexternalstorageapp"; 44 45 /** 46 * Primary storage must always be mounted. 47 */ 48 public void testExternalStorageMounted() { 49 assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState()); 50 } 51 52 /** 53 * Verify that single path is always first item in multiple. 54 */ 55 public void testMultipleCacheDirs() throws Exception { 56 final File single = getContext().getExternalCacheDir(); 57 assertNotNull("Primary storage must always be available", single); 58 final File firstMultiple = getContext().getExternalCacheDirs()[0]; 59 assertEquals(single, firstMultiple); 60 } 61 62 /** 63 * Verify that single path is always first item in multiple. 64 */ 65 public void testMultipleFilesDirs() throws Exception { 66 final File single = getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES); 67 assertNotNull("Primary storage must always be available", single); 68 final File firstMultiple = getContext() 69 .getExternalFilesDirs(Environment.DIRECTORY_PICTURES)[0]; 70 assertEquals(single, firstMultiple); 71 } 72 73 /** 74 * Verify that single path is always first item in multiple. 75 */ 76 public void testMultipleObbDirs() throws Exception { 77 final File single = getContext().getObbDir(); 78 assertNotNull("Primary storage must always be available", single); 79 final File firstMultiple = getContext().getObbDirs()[0]; 80 assertEquals(single, firstMultiple); 81 } 82 83 /** 84 * Verify we can write to our own package dirs. 85 */ 86 public void testAllPackageDirsWritable() throws Exception { 87 final List<File> paths = getAllPackageSpecificPaths(getContext()); 88 for (File path : paths) { 89 assertNotNull("Valid media must be inserted during CTS", path); 90 assertEquals("Valid media must be inserted during CTS", Environment.MEDIA_MOUNTED, 91 Environment.getStorageState(path)); 92 93 assertDirReadWriteAccess(path); 94 95 final File directChild = new File(path, "directChild"); 96 final File subdir = new File(path, "subdir"); 97 final File subdirChild = new File(path, "subdirChild"); 98 99 writeInt(directChild, 32); 100 subdir.mkdirs(); 101 assertDirReadWriteAccess(subdir); 102 writeInt(subdirChild, 64); 103 104 assertEquals(32, readInt(directChild)); 105 assertEquals(64, readInt(subdirChild)); 106 } 107 108 for (File path : paths) { 109 deleteContents(path); 110 } 111 } 112 113 /** 114 * Return a set of several package-specific external storage paths. 115 */ 116 public static List<File> getAllPackageSpecificPaths(Context context) { 117 final List<File> paths = new ArrayList<File>(); 118 Collections.addAll(paths, context.getExternalCacheDirs()); 119 Collections.addAll(paths, context.getExternalFilesDirs(null)); 120 Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES)); 121 Collections.addAll(paths, context.getObbDirs()); 122 return paths; 123 } 124 125 public static List<File> getAllPackageSpecificPathsExceptObb(Context context) { 126 final List<File> paths = new ArrayList<File>(); 127 Collections.addAll(paths, context.getExternalCacheDirs()); 128 Collections.addAll(paths, context.getExternalFilesDirs(null)); 129 Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES)); 130 return paths; 131 } 132 133 public static List<File> getPrimaryPackageSpecificPaths(Context context) { 134 final List<File> paths = new ArrayList<File>(); 135 Collections.addAll(paths, context.getExternalCacheDir()); 136 Collections.addAll(paths, context.getExternalFilesDir(null)); 137 Collections.addAll(paths, context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)); 138 Collections.addAll(paths, context.getObbDir()); 139 return paths; 140 } 141 142 public static List<File> getSecondaryPackageSpecificPaths(Context context) { 143 final List<File> paths = new ArrayList<File>(); 144 Collections.addAll(paths, dropFirst(context.getExternalCacheDirs())); 145 Collections.addAll(paths, dropFirst(context.getExternalFilesDirs(null))); 146 Collections.addAll( 147 paths, dropFirst(context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES))); 148 Collections.addAll(paths, dropFirst(context.getObbDirs())); 149 return paths; 150 } 151 152 private static File[] dropFirst(File[] before) { 153 final File[] after = new File[before.length - 1]; 154 System.arraycopy(before, 1, after, 0, after.length); 155 return after; 156 } 157 158 public static File buildGiftForPackage(Context context, String packageName) { 159 final File myCache = context.getExternalCacheDir(); 160 return new File(myCache.getAbsolutePath().replace(context.getPackageName(), packageName), 161 packageName + ".gift"); 162 } 163 164 public static File buildProbeFile(File dir) { 165 return new File(dir, ".probe_" + System.nanoTime()); 166 } 167 168 public static void assertDirReadOnlyAccess(File path) { 169 Log.d(TAG, "Asserting read-only access to " + path); 170 171 assertTrue("exists", path.exists()); 172 assertTrue("read", path.canRead()); 173 assertTrue("execute", path.canExecute()); 174 assertNotNull("list", path.list()); 175 176 try { 177 final File probe = buildProbeFile(path); 178 probe.createNewFile(); 179 probe.delete(); 180 fail("able to create probe!"); 181 } catch (IOException e) { 182 // expected 183 } 184 } 185 186 public static void assertDirReadWriteAccess(File path) { 187 Log.d(TAG, "Asserting read/write access to " + path); 188 189 assertTrue("exists", path.exists()); 190 assertTrue("read", path.canRead()); 191 assertTrue("execute", path.canExecute()); 192 assertNotNull("list", path.list()); 193 194 try { 195 final File probe = buildProbeFile(path); 196 probe.createNewFile(); 197 probe.delete(); 198 } catch (IOException e) { 199 fail("failed to create probe!"); 200 } 201 } 202 203 public static void assertDirNoAccess(File path) { 204 Log.d(TAG, "Asserting no access to " + path); 205 206 assertFalse("read", path.canRead()); 207 assertNull("list", path.list()); 208 209 try { 210 final File probe = buildProbeFile(path); 211 probe.createNewFile(); 212 probe.delete(); 213 fail("able to create probe!"); 214 } catch (IOException e) { 215 // expected 216 } 217 } 218 219 public static void assertDirNoWriteAccess(File path) { 220 Log.d(TAG, "Asserting no write access to " + path); 221 222 try { 223 final File probe = buildProbeFile(path); 224 probe.createNewFile(); 225 probe.delete(); 226 fail("able to create probe!"); 227 } catch (IOException e) { 228 // expected 229 } 230 } 231 232 public static void assertFileReadOnlyAccess(File path) { 233 try { 234 new FileInputStream(path).close(); 235 } catch (IOException e) { 236 fail("failed to read!"); 237 } 238 239 try { 240 new FileOutputStream(path, true).close(); 241 fail("able to write!"); 242 } catch (IOException e) { 243 // expected 244 } 245 } 246 247 public static void assertFileReadWriteAccess(File path) { 248 try { 249 new FileInputStream(path).close(); 250 } catch (IOException e) { 251 fail("failed to read!"); 252 } 253 254 try { 255 new FileOutputStream(path, true).close(); 256 } catch (IOException e) { 257 fail("failed to write!"); 258 } 259 } 260 261 public static void assertFileNoAccess(File path) { 262 try { 263 new FileInputStream(path).close(); 264 fail("able to read!"); 265 } catch (IOException e) { 266 // expected 267 } 268 269 try { 270 new FileOutputStream(path, true).close(); 271 fail("able to write!"); 272 } catch (IOException e) { 273 // expected 274 } 275 } 276 277 private static boolean isWhiteList(File file) { 278 final String[] whiteLists = { 279 "autorun.inf", ".android_secure", "android_secure" 280 }; 281 if (file.getParentFile().getAbsolutePath().equals( 282 Environment.getExternalStorageDirectory().getAbsolutePath())) { 283 for (String whiteList : whiteLists) { 284 if (file.getName().equalsIgnoreCase(whiteList)) { 285 return true; 286 } 287 } 288 } 289 return false; 290 } 291 292 private static File[] removeWhiteList(File[] files) { 293 List<File> fileList = new ArrayList<File>(); 294 if (files == null) { 295 return null; 296 } 297 298 for (File file : files) { 299 if (!isWhiteList(file)) { 300 fileList.add(file); 301 } 302 } 303 return fileList.toArray(new File[fileList.size()]); 304 } 305 306 public static void deleteContents(File dir) throws IOException { 307 File[] files = dir.listFiles(); 308 files = removeWhiteList(files); 309 if (files != null) { 310 for (File file : files) { 311 if (file.isDirectory()) { 312 deleteContents(file); 313 } 314 assertTrue(file.delete()); 315 } 316 317 File[] dirs = removeWhiteList(dir.listFiles()); 318 assertEquals(0, dirs.length); 319 } 320 } 321 322 public static void writeInt(File file, int value) throws IOException { 323 final DataOutputStream os = new DataOutputStream(new FileOutputStream(file)); 324 try { 325 os.writeInt(value); 326 } finally { 327 os.close(); 328 } 329 } 330 331 public static int readInt(File file) throws IOException { 332 final DataInputStream is = new DataInputStream(new FileInputStream(file)); 333 try { 334 return is.readInt(); 335 } finally { 336 is.close(); 337 } 338 } 339 } 340