/* * Copyright (C) 2006 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 android.os.storage; import android.content.Context; import android.os.Environment; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.test.AndroidTestCase; import android.util.Log; import java.io.File; import java.io.FileOutputStream; public class AsecTests extends AndroidTestCase { private static final String SECURE_CONTAINER_PREFIX = "com.android.unittests.AsecTests."; private static final boolean localLOGV = true; public static final String TAG="AsecTests"; private static final String FS_FAT = "fat"; private static final String FS_EXT4 = "ext4"; @Override protected void setUp() throws Exception { super.setUp(); if (localLOGV) Log.i(TAG, "Cleaning out old test containers"); cleanupContainers(); } @Override protected void tearDown() throws Exception { super.tearDown(); if (localLOGV) Log.i(TAG, "Cleaning out old test containers"); cleanupContainers(); } private void cleanupContainers() throws RemoteException { IMountService ms = getMs(); String[] containers = ms.getSecureContainerList(); for (int i = 0; i < containers.length; i++) { if (containers[i].startsWith(SECURE_CONTAINER_PREFIX)) { if (localLOGV) Log.i(TAG, "Cleaning: " + containers[i]); ms.destroySecureContainer(containers[i], true); } } } private boolean containerExists(String localId) throws RemoteException { IMountService ms = getMs(); String[] containers = ms.getSecureContainerList(); String fullId = SECURE_CONTAINER_PREFIX + localId; for (int i = 0; i < containers.length; i++) { if (containers[i].equals(fullId)) { return true; } } return false; } private int createContainer(String localId, int size, String key, String filesystem, boolean isExternal) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; IMountService ms = getMs(); return ms.createSecureContainer(fullId, size, filesystem, key, android.os.Process.myUid(), isExternal); } private int mountContainer(String localId, String key) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; IMountService ms = getMs(); return ms.mountSecureContainer(fullId, key, android.os.Process.myUid()); } private int renameContainer(String localId1, String localId2) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId1 = SECURE_CONTAINER_PREFIX + localId1; String fullId2 = SECURE_CONTAINER_PREFIX + localId2; IMountService ms = getMs(); return ms.renameSecureContainer(fullId1, fullId2); } private int unmountContainer(String localId, boolean force) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; IMountService ms = getMs(); return ms.unmountSecureContainer(fullId, force); } private int destroyContainer(String localId, boolean force) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; IMountService ms = getMs(); return ms.destroySecureContainer(fullId, force); } private boolean isContainerMounted(String localId) throws Exception { assertTrue("Media should be mounted", isMediaMounted()); String fullId = SECURE_CONTAINER_PREFIX + localId; IMountService ms = getMs(); return ms.isSecureContainerMounted(fullId); } private IMountService getMs() { IBinder service = ServiceManager.getService("mount"); if (service != null) { return IMountService.Stub.asInterface(service); } else { Log.e(TAG, "Can't get mount service"); } return null; } private boolean isMediaMounted() throws Exception { String mPath = Environment.getExternalStorageDirectory().toString(); String state = getMs().getVolumeState(mPath); return Environment.MEDIA_MOUNTED.equals(state); } /* * CREATE */ public void test_Fat_External_Create_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 4, "none", FS_FAT, true)); assertTrue(containerExists("testCreateContainer")); } public void test_Ext4_External_Create_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 4, "none", FS_EXT4, true)); assertTrue(containerExists("testCreateContainer")); } public void test_Fat_Internal_Create_Success() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 4, "none", FS_FAT, false)); assertTrue(containerExists("testCreateContainer")); } public void test_Ext4_Internal_Create_Success() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 4, "none", FS_EXT4, false)); assertTrue(containerExists("testCreateContainer")); } /* * CREATE MIN SIZE */ public void test_Fat_External_CreateMinSize_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 1, "none", FS_FAT, true)); assertTrue(containerExists("testCreateContainer")); } public void test_Ext4_External_CreateMinSize_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 1, "none", FS_EXT4, true)); assertTrue(containerExists("testCreateContainer")); } public void test_Fat_Internal_CreateMinSize_Success() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 1, "none", FS_FAT, false)); assertTrue(containerExists("testCreateContainer")); } public void test_Ext4_Internal_CreateMinSize_Success() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateContainer", 1, "none", FS_EXT4, false)); assertTrue(containerExists("testCreateContainer")); } /* * CREATE ZERO SIZE - FAIL CASE */ public void test_Fat_External_CreateZeroSize_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateZeroContainer", 0, "none", FS_FAT, true)); } public void test_Ext4_External_CreateZeroSize_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, true)); } public void test_Fat_Internal_CreateZeroSize_Failure() throws Exception { assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateZeroContainer", 0, "none", FS_FAT, false)); } public void test_Ext4_Internal_CreateZeroSize_Failure() throws Exception { assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateZeroContainer", 0, "none", FS_EXT4, false)); } /* * CREATE DUPLICATE - FAIL CASE */ public void test_Fat_External_CreateDuplicate_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateDupContainer", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateDupContainer", 4, "none", FS_FAT, true)); } public void test_Ext4_External_CreateDuplicate_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true)); assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateDupContainer", 4, "none", FS_EXT4, true)); } public void test_Fat_Internal_CreateDuplicate_Failure() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateDupContainer", 4, "none", FS_FAT, false)); assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateDupContainer", 4, "none", FS_FAT, false)); } public void test_Ext4_Internal_CreateDuplicate_Failure() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false)); assertEquals(StorageResultCode.OperationFailedInternalError, createContainer("testCreateDupContainer", 4, "none", FS_EXT4, false)); } /* * DESTROY */ public void test_Fat_External_Destroy_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testDestroyContainer", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationSucceeded, destroyContainer("testDestroyContainer", false)); } public void test_Ext4_External_Destroy_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testDestroyContainer", 4, "none", FS_EXT4, true)); assertEquals(StorageResultCode.OperationSucceeded, destroyContainer("testDestroyContainer", false)); } public void test_Fat_Internal_Destroy_Success() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testDestroyContainer", 4, "none", FS_FAT, false)); assertEquals(StorageResultCode.OperationSucceeded, destroyContainer("testDestroyContainer", false)); } public void test_Ext4_Internal_Destroy_Success() throws Exception { assertEquals(StorageResultCode.OperationSucceeded, createContainer("testDestroyContainer", 4, "none", FS_EXT4, false)); assertEquals(StorageResultCode.OperationSucceeded, destroyContainer("testDestroyContainer", false)); } /* * MOUNT */ public void test_Fat_External_Mount() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testMountContainer", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationSucceeded, unmountContainer("testMountContainer", false)); assertEquals(StorageResultCode.OperationSucceeded, mountContainer("testMountContainer", "none")); } /* * MOUNT BAD KEY - FAIL CASE */ public void test_Fat_External_MountBadKey_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testMountBadKey", 4, "00000000000000000000000000000000", FS_FAT, true)); assertEquals(StorageResultCode.OperationSucceeded, unmountContainer("testMountBadKey", false)); assertEquals(StorageResultCode.OperationFailedInternalError, mountContainer("testMountContainer", "000000000000000000000000000000001")); assertEquals(StorageResultCode.OperationFailedInternalError, mountContainer("testMountContainer", "none")); } public void test_Fat_External_UnmountBusy_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } IMountService ms = getMs(); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testUnmountBusyContainer", 4, "none", FS_FAT, true)); String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testUnmountBusyContainer"); File f = new File(path, "reference"); FileOutputStream fos = new FileOutputStream(f); assertEquals(StorageResultCode.OperationFailedStorageBusy, unmountContainer("testUnmountBusyContainer", false)); fos.close(); assertEquals(StorageResultCode.OperationSucceeded, unmountContainer("testUnmountBusyContainer", false)); } public void test_Fat_External_DestroyBusy() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } IMountService ms = getMs(); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testDestroyBusyContainer", 4, "none", FS_FAT, true)); String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testDestroyBusyContainer"); File f = new File(path, "reference"); FileOutputStream fos = new FileOutputStream(f); assertEquals(StorageResultCode.OperationFailedStorageBusy, destroyContainer("testDestroyBusyContainer", false)); fos.close(); assertEquals(StorageResultCode.OperationSucceeded, destroyContainer("testDestroyBusyContainer", false)); } public void test_Fat_External_Rename_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testRenameContainer.1", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationSucceeded, unmountContainer("testRenameContainer.1", false)); assertEquals(StorageResultCode.OperationSucceeded, renameContainer("testRenameContainer.1", "testRenameContainer.2")); assertFalse(containerExists("testRenameContainer.1")); assertTrue(containerExists("testRenameContainer.2")); } public void test_Fat_External_RenameSrcMounted_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testRenameContainer.1", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationFailedStorageMounted, renameContainer("testRenameContainer.1", "testRenameContainer.2")); } public void test_Fat_External_RenameDstMounted_Failure() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } assertEquals(StorageResultCode.OperationSucceeded, createContainer("testRenameContainer.1", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationSucceeded, unmountContainer("testRenameContainer.1", false)); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testRenameContainer.2", 4, "none", FS_FAT, true)); assertEquals(StorageResultCode.OperationFailedStorageMounted, renameContainer("testRenameContainer.1", "testRenameContainer.2")); } public void test_Fat_External_Size_Success() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } IMountService ms = getMs(); assertEquals(StorageResultCode.OperationSucceeded, createContainer("testContainerSize", 1, "none", FS_FAT, true)); String path = ms.getSecureContainerPath(SECURE_CONTAINER_PREFIX + "testContainerSize"); byte[] buf = new byte[4096]; File f = new File(path, "reference"); FileOutputStream fos = new FileOutputStream(f); for (int i = 0; i < (1024 * 1024); i += buf.length) { fos.write(buf); } fos.close(); } public void testGetSecureContainerPath_NonExistPath_Failure() throws Exception { IMountService ms = getMs(); assertNull("Getting the path for an invalid container should return null", ms.getSecureContainerPath("jparks.broke.it")); } /*------------ Tests for unmounting volume ---*/ public final long MAX_WAIT_TIME=120*1000; public final long WAIT_TIME_INCR=20*1000; boolean getMediaState() throws Exception { String mPath = Environment.getExternalStorageDirectory().toString(); String state = getMs().getVolumeState(mPath); return Environment.MEDIA_MOUNTED.equals(state); } boolean mountMedia() throws Exception { if (Environment.isExternalStorageEmulated()) { return true; } if (getMediaState()) { return true; } String mPath = Environment.getExternalStorageDirectory().toString(); int ret = getMs().mountVolume(mPath); return ret == StorageResultCode.OperationSucceeded; } class StorageListener extends StorageEventListener { String oldState; String newState; String path; private boolean doneFlag = false; public void action() { synchronized (this) { doneFlag = true; notifyAll(); } } public boolean isDone() { return doneFlag; } @Override public void onStorageStateChanged(String path, String oldState, String newState) { if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState); this.oldState = oldState; this.newState = newState; this.path = path; action(); } } private void unmountMedia() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } if (!getMediaState()) { return; } String path = Environment.getExternalStorageDirectory().toString(); StorageListener observer = new StorageListener(); StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); sm.registerListener(observer); try { // Wait on observer synchronized(observer) { getMs().unmountVolume(path, false, false); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { observer.wait(WAIT_TIME_INCR); waitTime += WAIT_TIME_INCR; } if(!observer.isDone()) { fail("Timed out waiting for packageInstalled callback"); } } } finally { sm.unregisterListener(observer); } } public void testUnmount() throws Exception { boolean oldStatus = getMediaState(); Log.i(TAG, "oldStatus="+oldStatus); try { // Mount media firsts if (!getMediaState()) { mountMedia(); } unmountMedia(); } finally { // Restore old status boolean currStatus = getMediaState(); if (oldStatus != currStatus) { if (oldStatus) { // Mount media mountMedia(); } else { unmountMedia(); } } } } class MultipleStorageLis extends StorageListener { int count = 0; public void onStorageStateChanged(String path, String oldState, String newState) { count++; super.action(); } } /* * This test invokes unmount multiple time and expects the call back * to be invoked just once. */ public void testUnmountMultiple() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } boolean oldStatus = getMediaState(); StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); MultipleStorageLis observer = new MultipleStorageLis(); try { // Mount media firsts if (!getMediaState()) { mountMedia(); } String path = Environment.getExternalStorageDirectory().toString(); sm.registerListener(observer); // Wait on observer synchronized(observer) { for (int i = 0; i < 5; i++) { getMs().unmountVolume(path, false, false); } long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { observer.wait(WAIT_TIME_INCR); waitTime += WAIT_TIME_INCR; } if(!observer.isDone()) { fail("Timed out waiting for packageInstalled callback"); } } assertEquals(observer.count, 1); } finally { sm.unregisterListener(observer); // Restore old status boolean currStatus = getMediaState(); if (oldStatus != currStatus) { if (oldStatus) { // Mount media mountMedia(); } else { unmountMedia(); } } } } class ShutdownObserver extends IMountShutdownObserver.Stub{ private boolean doneFlag = false; int statusCode; public void action() { synchronized (this) { doneFlag = true; notifyAll(); } } public boolean isDone() { return doneFlag; } public void onShutDownComplete(int statusCode) throws RemoteException { this.statusCode = statusCode; action(); } } void invokeShutdown() throws Exception { IMountService ms = getMs(); ShutdownObserver observer = new ShutdownObserver(); synchronized (observer) { ms.shutdown(observer); } } public void testShutdown() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } boolean oldStatus = getMediaState(); try { // Mount media firsts if (!getMediaState()) { mountMedia(); } invokeShutdown(); } finally { // Restore old status boolean currStatus = getMediaState(); if (oldStatus != currStatus) { if (oldStatus) { // Mount media mountMedia(); } else { unmountMedia(); } } } } /* * This test invokes unmount multiple time and expects the call back * to be invoked just once. */ public void testShutdownMultiple() throws Exception { if (Environment.isExternalStorageEmulated()) { return; } boolean oldStatus = getMediaState(); try { // Mount media firsts if (!getMediaState()) { mountMedia(); } IMountService ms = getMs(); ShutdownObserver observer = new ShutdownObserver(); synchronized (observer) { ms.shutdown(observer); for (int i = 0; i < 4; i++) { ms.shutdown(null); } } } finally { // Restore old status boolean currStatus = getMediaState(); if (oldStatus != currStatus) { if (oldStatus) { // Mount media mountMedia(); } else { unmountMedia(); } } } } }