blob: eac4405a481932f11a72f8748fdda3c56801f833 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts.externalstorageapp;
import android.content.Context;
import android.os.Environment;
import android.test.AndroidTestCase;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Tests common functionality that should be supported regardless of external
* storage status.
*/
public class CommonExternalStorageTest extends AndroidTestCase {
public static final String TAG = "CommonExternalStorageTest";
public static final String PACKAGE_NONE = "com.android.cts.externalstorageapp";
public static final String PACKAGE_READ = "com.android.cts.readexternalstorageapp";
public static final String PACKAGE_WRITE = "com.android.cts.writeexternalstorageapp";
/**
* Dump helpful debugging details.
*/
public void testDumpDebug() throws Exception {
logCommand("/system/bin/id");
logCommand("/system/bin/cat", "/proc/self/mountinfo");
}
/**
* Primary storage must always be mounted.
*/
public void testExternalStorageMounted() {
assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
}
/**
* Verify that single path is always first item in multiple.
*/
public void testMultipleCacheDirs() throws Exception {
final File single = getContext().getExternalCacheDir();
assertNotNull("Primary storage must always be available", single);
final File firstMultiple = getContext().getExternalCacheDirs()[0];
assertEquals(single, firstMultiple);
}
/**
* Verify that single path is always first item in multiple.
*/
public void testMultipleFilesDirs() throws Exception {
final File single = getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
assertNotNull("Primary storage must always be available", single);
final File firstMultiple = getContext()
.getExternalFilesDirs(Environment.DIRECTORY_PICTURES)[0];
assertEquals(single, firstMultiple);
}
/**
* Verify that single path is always first item in multiple.
*/
public void testMultipleObbDirs() throws Exception {
final File single = getContext().getObbDir();
assertNotNull("Primary storage must always be available", single);
final File firstMultiple = getContext().getObbDirs()[0];
assertEquals(single, firstMultiple);
}
/**
* Verify we can write to our own package dirs.
*/
public void testAllPackageDirsWritable() throws Exception {
final List<File> paths = getAllPackageSpecificPaths(getContext());
for (File path : paths) {
assertNotNull("Valid media must be inserted during CTS", path);
assertEquals("Valid media must be inserted during CTS", Environment.MEDIA_MOUNTED,
Environment.getStorageState(path));
assertDirReadWriteAccess(path);
final File directChild = new File(path, "directChild");
final File subdir = new File(path, "subdir");
final File subdirChild = new File(path, "subdirChild");
writeInt(directChild, 32);
subdir.mkdirs();
assertDirReadWriteAccess(subdir);
writeInt(subdirChild, 64);
assertEquals(32, readInt(directChild));
assertEquals(64, readInt(subdirChild));
}
for (File path : paths) {
deleteContents(path);
}
}
/**
* Return a set of several package-specific external storage paths.
*/
public static List<File> getAllPackageSpecificPaths(Context context) {
final List<File> paths = new ArrayList<File>();
Collections.addAll(paths, context.getExternalCacheDirs());
Collections.addAll(paths, context.getExternalFilesDirs(null));
Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES));
Collections.addAll(paths, context.getObbDirs());
return paths;
}
public static List<File> getAllPackageSpecificPathsExceptObb(Context context) {
final List<File> paths = new ArrayList<File>();
Collections.addAll(paths, context.getExternalCacheDirs());
Collections.addAll(paths, context.getExternalFilesDirs(null));
Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES));
return paths;
}
public static List<File> getPrimaryPackageSpecificPaths(Context context) {
final List<File> paths = new ArrayList<File>();
Collections.addAll(paths, context.getExternalCacheDir());
Collections.addAll(paths, context.getExternalFilesDir(null));
Collections.addAll(paths, context.getExternalFilesDir(Environment.DIRECTORY_PICTURES));
Collections.addAll(paths, context.getObbDir());
return paths;
}
public static List<File> getSecondaryPackageSpecificPaths(Context context) {
final List<File> paths = new ArrayList<File>();
Collections.addAll(paths, dropFirst(context.getExternalCacheDirs()));
Collections.addAll(paths, dropFirst(context.getExternalFilesDirs(null)));
Collections.addAll(
paths, dropFirst(context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES)));
Collections.addAll(paths, dropFirst(context.getObbDirs()));
return paths;
}
private static File[] dropFirst(File[] before) {
final File[] after = new File[before.length - 1];
System.arraycopy(before, 1, after, 0, after.length);
return after;
}
public static File buildGiftForPackage(Context context, String packageName) {
final File myCache = context.getExternalCacheDir();
return new File(myCache.getAbsolutePath().replace(context.getPackageName(), packageName),
packageName + ".gift");
}
public static File buildProbeFile(File dir) {
return new File(dir, ".probe_" + System.nanoTime());
}
public static void assertDirReadOnlyAccess(File path) {
Log.d(TAG, "Asserting read-only access to " + path);
assertTrue("exists", path.exists());
assertTrue("read", path.canRead());
assertTrue("execute", path.canExecute());
assertNotNull("list", path.list());
try {
final File probe = buildProbeFile(path);
probe.createNewFile();
probe.delete();
fail("able to create probe!");
} catch (IOException e) {
// expected
}
}
public static void assertDirReadWriteAccess(File path) {
Log.d(TAG, "Asserting read/write access to " + path);
assertTrue("exists", path.exists());
assertTrue("read", path.canRead());
assertTrue("execute", path.canExecute());
assertNotNull("list", path.list());
try {
final File probe = buildProbeFile(path);
probe.createNewFile();
probe.delete();
} catch (IOException e) {
fail("failed to create probe!");
}
}
public static void assertDirNoAccess(File path) {
Log.d(TAG, "Asserting no access to " + path);
assertFalse("read", path.canRead());
assertNull("list", path.list());
try {
final File probe = buildProbeFile(path);
probe.createNewFile();
probe.delete();
fail("able to create probe!");
} catch (IOException e) {
// expected
}
}
public static void assertDirNoWriteAccess(File path) {
Log.d(TAG, "Asserting no write access to " + path);
try {
final File probe = buildProbeFile(path);
probe.createNewFile();
probe.delete();
fail("able to create probe!");
} catch (IOException e) {
// expected
}
}
public static void assertFileReadOnlyAccess(File path) {
try {
new FileInputStream(path).close();
} catch (IOException e) {
fail("failed to read!");
}
try {
new FileOutputStream(path, true).close();
fail("able to write!");
} catch (IOException e) {
// expected
}
}
public static void assertFileReadWriteAccess(File path) {
try {
new FileInputStream(path).close();
} catch (IOException e) {
fail("failed to read!");
}
try {
new FileOutputStream(path, true).close();
} catch (IOException e) {
fail("failed to write!");
}
}
public static void assertFileNoAccess(File path) {
try {
new FileInputStream(path).close();
fail("able to read!");
} catch (IOException e) {
// expected
}
try {
new FileOutputStream(path, true).close();
fail("able to write!");
} catch (IOException e) {
// expected
}
}
private static boolean isWhiteList(File file) {
final String[] whiteLists = {
"autorun.inf", ".android_secure", "android_secure"
};
if (file.getParentFile().getAbsolutePath().equals(
Environment.getExternalStorageDirectory().getAbsolutePath())) {
for (String whiteList : whiteLists) {
if (file.getName().equalsIgnoreCase(whiteList)) {
return true;
}
}
}
return false;
}
private static File[] removeWhiteList(File[] files) {
List<File> fileList = new ArrayList<File>();
if (files == null) {
return null;
}
for (File file : files) {
if (!isWhiteList(file)) {
fileList.add(file);
}
}
return fileList.toArray(new File[fileList.size()]);
}
public static void deleteContents(File dir) throws IOException {
File[] files = dir.listFiles();
files = removeWhiteList(files);
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
deleteContents(file);
}
assertTrue(file.delete());
}
File[] dirs = removeWhiteList(dir.listFiles());
assertEquals(0, dirs.length);
}
}
public static void writeInt(File file, int value) throws IOException {
final DataOutputStream os = new DataOutputStream(new FileOutputStream(file));
try {
os.writeInt(value);
} finally {
os.close();
}
}
public static int readInt(File file) throws IOException {
final DataInputStream is = new DataInputStream(new FileInputStream(file));
try {
return is.readInt();
} finally {
is.close();
}
}
private static void logCommand(String... cmd) throws Exception {
final Process proc = new ProcessBuilder(cmd).redirectErrorStream(true).start();
final ByteArrayOutputStream buf = new ByteArrayOutputStream();
copy(proc.getInputStream(), buf);
final int res = proc.waitFor();
Log.d(TAG, Arrays.toString(cmd) + " result " + res + ":");
Log.d(TAG, buf.toString());
}
/** Shamelessly lifted from libcore.io.Streams */
public static int copy(InputStream in, OutputStream out) throws IOException {
int total = 0;
byte[] buffer = new byte[8192];
int c;
while ((c = in.read(buffer)) != -1) {
total += c;
out.write(buffer, 0, c);
}
return total;
}
}