| /* |
| * 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 com.android.unit_tests; |
| |
| import com.android.unit_tests.PackageManagerTests.StorageListener; |
| |
| import android.os.storage.IMountService.Stub; |
| |
| import android.net.Uri; |
| import android.os.FileUtils; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| import android.app.PendingIntent; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.test.AndroidTestCase; |
| import android.test.suitebuilder.annotation.Suppress; |
| import android.util.DisplayMetrics; |
| import android.util.Log; |
| import android.os.Environment; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.storage.IMountService; |
| import android.os.storage.IMountShutdownObserver; |
| import android.os.storage.StorageEventListener; |
| import android.os.storage.StorageManager; |
| import android.os.storage.StorageResultCode; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.os.StatFs; |
| import android.provider.Settings; |
| import junit.framework.Assert; |
| |
| public class AsecTests extends AndroidTestCase { |
| private static final boolean localLOGV = true; |
| public static final String TAG="AsecTests"; |
| |
| void failStr(String errMsg) { |
| Log.w(TAG, "errMsg="+errMsg); |
| } |
| |
| void failStr(Exception e) { |
| Log.w(TAG, "e.getMessage="+e.getMessage()); |
| Log.w(TAG, "e="+e); |
| } |
| |
| @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("com.android.unittests.AsecTests.")) { |
| ms.destroySecureContainer(containers[i], true); |
| } |
| } |
| } |
| |
| private boolean containerExists(String localId) throws RemoteException { |
| IMountService ms = getMs(); |
| String[] containers = ms.getSecureContainerList(); |
| String fullId = "com.android.unittests.AsecTests." + 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) throws RemoteException { |
| Assert.assertTrue(isMediaMounted()); |
| String fullId = "com.android.unittests.AsecTests." + localId; |
| |
| IMountService ms = getMs(); |
| return ms.createSecureContainer(fullId, size, "fat", key, android.os.Process.myUid()); |
| } |
| |
| private int mountContainer(String localId, String key) throws RemoteException { |
| Assert.assertTrue(isMediaMounted()); |
| String fullId = "com.android.unittests.AsecTests." + localId; |
| |
| IMountService ms = getMs(); |
| return ms.mountSecureContainer(fullId, key, android.os.Process.myUid()); |
| } |
| |
| private int renameContainer(String localId1, String localId2) throws RemoteException { |
| Assert.assertTrue(isMediaMounted()); |
| String fullId1 = "com.android.unittests.AsecTests." + localId1; |
| String fullId2 = "com.android.unittests.AsecTests." + localId2; |
| |
| IMountService ms = getMs(); |
| return ms.renameSecureContainer(fullId1, fullId2); |
| } |
| |
| private int unmountContainer(String localId, boolean force) throws RemoteException { |
| Assert.assertTrue(isMediaMounted()); |
| String fullId = "com.android.unittests.AsecTests." + localId; |
| |
| IMountService ms = getMs(); |
| return ms.unmountSecureContainer(fullId, force); |
| } |
| |
| private int destroyContainer(String localId, boolean force) throws RemoteException { |
| Assert.assertTrue(isMediaMounted()); |
| String fullId = "com.android.unittests.AsecTests." + localId; |
| |
| IMountService ms = getMs(); |
| return ms.destroySecureContainer(fullId, force); |
| } |
| |
| private boolean isContainerMounted(String localId) throws RemoteException { |
| Assert.assertTrue(isMediaMounted()); |
| String fullId = "com.android.unittests.AsecTests." + 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() { |
| try { |
| String mPath = Environment.getExternalStorageDirectory().toString(); |
| String state = getMs().getVolumeState(mPath); |
| return Environment.MEDIA_MOUNTED.equals(state); |
| } catch (RemoteException e) { |
| failStr(e); |
| return false; |
| } |
| } |
| |
| public void testCreateContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testCreateContainer", 4, "none")); |
| Assert.assertEquals(true, containerExists("testCreateContainer")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testCreateMinSizeContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testCreateContainer", 1, "none")); |
| Assert.assertEquals(true, containerExists("testCreateContainer")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testCreateZeroSizeContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationFailedInternalError, |
| createContainer("testCreateZeroContainer", 0, "none")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testCreateDuplicateContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testCreateDupContainer", 4, "none")); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedInternalError, |
| createContainer("testCreateDupContainer", 4, "none")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testDestroyContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testDestroyContainer", 4, "none")); |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| destroyContainer("testDestroyContainer", false)); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testMountContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testMountContainer", 4, "none")); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| unmountContainer("testMountContainer", false)); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| mountContainer("testMountContainer", "none")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testMountBadKey() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testMountBadKey", 4, "00000000000000000000000000000000")); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| unmountContainer("testMountBadKey", false)); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedInternalError, |
| mountContainer("testMountContainer", "000000000000000000000000000000001")); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedInternalError, |
| mountContainer("testMountContainer", "none")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testUnmountBusyContainer() { |
| IMountService ms = getMs(); |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testUnmountBusyContainer", 4, "none")); |
| |
| String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer"); |
| |
| File f = new File(path, "reference"); |
| FileOutputStream fos = new FileOutputStream(f); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy, |
| unmountContainer("testUnmountBusyContainer", false)); |
| |
| fos.close(); |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| unmountContainer("testUnmountBusyContainer", false)); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testDestroyBusyContainer() { |
| IMountService ms = getMs(); |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testDestroyBusyContainer", 4, "none")); |
| |
| String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testDestroyBusyContainer"); |
| |
| File f = new File(path, "reference"); |
| FileOutputStream fos = new FileOutputStream(f); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy, |
| destroyContainer("testDestroyBusyContainer", false)); |
| |
| fos.close(); |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| destroyContainer("testDestroyBusyContainer", false)); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testRenameContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testRenameContainer.1", 4, "none")); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| unmountContainer("testRenameContainer.1", false)); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| renameContainer("testRenameContainer.1", "testRenameContainer.2")); |
| |
| Assert.assertEquals(false, containerExists("testRenameContainer.1")); |
| Assert.assertEquals(true, containerExists("testRenameContainer.2")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testRenameSrcMountedContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testRenameContainer.1", 4, "none")); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted, |
| renameContainer("testRenameContainer.1", "testRenameContainer.2")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testRenameDstMountedContainer() { |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testRenameContainer.1", 4, "none")); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| unmountContainer("testRenameContainer.1", false)); |
| |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testRenameContainer.2", 4, "none")); |
| |
| Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted, |
| renameContainer("testRenameContainer.1", "testRenameContainer.2")); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| public void testContainerSize() { |
| IMountService ms = getMs(); |
| try { |
| Assert.assertEquals(StorageResultCode.OperationSucceeded, |
| createContainer("testContainerSize", 1, "none")); |
| String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer"); |
| |
| 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(); |
| } catch (Exception e) { |
| failStr(e); |
| } |
| } |
| |
| /*------------ Tests for unmounting volume ---*/ |
| public final long MAX_WAIT_TIME=120*1000; |
| public final long WAIT_TIME_INCR=20*1000; |
| boolean getMediaState() { |
| try { |
| String mPath = Environment.getExternalStorageDirectory().toString(); |
| String state = getMs().getVolumeState(mPath); |
| return Environment.MEDIA_MOUNTED.equals(state); |
| } catch (RemoteException e) { |
| return false; |
| } |
| } |
| |
| boolean mountMedia() { |
| if (getMediaState()) { |
| return true; |
| } |
| try { |
| String mPath = Environment.getExternalStorageDirectory().toString(); |
| int ret = getMs().mountVolume(mPath); |
| return ret == StorageResultCode.OperationSucceeded; |
| } catch (RemoteException e) { |
| return false; |
| } |
| } |
| |
| 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 boolean unmountMedia() { |
| if (!getMediaState()) { |
| return true; |
| } |
| 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); |
| long waitTime = 0; |
| while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { |
| observer.wait(WAIT_TIME_INCR); |
| waitTime += WAIT_TIME_INCR; |
| } |
| if(!observer.isDone()) { |
| throw new Exception("Timed out waiting for packageInstalled callback"); |
| } |
| return true; |
| } |
| } catch (Exception e) { |
| return false; |
| } finally { |
| sm.unregisterListener(observer); |
| } |
| } |
| public void testUnmount() { |
| boolean oldStatus = getMediaState(); |
| Log.i(TAG, "oldStatus="+oldStatus); |
| try { |
| // Mount media firsts |
| if (!getMediaState()) { |
| mountMedia(); |
| } |
| assertTrue(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() { |
| 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); |
| } |
| long waitTime = 0; |
| while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { |
| observer.wait(WAIT_TIME_INCR); |
| waitTime += WAIT_TIME_INCR; |
| } |
| if(!observer.isDone()) { |
| failStr("Timed out waiting for packageInstalled callback"); |
| } |
| } |
| assertEquals(observer.count, 1); |
| } catch (Exception e) { |
| failStr(e); |
| } 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(); |
| } |
| |
| } |
| |
| boolean invokeShutdown() { |
| IMountService ms = getMs(); |
| ShutdownObserver observer = new ShutdownObserver(); |
| synchronized (observer) { |
| try { |
| ms.shutdown(observer); |
| return true; |
| } catch (RemoteException e) { |
| failStr(e); |
| } |
| } |
| return false; |
| } |
| |
| public void testShutdown() { |
| boolean oldStatus = getMediaState(); |
| try { |
| // Mount media firsts |
| if (!getMediaState()) { |
| mountMedia(); |
| } |
| assertTrue(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() { |
| boolean oldStatus = getMediaState(); |
| try { |
| // Mount media firsts |
| if (!getMediaState()) { |
| mountMedia(); |
| } |
| IMountService ms = getMs(); |
| ShutdownObserver observer = new ShutdownObserver(); |
| synchronized (observer) { |
| try { |
| ms.shutdown(observer); |
| for (int i = 0; i < 4; i++) { |
| ms.shutdown(null); |
| } |
| } catch (RemoteException e) { |
| failStr(e); |
| } |
| } |
| } finally { |
| // Restore old status |
| boolean currStatus = getMediaState(); |
| if (oldStatus != currStatus) { |
| if (oldStatus) { |
| // Mount media |
| mountMedia(); |
| } else { |
| unmountMedia(); |
| } |
| } |
| } |
| } |
| |
| } |