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