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