1/*
2 * Copyright (C) 2010 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
17package android.os.storage;
18
19import android.os.ParcelFileDescriptor;
20import android.os.ProxyFileDescriptorCallback;
21import android.system.ErrnoException;
22import android.test.suitebuilder.annotation.LargeTest;
23import android.util.Log;
24
25import com.android.frameworks.coretests.R;
26
27import java.io.File;
28import java.util.concurrent.ThreadFactory;
29
30public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
31    private static String LOG_TAG = "StorageManagerIntegrationTest";
32
33    /**
34     * Tests mounting a single OBB file and verifies its contents.
35     */
36    @LargeTest
37    public void testMountSingleObb() throws Exception {
38        final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
39        String filePath = file.getAbsolutePath();
40        mountObb(filePath);
41        verifyObb1Contents(filePath);
42        unmountObb(filePath, DONT_FORCE);
43    }
44
45    /**
46     * Tests mounting several OBB files and verifies its contents.
47     */
48    @LargeTest
49    public void testMountMultipleObb() throws Exception {
50        File file1 = null;
51        File file2 = null;
52        File file3 = null;
53        try {
54            file1 = createObbFile(OBB_FILE_1, R.raw.obb_file1);
55            String filePath1 = file1.getAbsolutePath();
56            mountObb(filePath1);
57            verifyObb1Contents(filePath1);
58
59            file2 = createObbFile(OBB_FILE_2, R.raw.obb_file2);
60            String filePath2 = file2.getAbsolutePath();
61            mountObb(filePath2);
62            verifyObb2Contents(filePath2);
63
64            file3 = createObbFile(OBB_FILE_3, R.raw.obb_file3);
65            String filePath3 = file3.getAbsolutePath();
66            mountObb(filePath3);
67            verifyObb3Contents(filePath3);
68
69            unmountObb(filePath1, DONT_FORCE);
70            unmountObb(filePath2, DONT_FORCE);
71            unmountObb(filePath3, DONT_FORCE);
72        } finally {
73            if (file1 != null) {
74                file1.delete();
75            }
76            if (file2 != null) {
77                file2.delete();
78            }
79            if (file3 != null) {
80                file3.delete();
81            }
82        }
83    }
84
85    /**
86     * Tests mounting a single encrypted OBB file and verifies its contents.
87     */
88    @LargeTest
89    public void testMountSingleEncryptedObb() throws Exception {
90        final File file = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
91        String filePath = file.getAbsolutePath();
92        mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
93        verifyObb3Contents(filePath);
94        unmountObb(filePath, DONT_FORCE);
95    }
96
97    /**
98     * Tests mounting a single encrypted OBB file using an invalid password.
99     */
100    @LargeTest
101    public void testMountSingleEncryptedObbInvalidPassword() throws Exception {
102        final File file = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3);
103        String filePath = file.getAbsolutePath();
104        mountObb(filePath, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
105    }
106
107    /**
108     * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents.
109     */
110    @LargeTest
111    public void testMountTwoEncryptedObb() throws Exception {
112        File file3 = null;
113        File file1 = null;
114        try {
115            file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
116            String filePath3 = file3.getAbsolutePath();
117            mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
118            verifyObb3Contents(filePath3);
119
120            file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1);
121            String filePath1 = file1.getAbsolutePath();
122            mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED);
123            verifyObb1Contents(filePath1);
124
125            unmountObb(filePath3, DONT_FORCE);
126            unmountObb(filePath1, DONT_FORCE);
127        } finally {
128            if (file3 != null) {
129                file3.delete();
130            }
131            if (file1 != null) {
132                file1.delete();
133            }
134        }
135    }
136
137    /**
138     * Tests that we can not force unmount when a file is currently open on the OBB.
139     */
140    @LargeTest
141    public void testUnmount_DontForce() throws Exception {
142        final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
143        String obbFilePath = file.getAbsolutePath();
144
145        MountingObbThread mountingThread = new MountingObbThread(obbFilePath,
146                OBB_FILE_1_CONTENTS_1);
147
148        try {
149            mountingThread.start();
150
151            long waitTime = 0;
152            while (!mountingThread.isFileOpenOnObb()) {
153                synchronized (mountingThread) {
154                    Log.i(LOG_TAG, "Waiting for file to be opened on OBB...");
155                    mountingThread.wait(WAIT_TIME_INCR);
156                    waitTime += WAIT_TIME_INCR;
157                    if (waitTime > MAX_WAIT_TIME) {
158                        fail("Timed out waiting for file file to be opened on OBB!");
159                    }
160                }
161            }
162
163            unmountObb(obbFilePath, DONT_FORCE);
164
165            // verify still mounted
166            assertTrue("mounted path should not be null!", obbFilePath != null);
167            assertTrue("mounted path should still be mounted!", mSm.isObbMounted(obbFilePath));
168
169            // close the opened file
170            mountingThread.doStop();
171
172            // try unmounting again (should succeed this time)
173            unmountObb(obbFilePath, DONT_FORCE);
174            assertFalse("mounted path should no longer be mounted!",
175                    mSm.isObbMounted(obbFilePath));
176        } catch (InterruptedException e) {
177            fail("Timed out waiting for file on OBB to be opened...");
178        }
179    }
180
181    /**
182     * Tests mounting a single OBB that isn't signed.
183     */
184    @LargeTest
185    public void testMountUnsignedObb() throws Exception {
186        final File file = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign);
187        String filePath = file.getAbsolutePath();
188        mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL);
189    }
190
191    /**
192     * Tests mounting a single OBB that is signed with a different package.
193     */
194    @LargeTest
195    public void testMountBadPackageNameObb() throws Exception {
196        final File file = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
197        String filePath = file.getAbsolutePath();
198        mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME,
199                OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
200    }
201
202    /**
203     * Tests remounting a single OBB that has already been mounted.
204     */
205    @LargeTest
206    public void testRemountObb() throws Exception {
207        final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
208        String filePath = file.getAbsolutePath();
209        mountObb(filePath);
210        verifyObb1Contents(filePath);
211        mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
212        verifyObb1Contents(filePath);
213        unmountObb(filePath, DONT_FORCE);
214    }
215
216    @LargeTest
217    public void testOpenProxyFileDescriptor() throws Exception {
218        final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() {
219            @Override
220            public long onGetSize() throws ErrnoException {
221                return 0;
222            }
223
224            @Override
225            public void onRelease() {}
226        };
227
228        final MyThreadFactory factory = new MyThreadFactory();
229        int firstMountId;
230        try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
231                ParcelFileDescriptor.MODE_READ_ONLY, callback, null, factory)) {
232            assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
233            firstMountId = mSm.getProxyFileDescriptorMountPointId();
234            assertNotSame(-1, firstMountId);
235        }
236
237        // After closing descriptor, the loop should terminate.
238        factory.thread.join(3000);
239        assertEquals(Thread.State.TERMINATED, factory.thread.getState());
240
241        // StorageManager should mount another bridge on the next open request.
242        try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
243                ParcelFileDescriptor.MODE_WRITE_ONLY, callback, null, factory)) {
244            assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
245            assertNotSame(firstMountId, mSm.getProxyFileDescriptorMountPointId());
246        }
247    }
248
249    private static class MyThreadFactory implements ThreadFactory {
250        Thread thread = null;
251
252        @Override
253        public Thread newThread(Runnable r) {
254            thread = new Thread(r);
255            return thread;
256        }
257    }
258}
259