• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
17 package android.os.storage.cts;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27 import static org.junit.Assume.assumeTrue;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.when;
30 import static org.testng.Assert.assertThrows;
31 
32 import static java.util.stream.Collectors.joining;
33 
34 import android.app.PendingIntent;
35 import android.content.Context;
36 import android.content.res.Resources;
37 import android.content.res.Resources.NotFoundException;
38 import android.os.Environment;
39 import android.os.Handler;
40 import android.os.Looper;
41 import android.os.Parcel;
42 import android.os.ParcelFileDescriptor;
43 import android.os.Process;
44 import android.os.ProxyFileDescriptorCallback;
45 import android.os.UserHandle;
46 import android.os.cts.R;
47 import android.os.storage.OnObbStateChangeListener;
48 import android.os.storage.StorageManager;
49 import android.os.storage.StorageManager.StorageVolumeCallback;
50 import android.os.storage.StorageVolume;
51 import android.platform.test.annotations.AppModeFull;
52 import android.provider.DeviceConfig;
53 import android.system.ErrnoException;
54 import android.system.Os;
55 import android.system.OsConstants;
56 import android.test.ComparisonFailure;
57 import android.util.Log;
58 
59 import androidx.test.ext.junit.runners.AndroidJUnit4;
60 import androidx.test.platform.app.InstrumentationRegistry;
61 
62 import com.android.compatibility.common.util.FileUtils;
63 import com.android.compatibility.common.util.SystemUtil;
64 
65 import org.junit.Before;
66 import org.junit.FixMethodOrder;
67 import org.junit.Test;
68 import org.junit.runner.RunWith;
69 import org.junit.runners.MethodSorters;
70 
71 import java.io.ByteArrayOutputStream;
72 import java.io.File;
73 import java.io.FileDescriptor;
74 import java.io.FileInputStream;
75 import java.io.IOException;
76 import java.io.InputStream;
77 import java.io.InterruptedIOException;
78 import java.io.SyncFailedException;
79 import java.lang.reflect.Field;
80 import java.lang.reflect.Modifier;
81 import java.util.ArrayList;
82 import java.util.List;
83 import java.util.Optional;
84 import java.util.Set;
85 import java.util.UUID;
86 import java.util.concurrent.CountDownLatch;
87 import java.util.concurrent.SynchronousQueue;
88 import java.util.concurrent.TimeUnit;
89 import java.util.stream.Collectors;
90 
91 // The FixMethodOrder annotation is added to avoid flakiness caused by a change in test execution
92 // order (b/273874071).
93 // TODO(b/278069249): Investigate why the order matters, and possibly remove the annotation.
94 @RunWith(AndroidJUnit4.class)
95 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
96 public class StorageManagerTest {
97 
98     private static final String TAG = StorageManager.class.getSimpleName();
99 
100     private static final long MAX_WAIT_TIME = 25*1000;
101     private static final long WAIT_TIME_INCR = 5*1000;
102 
103     private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
104     private static final String TEST1_NEW_CONTENTS = "1\n";
105 
106     private Context mContext;
107     private StorageManager mStorageManager;
108     private final Handler mHandler = new Handler(Looper.getMainLooper());
109 
110     @Before
setUp()111     public void setUp() throws Exception {
112         mContext = InstrumentationRegistry.getInstrumentation().getContext();
113         mStorageManager = mContext.getSystemService(StorageManager.class);
114     }
115 
116     @Test
117     @AppModeFull(reason = "Instant apps cannot access external storage")
testMountAndUnmountObbNormal()118     public void testMountAndUnmountObbNormal() throws IOException {
119         for (File target : getTargetFiles()) {
120             target = new File(target, "test1_new.obb");
121             Log.d(TAG, "Testing path " + target);
122             doMountAndUnmountObbNormal(target);
123         }
124     }
125 
doMountAndUnmountObbNormal(File outFile)126     private void doMountAndUnmountObbNormal(File outFile) throws IOException {
127         final String canonPath = mountObb(R.raw.test1_new, outFile, OnObbStateChangeListener.MOUNTED);
128 
129         mountObb(R.raw.test1_new, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
130 
131         try {
132             final String mountPath = checkMountedPath(canonPath);
133             final File mountDir = new File(mountPath);
134             final File testFile = new File(mountDir, "test1.txt");
135 
136             assertTrue("OBB mounted path should be a directory", mountDir.isDirectory());
137             assertTrue("test1.txt does not exist in OBB dir", testFile.exists());
138             assertFileContains(testFile, TEST1_NEW_CONTENTS);
139         } finally {
140             unmountObb(outFile, OnObbStateChangeListener.UNMOUNTED);
141         }
142     }
143 
144     @Test
145     @AppModeFull(reason = "Instant apps cannot access external storage")
testAttemptMountNonObb()146     public void testAttemptMountNonObb() {
147         for (File target : getTargetFiles()) {
148             target = new File(target, "test1_nosig.obb");
149             Log.d(TAG, "Testing path " + target);
150             doAttemptMountNonObb(target);
151         }
152     }
153 
doAttemptMountNonObb(File outFile)154     private void doAttemptMountNonObb(File outFile) {
155         try {
156             mountObb(R.raw.test1_nosig, outFile, OnObbStateChangeListener.ERROR_INTERNAL);
157             fail("mountObb should've failed with an exception");
158         } catch (IllegalArgumentException e) {
159             // Expected
160         }
161 
162         assertFalse("OBB should not be mounted",
163                 mStorageManager.isObbMounted(outFile.getPath()));
164 
165         assertNull("OBB's mounted path should be null",
166                 mStorageManager.getMountedObbPath(outFile.getPath()));
167     }
168 
169     @Test
170     @AppModeFull(reason = "Instant apps cannot access external storage")
testAttemptMountObbWrongPackage()171     public void testAttemptMountObbWrongPackage() {
172         for (File target : getTargetFiles()) {
173             target = new File(target, "test1_wrongpackage.obb");
174             Log.d(TAG, "Testing path " + target);
175             doAttemptMountObbWrongPackage(target);
176         }
177     }
178 
doAttemptMountObbWrongPackage(File outFile)179     private void doAttemptMountObbWrongPackage(File outFile) {
180         mountObb(R.raw.test1_wrongpackage, outFile,
181                 OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
182 
183         assertFalse("OBB should not be mounted",
184                 mStorageManager.isObbMounted(outFile.getPath()));
185 
186         assertNull("OBB's mounted path should be null",
187                 mStorageManager.getMountedObbPath(outFile.getPath()));
188     }
189 
190     @Test
191     @AppModeFull(reason = "Instant apps cannot access external storage")
testMountAndUnmountTwoObbs()192     public void testMountAndUnmountTwoObbs() throws IOException {
193         for (File target : getTargetFiles()) {
194             Log.d(TAG, "Testing target " + target);
195             final File test1 = new File(target, "test1.obb");
196             final File test2 = new File(target, "test2.obb");
197             doMountAndUnmountTwoObbs(test1, test2);
198         }
199     }
200 
doMountAndUnmountTwoObbs(File file1, File file2)201     private void doMountAndUnmountTwoObbs(File file1, File file2) throws IOException {
202         ObbObserver oo1 = mountObbWithoutWait(R.raw.test1_new, file1);
203         ObbObserver oo2 = mountObbWithoutWait(R.raw.test1_new, file2);
204 
205         Log.d(TAG, "Waiting for OBB #1 to complete mount");
206         waitForObbActionCompletion(file1, oo1, OnObbStateChangeListener.MOUNTED);
207         Log.d(TAG, "Waiting for OBB #2 to complete mount");
208         waitForObbActionCompletion(file2, oo2, OnObbStateChangeListener.MOUNTED);
209 
210         try {
211             final String mountPath1 = checkMountedPath(oo1.getPath());
212             final File mountDir1 = new File(mountPath1);
213             final File testFile1 = new File(mountDir1, "test1.txt");
214             assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory());
215             assertTrue("test1.txt does not exist in OBB dir", testFile1.exists());
216             assertFileContains(testFile1, TEST1_NEW_CONTENTS);
217 
218             final String mountPath2 = checkMountedPath(oo2.getPath());
219             final File mountDir2 = new File(mountPath2);
220             final File testFile2 = new File(mountDir2, "test1.txt");
221             assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory());
222             assertTrue("test1.txt does not exist in OBB dir", testFile2.exists());
223             assertFileContains(testFile2, TEST1_NEW_CONTENTS);
224         } finally {
225             unmountObb(file1, OnObbStateChangeListener.UNMOUNTED);
226             unmountObb(file2, OnObbStateChangeListener.UNMOUNTED);
227         }
228     }
229 
230     @Test
testGetPrimaryVolume()231     public void testGetPrimaryVolume() throws Exception {
232         final StorageVolume volume = mStorageManager.getPrimaryStorageVolume();
233         assertNotNull("Did not get primary storage", volume);
234 
235         // Tests some basic Scoped Directory Access requests.
236         assertNull("Should not grant access for root directory", volume.createAccessIntent(null));
237         assertNull("Should not grant access for invalid directory",
238                 volume.createAccessIntent("/system"));
239         assertNotNull("Should grant access for valid directory " + Environment.DIRECTORY_DOCUMENTS,
240                 volume.createAccessIntent(Environment.DIRECTORY_DOCUMENTS));
241 
242         // Tests basic properties.
243         assertNotNull("Should have description", volume.getDescription(mContext));
244         assertTrue("Should be primary", volume.isPrimary());
245         assertEquals("Wrong state", Environment.MEDIA_MOUNTED, volume.getState());
246 
247         // Tests properties that depend on storage type (emulated or physical)
248         final String fsUuid = volume.getUuid();
249         final UUID uuid = volume.getStorageUuid();
250         final boolean removable = volume.isRemovable();
251         final boolean emulated = volume.isEmulated();
252         if (emulated) {
253             assertFalse("Should not be externally managed", volume.isExternallyManaged());
254             assertFalse("Should not be removable", removable);
255             assertNull("Should not have fsUuid", fsUuid);
256             assertEquals("Should have uuid_default", StorageManager.UUID_DEFAULT, uuid);
257         } else {
258             assertTrue("Should be removable", removable);
259             assertNotNull("Should have fsUuid", fsUuid);
260             assertNull("Should not have uuid", uuid);
261         }
262 
263         // Tests path - although it's not a public API, sm.getPrimaryStorageVolume()
264         // explicitly states it should match Environment#getExternalStorageDirectory
265         final String path = volume.getPath();
266         assertEquals("Path does not match Environment's",
267                 Environment.getExternalStorageDirectory().getAbsolutePath(), path);
268 
269         // Tests Parcelable contract.
270         assertEquals("Wrong describeContents", 0, volume.describeContents());
271         final Parcel parcel = Parcel.obtain();
272         try {
273             volume.writeToParcel(parcel, 0);
274             parcel.setDataPosition(0);
275             final StorageVolume clone = StorageVolume.CREATOR.createFromParcel(parcel);
276             assertStorageVolumesEquals(volume, clone);
277         } finally {
278             parcel.recycle();
279         }
280     }
281 
282     @Test
283     @AppModeFull(reason = "Instant apps cannot access external storage")
testGetStorageVolumes()284     public void testGetStorageVolumes() throws Exception {
285         final List<StorageVolume> volumes = mStorageManager.getStorageVolumes();
286         assertFalse("No volume return", volumes.isEmpty());
287         StorageVolume primary = null;
288         for (StorageVolume volume : volumes) {
289             if (volume.isPrimary()) {
290                 assertNull("There can be only one primary volume: " + volumes, primary);
291                 primary = volume;
292             }
293         }
294         assertNotNull("No primary volume on  " + volumes, primary);
295         assertStorageVolumesEquals(primary, mStorageManager.getPrimaryStorageVolume());
296     }
297 
298     @Test
299     @AppModeFull(reason = "Instant apps cannot access external storage")
testGetRecentStorageVolumes()300     public void testGetRecentStorageVolumes() throws Exception {
301         // At a minimum recent volumes should include current volumes
302         final Set<String> currentNames = mStorageManager.getStorageVolumes().stream()
303                 .map((v) -> v.getMediaStoreVolumeName()).collect(Collectors.toSet());
304         final Set<String> recentNames = mStorageManager.getRecentStorageVolumes().stream()
305                 .map((v) -> v.getMediaStoreVolumeName()).collect(Collectors.toSet());
306         assertTrue(recentNames.containsAll(currentNames));
307     }
308 
309     @Test
310     @AppModeFull(reason = "Instant apps cannot access external storage")
testGetStorageVolume()311     public void testGetStorageVolume() throws Exception {
312         assertNull("Should not get volume for null path",
313                 mStorageManager.getStorageVolume((File) null));
314         assertNull("Should not get volume for invalid path",
315                 mStorageManager.getStorageVolume(new File("/system")));
316         assertNull("Should not get volume for storage directory",
317                 mStorageManager.getStorageVolume(Environment.getStorageDirectory()));
318 
319         final File root = Environment.getExternalStorageDirectory();
320         Log.d("StorageManagerTest", "root: " + root);
321         final StorageVolume primary = mStorageManager.getPrimaryStorageVolume();
322         final StorageVolume rootVolume = mStorageManager.getStorageVolume(root);
323         assertNotNull("No volume for root (" + root + ")", rootVolume);
324         assertStorageVolumesEquals(primary, rootVolume);
325 
326         final File child = new File(root, "child");
327         StorageVolume childVolume = mStorageManager.getStorageVolume(child);
328         assertNotNull("No volume for child (" + child + ")", childVolume);
329         Log.d("StorageManagerTest", "child: " + childVolume.getPath());
330         assertStorageVolumesEquals(primary, childVolume);
331     }
332 
333     @Test
334     @AppModeFull(reason = "Instant apps cannot access external storage")
testGetStorageVolumeUSB()335     public void testGetStorageVolumeUSB() throws Exception {
336         assumeTrue(StorageManagerHelper.isAdoptableStorageSupported(mContext));
337 
338         String volumeName = StorageManagerHelper.createUSBVirtualDisk();
339         Log.d(TAG, "testGetStorageVolumeUSB#volumeName: " + volumeName);
340         List<StorageVolume> storageVolumes = mStorageManager.getStorageVolumes();
341         Optional<StorageVolume> usbStorageVolume =
342                 storageVolumes.stream().filter(sv->
343                 sv != null && sv.getPath() != null && sv.getPath().contains(volumeName)
344             ).findFirst();
345         assertTrue("The USB storage volume mounted on the main user is not present in "
346                 + storageVolumes.stream().map(StorageVolume::getPath)
347                 .collect(joining("\n")), usbStorageVolume.isPresent());
348     }
349 
350     @Test
351     @AppModeFull(reason = "Instant apps cannot access external storage")
testGetStorageVolumeSDCard()352     public void testGetStorageVolumeSDCard() throws Exception {
353         assumeTrue(StorageManagerHelper.isAdoptableStorageSupported(mContext));
354 
355         String volumeName = StorageManagerHelper.createSDCardVirtualDisk();
356         Log.d(TAG, "testGetStorageVolumeSDCard#volumeName: " + volumeName);
357         List<StorageVolume> storageVolumes = mStorageManager.getStorageVolumes();
358         Optional<StorageVolume> sdCardStorageVolume =
359                 storageVolumes.stream().filter(sv->
360                 sv != null && sv.getPath() != null && sv.getPath().contains(volumeName)
361             ).findFirst();
362         assertTrue("The SdCard storage volume mounted on the main user is not present in "
363                         + storageVolumes.stream().map(StorageVolume::getPath)
364                         .collect(joining("\n")), sdCardStorageVolume.isPresent());
365     }
366 
assertNoUuid(File file)367     private void assertNoUuid(File file) {
368         try {
369             final UUID uuid = mStorageManager.getUuidForPath(file);
370             fail("Unexpected UUID " + uuid + " for " + file);
371         } catch (IOException expected) {
372         }
373     }
374 
375     @Test
testGetUuidForPath()376     public void testGetUuidForPath() throws Exception {
377         assertEquals(StorageManager.UUID_DEFAULT,
378                 mStorageManager.getUuidForPath(Environment.getDataDirectory()));
379         assertEquals(StorageManager.UUID_DEFAULT,
380                 mStorageManager.getUuidForPath(mContext.getDataDir()));
381 
382         assertNoUuid(new File("/"));
383         assertNoUuid(new File("/proc/"));
384     }
385 
386     @Test
387     @AppModeFull(reason = "Instant apps cannot access external storage")
testGetExternalUuidForPath()388     public void testGetExternalUuidForPath() throws Exception {
389         final UUID extUuid = mStorageManager
390                 .getUuidForPath(Environment.getExternalStorageDirectory());
391         if (Environment.isExternalStorageEmulated()) {
392             assertEquals(StorageManager.UUID_DEFAULT, extUuid);
393         }
394 
395         assertEquals(extUuid, mStorageManager.getUuidForPath(mContext.getExternalCacheDir()));
396         assertEquals(extUuid, mStorageManager.getUuidForPath(new File("/sdcard/")));
397     }
398 
399     @Test
400     @AppModeFull(reason = "Instant apps cannot access external storage")
testCallback()401     public void testCallback() throws Exception {
402         final CountDownLatch mounted = new CountDownLatch(1);
403         final CountDownLatch unmounted = new CountDownLatch(1);
404         final StorageVolumeCallback callback = new StorageVolumeCallback() {
405             @Override
406             public void onStateChanged(StorageVolume volume) {
407                 switch (volume.getState()) {
408                     case Environment.MEDIA_MOUNTED: mounted.countDown(); break;
409                     case Environment.MEDIA_UNMOUNTED: unmounted.countDown(); break;
410                 }
411             }
412         };
413 
414         // Unmount storage data and obb dirs before test so test process won't be killed.
415         InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
416                 "sm unmount-app-data-dirs " + mContext.getPackageName() + " "
417                         + Process.myPid() + " " + UserHandle.myUserId());
418 
419         // Unmount primary storage, verify we can see it take effect
420         mStorageManager.registerStorageVolumeCallback(mContext.getMainExecutor(), callback);
421         InstrumentationRegistry.getInstrumentation().getUiAutomation()
422                 .executeShellCommand("sm unmount emulated;" + UserHandle.myUserId());
423         assertTrue(unmounted.await(30, TimeUnit.SECONDS));
424 
425         // Now unregister and verify we don't hear future events
426         mStorageManager.unregisterStorageVolumeCallback(callback);
427         InstrumentationRegistry.getInstrumentation().getUiAutomation()
428                 .executeShellCommand("sm mount emulated;" + UserHandle.myUserId());
429         assertFalse(mounted.await(15, TimeUnit.SECONDS));
430     }
431 
432     private static class TestProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
433         final byte[] bytes;
434         int fsyncCount;
435         int releaseCount;
436         ErrnoException onGetSizeError = null;
437         ErrnoException onReadError = null;
438         ErrnoException onWriteError = null;
439         ErrnoException onFsyncError = null;
440 
TestProxyFileDescriptorCallback(int size, String seed)441         TestProxyFileDescriptorCallback(int size, String seed) {
442             final byte[] seedBytes = seed.getBytes();
443             bytes = new byte[size];
444             for (int i = 0; i < size; i++) {
445                 bytes[i] = seedBytes[i % seedBytes.length];
446             }
447         }
448 
449         @Override
onWrite(long offset, int size, byte[] data)450         public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
451             if (onWriteError != null) {
452                 throw onWriteError;
453             }
454             for (int i = 0; i < size; i++) {
455                 bytes[(int)(i + offset)] = data[i];
456             }
457             return size;
458         }
459 
460         @Override
onRead(long offset, int size, byte[] data)461         public int onRead(long offset, int size, byte[] data) throws ErrnoException {
462             if (onReadError != null) {
463                 throw onReadError;
464             }
465             final int len = (int)(Math.min(size, bytes.length - offset));
466             for (int i = 0; i < len; i++) {
467                 data[i] = bytes[(int)(i + offset)];
468             }
469             return len;
470         }
471 
472         @Override
onGetSize()473         public long onGetSize() throws ErrnoException {
474             if (onGetSizeError != null) {
475                 throw onGetSizeError;
476             }
477             return bytes.length;
478         }
479 
480         @Override
onFsync()481         public void onFsync() throws ErrnoException {
482             if (onFsyncError != null) {
483                 throw onFsyncError;
484             }
485             fsyncCount++;
486         }
487 
488         @Override
onRelease()489         public void onRelease() {
490             releaseCount++;
491         }
492     }
493 
494     @Test
testOpenProxyFileDescriptor()495     public void testOpenProxyFileDescriptor() throws Exception {
496         final TestProxyFileDescriptorCallback appleCallback =
497                 new TestProxyFileDescriptorCallback(1024 * 1024, "Apple");
498         final TestProxyFileDescriptorCallback orangeCallback =
499                 new TestProxyFileDescriptorCallback(1024 * 128, "Orange");
500         final TestProxyFileDescriptorCallback cherryCallback =
501                 new TestProxyFileDescriptorCallback(1024 * 1024, "Cherry");
502         try (final ParcelFileDescriptor appleFd = mStorageManager.openProxyFileDescriptor(
503                      ParcelFileDescriptor.MODE_READ_ONLY, appleCallback, mHandler);
504              final ParcelFileDescriptor orangeFd = mStorageManager.openProxyFileDescriptor(
505                      ParcelFileDescriptor.MODE_WRITE_ONLY, orangeCallback, mHandler);
506              final ParcelFileDescriptor cherryFd = mStorageManager.openProxyFileDescriptor(
507                      ParcelFileDescriptor.MODE_READ_WRITE, cherryCallback, mHandler)) {
508             // Stat
509             assertEquals(appleCallback.onGetSize(), appleFd.getStatSize());
510             assertEquals(orangeCallback.onGetSize(), orangeFd.getStatSize());
511             assertEquals(cherryCallback.onGetSize(), cherryFd.getStatSize());
512 
513             final byte[] bytes = new byte[100];
514 
515             // Read
516             for (int i = 0; i < 2; i++) {
517                 Os.read(appleFd.getFileDescriptor(), bytes, 0, 100);
518                 for (int j = 0; j < 100; j++) {
519                     assertEquals(appleCallback.bytes[i * 100 + j], bytes[j]);
520                 }
521             }
522             try {
523                 Os.read(orangeFd.getFileDescriptor(), bytes, 0, 100);
524                 fail();
525             } catch (ErrnoException exp) {
526                 assertEquals(OsConstants.EBADF, exp.errno);
527             }
528             for (int i = 0; i < 2; i++) {
529                 Os.read(cherryFd.getFileDescriptor(), bytes, 0, 100);
530                 for (int j = 0; j < 100; j++) {
531                     assertEquals(cherryCallback.bytes[i * 100 + j], bytes[j]);
532                 }
533             }
534 
535             // Pread
536             Os.pread(appleFd.getFileDescriptor(), bytes, 0, 100, 500);
537             for (int j = 0; j < 100; j++) {
538                 assertEquals(appleCallback.bytes[500 + j], bytes[j]);
539             }
540             try {
541                 Os.pread(orangeFd.getFileDescriptor(), bytes, 0, 100, 500);
542                 fail();
543             } catch (ErrnoException exp) {
544                 assertEquals(OsConstants.EBADF, exp.errno);
545             }
546             Os.pread(cherryFd.getFileDescriptor(), bytes, 0, 100, 500);
547             for (int j = 0; j < 100; j++) {
548                 assertEquals(cherryCallback.bytes[500 + j], bytes[j]);
549             }
550 
551             // Write
552             final byte[] writeSeed = "Strawberry".getBytes();
553             for (int i = 0; i < bytes.length; i++) {
554                 bytes[i] = writeSeed[i % writeSeed.length];
555             }
556             try {
557                 Os.write(appleFd.getFileDescriptor(), bytes, 0, 100);
558                 fail();
559             } catch (ErrnoException exp) {
560                 assertEquals(OsConstants.EBADF, exp.errno);
561             }
562             for (int i = 0; i < 2; i++) {
563                 Os.write(orangeFd.getFileDescriptor(), bytes, 0, 100);
564                 for (int j = 0; j < 100; j++) {
565                     assertEquals(bytes[j], orangeCallback.bytes[i * 100 + j]);
566                 }
567             }
568             Os.lseek(cherryFd.getFileDescriptor(), 0, OsConstants.SEEK_SET);
569             for (int i = 0; i < 2; i++) {
570                 Os.write(cherryFd.getFileDescriptor(), bytes, 0, 100);
571                 for (int j = 0; j < 100; j++) {
572                     assertEquals(bytes[j], cherryCallback.bytes[i * 100 + j]);
573                 }
574             }
575 
576             // Pwrite
577             try {
578                 Os.pwrite(appleFd.getFileDescriptor(), bytes, 0, 100, 500);
579                 fail();
580             } catch (ErrnoException exp) {
581                 assertEquals(OsConstants.EBADF, exp.errno);
582             }
583             Os.pwrite(orangeFd.getFileDescriptor(), bytes, 0, 100, 500);
584             for (int j = 0; j < 100; j++) {
585                 assertEquals(bytes[j], orangeCallback.bytes[500 + j]);
586             }
587             Os.pwrite(cherryFd.getFileDescriptor(), bytes, 0, 100, 500);
588             for (int j = 0; j < 100; j++) {
589                 assertEquals(bytes[j], cherryCallback.bytes[500 + j]);
590             }
591 
592             // Flush
593             assertEquals(0, appleCallback.fsyncCount);
594             assertEquals(0, orangeCallback.fsyncCount);
595             assertEquals(0, cherryCallback.fsyncCount);
596             appleFd.getFileDescriptor().sync();
597             orangeFd.getFileDescriptor().sync();
598             cherryFd.getFileDescriptor().sync();
599             assertEquals(1, appleCallback.fsyncCount);
600             assertEquals(1, orangeCallback.fsyncCount);
601             assertEquals(1, cherryCallback.fsyncCount);
602 
603             // Before release
604             assertEquals(0, appleCallback.releaseCount);
605             assertEquals(0, orangeCallback.releaseCount);
606             assertEquals(0, cherryCallback.releaseCount);
607         }
608 
609         // Release
610         int retry = 3;
611         while (true) {
612             try {
613                 assertEquals(1, appleCallback.releaseCount);
614                 assertEquals(1, orangeCallback.releaseCount);
615                 assertEquals(1, cherryCallback.releaseCount);
616                 break;
617             } catch (AssertionError error) {
618                 if (retry-- > 0) {
619                    Thread.sleep(500);
620                    continue;
621                 } else {
622                     throw error;
623                 }
624             }
625         }
626     }
627 
628     @Test
testOpenProxyFileDescriptor_error()629     public void testOpenProxyFileDescriptor_error() throws Exception {
630         final TestProxyFileDescriptorCallback callback =
631                 new TestProxyFileDescriptorCallback(1024 * 1024, "Error");
632         final byte[] bytes = new byte[128];
633         callback.onGetSizeError = new ErrnoException("onGetSize", OsConstants.ENOENT);
634         try {
635             try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
636                     ParcelFileDescriptor.MODE_READ_WRITE, callback, mHandler)) {}
637             fail();
638         } catch (IOException exp) {}
639         callback.onGetSizeError = null;
640 
641         try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
642                 ParcelFileDescriptor.MODE_READ_WRITE, callback, mHandler)) {
643             callback.onReadError = new ErrnoException("onRead", OsConstants.EIO);
644             try {
645                 Os.read(fd.getFileDescriptor(), bytes, 0, bytes.length);
646                 fail();
647             } catch (ErrnoException error) {}
648 
649             callback.onReadError = new ErrnoException("onRead", OsConstants.ENOSYS);
650             try {
651                 Os.read(fd.getFileDescriptor(), bytes, 0, bytes.length);
652                 fail();
653             } catch (ErrnoException error) {}
654 
655             callback.onReadError = null;
656             Os.read(fd.getFileDescriptor(), bytes, 0, bytes.length);
657 
658             callback.onWriteError = new ErrnoException("onWrite", OsConstants.EIO);
659             try {
660                 Os.write(fd.getFileDescriptor(), bytes, 0, bytes.length);
661                 fail();
662             } catch (ErrnoException error) {}
663 
664             callback.onWriteError = new ErrnoException("onWrite", OsConstants.ENOSYS);
665             try {
666                 Os.write(fd.getFileDescriptor(), bytes, 0, bytes.length);
667                 fail();
668             } catch (ErrnoException error) {}
669 
670             callback.onWriteError = null;
671             Os.write(fd.getFileDescriptor(), bytes, 0, bytes.length);
672 
673             callback.onFsyncError = new ErrnoException("onFsync", OsConstants.EIO);
674             try {
675                 fd.getFileDescriptor().sync();
676                 fail();
677             } catch (SyncFailedException error) {}
678 
679             callback.onFsyncError = new ErrnoException("onFsync", OsConstants.ENOSYS);
680             try {
681                 fd.getFileDescriptor().sync();
682                 fail();
683             } catch (SyncFailedException error) {}
684 
685             callback.onFsyncError = null;
686             fd.getFileDescriptor().sync();
687         }
688     }
689 
690     @Test
testOpenProxyFileDescriptor_async()691     public void testOpenProxyFileDescriptor_async() throws Exception {
692         final CountDownLatch blockReadLatch = new CountDownLatch(1);
693         final CountDownLatch readBlockedLatch = new CountDownLatch(1);
694         final CountDownLatch releaseLatch = new CountDownLatch(2);
695         final TestProxyFileDescriptorCallback blockCallback =
696                 new TestProxyFileDescriptorCallback(1024 * 1024, "Block") {
697             @Override
698             public int onRead(long offset, int size, byte[] data) throws ErrnoException {
699                 try {
700                     readBlockedLatch.countDown();
701                     blockReadLatch.await();
702                 } catch (InterruptedException e) {
703                     fail(e.getMessage());
704                 }
705                 return super.onRead(offset, size, data);
706             }
707 
708             @Override
709             public void onRelease() {
710                 releaseLatch.countDown();
711             }
712         };
713         final TestProxyFileDescriptorCallback asyncCallback =
714                 new TestProxyFileDescriptorCallback(1024 * 1024, "Async") {
715             @Override
716             public void onRelease() {
717                 releaseLatch.countDown();
718             }
719         };
720         final SynchronousQueue<Handler> handlerChannel = new SynchronousQueue<>();
721         final Thread looperThread = new Thread(() -> {
722             Looper.prepare();
723             try {
724                 handlerChannel.put(new Handler());
725             } catch (InterruptedException e) {
726                 fail(e.getMessage());
727             }
728             Looper.loop();
729         });
730         looperThread.start();
731 
732         final Handler handler = handlerChannel.take();
733 
734         try (final ParcelFileDescriptor blockFd =
735                     mStorageManager.openProxyFileDescriptor(
736                             ParcelFileDescriptor.MODE_READ_ONLY, blockCallback, mHandler);
737              final ParcelFileDescriptor asyncFd =
738                     mStorageManager.openProxyFileDescriptor(
739                             ParcelFileDescriptor.MODE_READ_ONLY, asyncCallback, handler)) {
740             final Thread readingThread = new Thread(() -> {
741                 final byte[] bytes = new byte[128];
742                 try {
743 
744                     Os.read(blockFd.getFileDescriptor(), bytes, 0, 128);
745                 } catch (ErrnoException | InterruptedIOException e) {
746                     fail(e.getMessage());
747                 }
748             });
749             readingThread.start();
750 
751             readBlockedLatch.countDown();
752             assertEquals(Thread.State.RUNNABLE, readingThread.getState());
753 
754             final byte[] bytes = new byte[128];
755             Log.d("StorageManagerTest", "start read async");
756             assertEquals(128, Os.read(asyncFd.getFileDescriptor(), bytes, 0, 128));
757             Log.d("StorageManagerTest", "stop read async");
758 
759             blockReadLatch.countDown();
760             readingThread.join();
761         }
762 
763         releaseLatch.await();
764         handler.getLooper().quit();
765         looperThread.join();
766     }
767 
768     @Test
testOpenProxyFileDescriptor_largeFile()769     public void testOpenProxyFileDescriptor_largeFile() throws Exception {
770         final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() {
771             @Override
772             public int onRead(long offset, int size, byte[] data) throws ErrnoException {
773                 for (int i = 0; i < size; i++) {
774                     data[i] = 'L';
775                 }
776                 return size;
777             }
778 
779             @Override
780             public long onGetSize() throws ErrnoException {
781                 return 8L * 1024L * 1024L * 1024L;  // 8GB
782             }
783 
784             @Override
785             public void onRelease() {}
786         };
787         final byte[] bytes = new byte[128];
788         try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
789                 ParcelFileDescriptor.MODE_READ_ONLY, callback, mHandler)) {
790             assertEquals(8L * 1024L * 1024L * 1024L, fd.getStatSize());
791 
792             final int readBytes = Os.pread(
793                     fd.getFileDescriptor(), bytes, 0, bytes.length, fd.getStatSize() - 64L);
794             assertEquals(64, readBytes);
795             for (int i = 0; i < 64; i++) {
796                 assertEquals('L', bytes[i]);
797             }
798         }
799     }
800 
801     @Test
testOpenProxyFileDescriptor_largeRead()802     public void testOpenProxyFileDescriptor_largeRead() throws Exception {
803         final int SIZE = 1024 * 1024;
804         final TestProxyFileDescriptorCallback callback =
805                 new TestProxyFileDescriptorCallback(SIZE, "abcdefghijklmnopqrstuvwxyz");
806         final byte[] bytes = new byte[SIZE];
807         try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
808                 ParcelFileDescriptor.MODE_READ_ONLY, callback, mHandler)) {
809             final int readBytes = Os.read(
810                     fd.getFileDescriptor(), bytes, 0, bytes.length);
811             assertEquals(bytes.length, readBytes);
812             for (int i = 0; i < bytes.length; i++) {
813                 assertEquals(callback.bytes[i], bytes[i]);
814             }
815         }
816     }
817 
818     @Test
testOpenProxyFileDescriptor_largeWrite()819     public void testOpenProxyFileDescriptor_largeWrite() throws Exception {
820         final int SIZE = 1024 * 1024;
821         final TestProxyFileDescriptorCallback callback =
822                 new TestProxyFileDescriptorCallback(SIZE, "abcdefghijklmnopqrstuvwxyz");
823         final byte[] bytes = new byte[SIZE];
824         for (int i = 0; i < SIZE; i++) {
825             bytes[i] = (byte)(i % 123);
826         }
827         try (final ParcelFileDescriptor fd = mStorageManager.openProxyFileDescriptor(
828                 ParcelFileDescriptor.MODE_WRITE_ONLY, callback, mHandler)) {
829             final int writtenBytes = Os.write(
830                     fd.getFileDescriptor(), bytes, 0, bytes.length);
831             assertEquals(bytes.length, writtenBytes);
832             for (int i = 0; i < bytes.length; i++) {
833                 assertEquals(bytes[i], callback.bytes[i]);
834             }
835         }
836     }
837 
838     @Test
testIsAllocationSupported()839     public void testIsAllocationSupported() throws Exception {
840         FileDescriptor good = Os.open(
841             File.createTempFile("StorageManagerTest", "").getAbsolutePath(),
842             OsConstants.O_RDONLY, 0);
843         FileDescriptor bad = Os.open("/proc/self/cmdline", OsConstants.O_RDONLY, 0);
844         try {
845             assertTrue(mStorageManager.isAllocationSupported(good));
846             assertFalse(mStorageManager.isAllocationSupported(bad));
847         } finally {
848             try {
849                 Os.close(good);
850             } catch (ErrnoException ignored) {}
851 
852             try {
853                 Os.close(bad);
854             } catch (ErrnoException ignored) {}
855         }
856     }
857 
858     @Test
testFatUuidHandling()859     public void testFatUuidHandling() throws Exception {
860         assertEquals(UUID.fromString("fafafafa-fafa-5afa-8afa-fafa01234567"),
861                 StorageManager.convert("0123-4567"));
862         assertEquals(UUID.fromString("fafafafa-fafa-5afa-8afa-fafadeadbeef"),
863                 StorageManager.convert("DEAD-BEEF"));
864         assertEquals(UUID.fromString("fafafafa-fafa-5afa-8afa-fafadeadbeef"),
865                 StorageManager.convert("dead-BEEF"));
866 
867         try {
868             StorageManager.convert("DEADBEEF");
869             fail();
870         } catch (IllegalArgumentException expected) {}
871 
872         try {
873             StorageManager.convert("DEAD-BEEF0");
874             fail();
875         } catch (IllegalArgumentException expected) {}
876 
877         assertEquals("0123-4567",
878                 StorageManager.convert(UUID.fromString("fafafafa-fafa-5afa-8afa-fafa01234567")));
879         assertEquals("DEAD-BEEF",
880                 StorageManager.convert(UUID.fromString("fafafafa-fafa-5afa-8afa-fafadeadbeef")));
881     }
882 
883     @Test
884     @AppModeFull(reason = "Instant apps cannot hold MANAGE_EXTERNAL_STORAGE permission")
testGetManageSpaceActivityIntent()885     public void testGetManageSpaceActivityIntent() throws Exception {
886         String packageName = "android.os.cts";
887         int REQUEST_CODE = 1;
888         PendingIntent piActual = null;
889 
890         // Test should only pass with MANAGE_EXTERNAL_STORAGE permission
891         assertThat(Environment.isExternalStorageManager()).isTrue();
892 
893         // Invalid packageName should throw an IllegalArgumentException
894         String invalidPackageName = "this.is.invalid";
895         assertThrows(
896                 IllegalArgumentException.class,
897                 () -> mStorageManager.getManageSpaceActivityIntent(invalidPackageName,
898                         REQUEST_CODE));
899 
900         piActual = mStorageManager.getManageSpaceActivityIntent(packageName,
901                 REQUEST_CODE);
902         assertThat(piActual.isActivity()).isTrue();
903 
904         // Nothing to assert, but call send to make sure it does not throw an exception
905         piActual.send();
906 
907         // Drop MANAGE_EXTERNAL_STORAGE permission
908         InstrumentationRegistry.getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
909     }
910 
assertStorageVolumesEquals(StorageVolume volume, StorageVolume clone)911     private void assertStorageVolumesEquals(StorageVolume volume, StorageVolume clone)
912             throws Exception {
913         // Asserts equals() method.
914         assertEquals("StorageVolume.equals() mismatch", volume, clone);
915         // Make sure all fields match.
916         for (Field field : StorageVolume.class.getDeclaredFields()) {
917             if (Modifier.isStatic(field.getModifiers())) continue;
918             field.setAccessible(true);
919             final Object originalValue = field.get(volume);
920             final Object clonedValue = field.get(clone);
921             assertEquals("Mismatch for field " + field.getName(), originalValue, clonedValue);
922         }
923     }
924 
assertStartsWith(String message, String prefix, String actual)925     private static void assertStartsWith(String message, String prefix, String actual) {
926         if (!actual.startsWith(prefix)) {
927             throw new ComparisonFailure(message, prefix, actual);
928         }
929     }
930 
assertFileContains(File file, String contents)931     private static void assertFileContains(File file, String contents) throws IOException {
932         byte[] actual = readFully(new FileInputStream(file));
933         byte[] expected = contents.getBytes("UTF-8");
934         assertEquals("unexpected size", expected.length, actual.length);
935         for (int i = 0; i < expected.length; i++) {
936             assertEquals("unexpected value at offset " + i, expected[i], actual[i]);
937         }
938     }
939 
940     private static class ObbObserver extends OnObbStateChangeListener {
941         private String path;
942 
943         public int state = -1;
944         boolean done = false;
945 
946         @Override
onObbStateChange(String path, int state)947         public void onObbStateChange(String path, int state) {
948             Log.d(TAG, "Received message.  path=" + path + ", state=" + state);
949             synchronized (this) {
950                 this.path = path;
951                 this.state = state;
952                 done = true;
953                 notifyAll();
954             }
955         }
956 
getPath()957         public String getPath() {
958             assertTrue("Expected ObbObserver to have received a state change.", done);
959             return path;
960         }
961 
getState()962         public int getState() {
963             assertTrue("Expected ObbObserver to have received a state change.", done);
964             return state;
965         }
966 
isDone()967         public boolean isDone() {
968             return done;
969         }
970 
waitForCompletion()971         public boolean waitForCompletion() {
972             long waitTime = 0;
973             synchronized (this) {
974                 while (!isDone() && waitTime < MAX_WAIT_TIME) {
975                     try {
976                         wait(WAIT_TIME_INCR);
977                         waitTime += WAIT_TIME_INCR;
978                     } catch (InterruptedException e) {
979                         Log.i(TAG, "Interrupted during sleep", e);
980                     }
981                 }
982             }
983 
984             return isDone();
985         }
986     }
987 
getTargetFiles()988     private List<File> getTargetFiles() {
989         final List<File> targets = new ArrayList<File>();
990         for (File dir : mContext.getObbDirs()) {
991             assertNotNull("Valid media must be inserted during CTS", dir);
992             assertEquals("Valid media must be inserted during CTS", Environment.MEDIA_MOUNTED,
993                     Environment.getStorageState(dir));
994             targets.add(dir);
995         }
996         return targets;
997     }
998 
copyRawToFile(int rawResId, File outFile)999     private void copyRawToFile(int rawResId, File outFile) {
1000         Resources res = mContext.getResources();
1001         InputStream is = null;
1002         try {
1003             is = res.openRawResource(rawResId);
1004         } catch (NotFoundException e) {
1005             fail("Failed to load resource with id: " + rawResId);
1006         }
1007         assertTrue(FileUtils.copyToFile(is, outFile));
1008         exposeFile(outFile);
1009     }
1010 
exposeFile(File file)1011     private File exposeFile(File file) {
1012         file.setReadable(true, false);
1013         file.setReadable(true, true);
1014 
1015         File dir = file.getParentFile();
1016         do {
1017             dir.setExecutable(true, false);
1018             dir.setExecutable(true, true);
1019             dir = dir.getParentFile();
1020         } while (dir != null);
1021 
1022         return file;
1023     }
1024 
mountObb(final int resource, final File file, int expectedState)1025     private String mountObb(final int resource, final File file, int expectedState) {
1026         copyRawToFile(resource, file);
1027 
1028         final ObbObserver observer = new ObbObserver();
1029         assertTrue("mountObb call on " + file.getPath() + " should succeed",
1030                 mStorageManager.mountObb(file.getPath(), null, observer));
1031 
1032         assertTrue("Mount should have completed",
1033                 observer.waitForCompletion());
1034 
1035         if (expectedState == OnObbStateChangeListener.MOUNTED) {
1036             assertTrue("OBB should be mounted", mStorageManager.isObbMounted(observer.getPath()));
1037         }
1038 
1039         assertEquals(expectedState, observer.getState());
1040 
1041         return observer.getPath();
1042     }
1043 
mountObbWithoutWait(final int resource, final File file)1044     private ObbObserver mountObbWithoutWait(final int resource, final File file) {
1045         copyRawToFile(resource, file);
1046 
1047         final ObbObserver observer = new ObbObserver();
1048         assertTrue("mountObb call on " + file.getPath() + " should succeed",
1049                 mStorageManager.mountObb(file.getPath(), null, observer));
1050 
1051         return observer;
1052     }
1053 
waitForObbActionCompletion(final File file, final ObbObserver observer, int expectedState)1054     private void waitForObbActionCompletion(final File file, final ObbObserver observer,
1055             int expectedState) {
1056         assertTrue("Mount should have completed", observer.waitForCompletion());
1057 
1058         assertTrue("OBB should be mounted", mStorageManager.isObbMounted(observer.getPath()));
1059 
1060         assertEquals(expectedState, observer.getState());
1061     }
1062 
checkMountedPath(final String path)1063     private String checkMountedPath(final String path) {
1064         final String mountPath = mStorageManager.getMountedObbPath(path);
1065         assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX,
1066                 OBB_MOUNT_PREFIX,
1067                 mountPath);
1068         return mountPath;
1069     }
1070 
unmountObb(final File file, int expectedState)1071     private void unmountObb(final File file, int expectedState) {
1072         final ObbObserver observer = new ObbObserver();
1073 
1074         assertTrue("unmountObb call on test1_new.obb should succeed",
1075                 mStorageManager.unmountObb(file.getPath(), false, observer));
1076 
1077         assertTrue("Unmount should have completed",
1078                 observer.waitForCompletion());
1079 
1080         assertEquals(expectedState, observer.getState());
1081 
1082         if (expectedState == OnObbStateChangeListener.UNMOUNTED) {
1083             assertFalse("OBB should not be mounted", mStorageManager.isObbMounted(file.getPath()));
1084         }
1085     }
1086 
1087     @Test
testComputeStorageCacheBytes()1088     public void testComputeStorageCacheBytes() throws Exception {
1089         File mockFile = mock(File.class);
1090 
1091         final int[] storageThresholdPercentHigh = new int[1];
1092         SystemUtil.runWithShellPermissionIdentity(() -> {
1093             storageThresholdPercentHigh[0] = DeviceConfig.getInt(
1094                 DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
1095                 StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH_KEY, 0);
1096         });
1097         assertTrue("storageThresholdPercentHigh [" + storageThresholdPercentHigh[0]
1098                 + "] expected to be greater than equal to 0", storageThresholdPercentHigh[0] >= 0);
1099         assertTrue("storageThresholdPercentHigh [" + storageThresholdPercentHigh[0]
1100                 + "] expected to be lesser than equal to 100",
1101                 storageThresholdPercentHigh[0] <= 100);
1102 
1103         when(mockFile.getUsableSpace()).thenReturn(10000L);
1104         when(mockFile.getTotalSpace()).thenReturn(15000L);
1105         final long[] resultHigh = new long[1];
1106         SystemUtil.runWithShellPermissionIdentity(() -> {
1107             resultHigh[0] = mStorageManager.computeStorageCacheBytes(mockFile);
1108         });
1109         assertTrue("" + resultHigh[0] + " expected to be greater than equal to 0",
1110                 resultHigh[0] >= 0L);
1111         assertTrue("" + resultHigh[0] + " expected to be less than equal to total space",
1112                 resultHigh[0] <= mockFile.getTotalSpace());
1113 
1114         when(mockFile.getUsableSpace()).thenReturn(10000L);
1115         when(mockFile.getTotalSpace()).thenReturn(250000L);
1116         final long[] resultLow = new long[1];
1117         SystemUtil.runWithShellPermissionIdentity(() -> {
1118             resultLow[0] = mStorageManager.computeStorageCacheBytes(mockFile);
1119         });
1120         assertTrue("" + resultLow[0] + " expected to be greater than equal to 0",
1121                 resultLow[0] >= 0L);
1122         assertTrue("" + resultLow[0] + " expected to be less than equal to total space",
1123                 resultLow[0] <= mockFile.getTotalSpace());
1124 
1125         when(mockFile.getUsableSpace()).thenReturn(10000L);
1126         when(mockFile.getTotalSpace()).thenReturn(100000L);
1127         final long[] resultModerate = new long[1];
1128         SystemUtil.runWithShellPermissionIdentity(() -> {
1129             resultModerate[0] = mStorageManager.computeStorageCacheBytes(mockFile);
1130         });
1131         assertTrue("" + resultModerate[0] + " expected to be greater than equal to 0",
1132                 resultModerate[0] >= 0L);
1133         assertTrue("" + resultModerate[0] + " expected to be less than equal to total space",
1134                 resultModerate[0] <= mockFile.getTotalSpace());
1135     }
1136 
readFully(InputStream in)1137     public static byte[] readFully(InputStream in) throws IOException {
1138         // Shamelessly borrowed from libcore.io.Streams
1139         try {
1140             return readFullyNoClose(in);
1141         } finally {
1142             in.close();
1143         }
1144     }
1145 
readFullyNoClose(InputStream in)1146     public static byte[] readFullyNoClose(InputStream in) throws IOException {
1147         // Shamelessly borrowed from libcore.io.Streams
1148         ByteArrayOutputStream bytes = new ByteArrayOutputStream();
1149         byte[] buffer = new byte[1024];
1150         int count;
1151         while ((count = in.read(buffer)) != -1) {
1152             bytes.write(buffer, 0, count);
1153         }
1154         return bytes.toByteArray();
1155     }
1156 }
1157