| /* |
| * Copyright (C) 2010 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.ProxyFileDescriptorCallback; |
| import android.os.ParcelFileDescriptor; |
| import android.system.ErrnoException; |
| import android.system.Os; |
| import android.test.InstrumentationTestCase; |
| import android.test.suitebuilder.annotation.LargeTest; |
| import android.test.suitebuilder.annotation.Suppress; |
| import android.util.Log; |
| |
| import com.android.frameworks.coretests.R; |
| import com.android.internal.os.FuseAppLoop; |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.util.concurrent.ThreadFactory; |
| import java.io.File; |
| import java.io.FileInputStream; |
| |
| import junit.framework.AssertionFailedError; |
| |
| public class StorageManagerIntegrationTest extends StorageManagerBaseTest { |
| |
| private static String LOG_TAG = "StorageManagerBaseTest.StorageManagerIntegrationTest"; |
| protected File mFile = null; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| mContext = getInstrumentation().getContext(); |
| mFile = null; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void tearDown() throws Exception { |
| if (mFile != null) { |
| mFile.delete(); |
| mFile = null; |
| } |
| super.tearDown(); |
| } |
| |
| /** |
| * Tests mounting a single OBB file and verifies its contents. |
| */ |
| @LargeTest |
| public void testMountSingleObb() { |
| mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); |
| String filePath = mFile.getAbsolutePath(); |
| mountObb(filePath); |
| verifyObb1Contents(filePath); |
| unmountObb(filePath, DONT_FORCE); |
| } |
| |
| /** |
| * Tests mounting several OBB files and verifies its contents. |
| */ |
| @LargeTest |
| public void testMountMultipleObb() { |
| File file1 = null; |
| File file2 = null; |
| File file3 = null; |
| try { |
| file1 = createObbFile(OBB_FILE_1, R.raw.obb_file1); |
| String filePath1 = file1.getAbsolutePath(); |
| mountObb(filePath1); |
| verifyObb1Contents(filePath1); |
| |
| file2 = createObbFile(OBB_FILE_2, R.raw.obb_file2); |
| String filePath2 = file2.getAbsolutePath(); |
| mountObb(filePath2); |
| verifyObb2Contents(filePath2); |
| |
| file3 = createObbFile(OBB_FILE_3, R.raw.obb_file3); |
| String filePath3 = file3.getAbsolutePath(); |
| mountObb(filePath3); |
| verifyObb3Contents(filePath3); |
| |
| unmountObb(filePath1, DONT_FORCE); |
| unmountObb(filePath2, DONT_FORCE); |
| unmountObb(filePath3, DONT_FORCE); |
| } finally { |
| if (file1 != null) { |
| file1.delete(); |
| } |
| if (file2 != null) { |
| file2.delete(); |
| } |
| if (file3 != null) { |
| file3.delete(); |
| } |
| } |
| } |
| |
| /** |
| * Tests mounting a single encrypted OBB file and verifies its contents. |
| */ |
| @LargeTest |
| public void testMountSingleEncryptedObb() { |
| mFile = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3); |
| String filePath = mFile.getAbsolutePath(); |
| mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED); |
| verifyObb3Contents(filePath); |
| unmountObb(filePath, DONT_FORCE); |
| } |
| |
| /** |
| * Tests mounting a single encrypted OBB file using an invalid password. |
| */ |
| @LargeTest |
| @Suppress // Failing. |
| public void testMountSingleEncryptedObbInvalidPassword() { |
| mFile = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3); |
| String filePath = mFile.getAbsolutePath(); |
| mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); |
| unmountObb(filePath, DONT_FORCE); |
| } |
| |
| /** |
| * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents. |
| */ |
| @LargeTest |
| public void testMountTwoEncryptedObb() { |
| File file3 = null; |
| File file1 = null; |
| try { |
| file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3); |
| String filePath3 = file3.getAbsolutePath(); |
| mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED); |
| verifyObb3Contents(filePath3); |
| |
| file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1); |
| String filePath1 = file1.getAbsolutePath(); |
| mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED); |
| verifyObb1Contents(filePath1); |
| |
| unmountObb(filePath3, DONT_FORCE); |
| unmountObb(filePath1, DONT_FORCE); |
| } finally { |
| if (file3 != null) { |
| file3.delete(); |
| } |
| if (file1 != null) { |
| file1.delete(); |
| } |
| } |
| } |
| |
| /** |
| * Tests that we can not force unmount when a file is currently open on the OBB. |
| */ |
| @LargeTest |
| public void testUnmount_DontForce() { |
| mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); |
| String obbFilePath = mFile.getAbsolutePath(); |
| |
| MountingObbThread mountingThread = new MountingObbThread(obbFilePath, |
| OBB_FILE_1_CONTENTS_1); |
| |
| try { |
| mountingThread.start(); |
| |
| long waitTime = 0; |
| while (!mountingThread.isFileOpenOnObb()) { |
| synchronized (mountingThread) { |
| Log.i(LOG_TAG, "Waiting for file to be opened on OBB..."); |
| mountingThread.wait(WAIT_TIME_INCR); |
| waitTime += WAIT_TIME_INCR; |
| if (waitTime > MAX_WAIT_TIME) { |
| fail("Timed out waiting for file file to be opened on OBB!"); |
| } |
| } |
| } |
| |
| unmountObb(obbFilePath, DONT_FORCE); |
| |
| // verify still mounted |
| assertTrue("mounted path should not be null!", obbFilePath != null); |
| assertTrue("mounted path should still be mounted!", mSm.isObbMounted(obbFilePath)); |
| |
| // close the opened file |
| mountingThread.doStop(); |
| |
| // try unmounting again (should succeed this time) |
| unmountObb(obbFilePath, DONT_FORCE); |
| assertFalse("mounted path should no longer be mounted!", |
| mSm.isObbMounted(obbFilePath)); |
| } catch (InterruptedException e) { |
| fail("Timed out waiting for file on OBB to be opened..."); |
| } |
| } |
| |
| /** |
| * Tests mounting a single OBB that isn't signed. |
| */ |
| @LargeTest |
| public void testMountUnsignedObb() { |
| mFile = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign); |
| String filePath = mFile.getAbsolutePath(); |
| mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL); |
| } |
| |
| /** |
| * Tests mounting a single OBB that is signed with a different package. |
| */ |
| @LargeTest |
| public void testMountBadPackageNameObb() { |
| mFile = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename); |
| String filePath = mFile.getAbsolutePath(); |
| mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME, |
| OnObbStateChangeListener.ERROR_PERMISSION_DENIED); |
| } |
| |
| /** |
| * Tests remounting a single OBB that has already been mounted. |
| */ |
| @LargeTest |
| public void testRemountObb() { |
| mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1); |
| String filePath = mFile.getAbsolutePath(); |
| mountObb(filePath); |
| verifyObb1Contents(filePath); |
| mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); |
| verifyObb1Contents(filePath); |
| unmountObb(filePath, DONT_FORCE); |
| } |
| |
| @LargeTest |
| public void testOpenProxyFileDescriptor() throws Exception { |
| final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() { |
| @Override |
| public long onGetSize() throws ErrnoException { |
| return 0; |
| } |
| |
| @Override |
| public void onRelease() {} |
| }; |
| |
| final MyThreadFactory factory = new MyThreadFactory(); |
| int firstMountId; |
| try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor( |
| ParcelFileDescriptor.MODE_READ_ONLY, callback, factory)) { |
| assertNotSame(Thread.State.TERMINATED, factory.thread.getState()); |
| firstMountId = mSm.getProxyFileDescriptorMountPointId(); |
| assertNotSame(-1, firstMountId); |
| } |
| |
| // After closing descriptor, the loop should terminate. |
| factory.thread.join(3000); |
| assertEquals(Thread.State.TERMINATED, factory.thread.getState()); |
| |
| // StorageManager should mount another bridge on the next open request. |
| try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor( |
| ParcelFileDescriptor.MODE_WRITE_ONLY, callback, factory)) { |
| assertNotSame(Thread.State.TERMINATED, factory.thread.getState()); |
| assertNotSame(firstMountId, mSm.getProxyFileDescriptorMountPointId()); |
| } |
| } |
| |
| private static class MyThreadFactory implements ThreadFactory { |
| Thread thread = null; |
| |
| @Override |
| public Thread newThread(Runnable r) { |
| thread = new Thread(r); |
| return thread; |
| } |
| } |
| } |