1 /* 2 * Copyright (C) 2017 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 com.android.cts.storageapp; 18 19 import static com.android.cts.storageapp.Utils.CACHE_ALL; 20 import static com.android.cts.storageapp.Utils.CACHE_EXT; 21 import static com.android.cts.storageapp.Utils.CACHE_INT; 22 import static com.android.cts.storageapp.Utils.DATA_EXT; 23 import static com.android.cts.storageapp.Utils.DATA_INT; 24 import static com.android.cts.storageapp.Utils.MB_IN_BYTES; 25 import static com.android.cts.storageapp.Utils.PKG_B; 26 import static com.android.cts.storageapp.Utils.assertMostlyEquals; 27 import static com.android.cts.storageapp.Utils.getSizeManual; 28 import static com.android.cts.storageapp.Utils.makeUniqueFile; 29 import static com.android.cts.storageapp.Utils.shouldHaveQuota; 30 import static com.android.cts.storageapp.Utils.useSpace; 31 32 import android.app.usage.StorageStats; 33 import android.app.usage.StorageStatsManager; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.pm.ApplicationInfo; 37 import android.content.pm.PackageManager; 38 import android.os.Environment; 39 import android.os.ParcelFileDescriptor; 40 import android.os.UserHandle; 41 import android.os.storage.StorageManager; 42 import android.system.Os; 43 import android.test.InstrumentationTestCase; 44 45 import java.io.File; 46 import java.io.IOException; 47 import java.util.UUID; 48 49 /** 50 * Client app for verifying storage behaviors. 51 */ 52 public class StorageTest extends InstrumentationTestCase { 53 private Context getContext() { 54 return getInstrumentation().getContext(); 55 } 56 57 public void testAllocate() throws Exception { 58 useSpace(getContext()); 59 } 60 61 public void testFullDisk() throws Exception { 62 if (shouldHaveQuota(Os.uname())) { 63 final File dataDir = getContext().getDataDir(); 64 65 // Pre-flight to see if we have enough disk space to test with 66 final long total = dataDir.getTotalSpace(); 67 final long free = dataDir.getFreeSpace(); 68 final long required = ((total * 9) / 10) + MB_IN_BYTES; 69 if (free < required) { 70 fail("Skipping full disk test; only found " + free + " free out of " + total); 71 } 72 73 Hoarder.doBlocks(dataDir, true); 74 } else { 75 fail("Skipping full disk test due to missing quota support"); 76 } 77 } 78 79 public void testTweakComponent() throws Exception { 80 getContext().getPackageManager().setComponentEnabledSetting( 81 new ComponentName(getContext().getPackageName(), UtilsReceiver.class.getName()), 82 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); 83 } 84 85 /** 86 * Measure ourselves manually. 87 */ 88 public void testVerifySpaceManual() throws Exception { 89 assertMostlyEquals(DATA_INT, 90 getSizeManual(getContext().getDataDir())); 91 assertMostlyEquals(DATA_EXT, 92 getSizeManual(getContext().getExternalCacheDir().getParentFile())); 93 } 94 95 /** 96 * Measure ourselves using platform APIs. 97 */ 98 public void testVerifySpaceApi() throws Exception { 99 final StorageManager sm = getContext().getSystemService(StorageManager.class); 100 final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class); 101 102 final long cacheSize = sm.getCacheSizeBytes( 103 sm.getUuidForPath(getContext().getCacheDir())); 104 final long extCacheSize = sm.getCacheSizeBytes( 105 sm.getUuidForPath(getContext().getExternalCacheDir())); 106 if (cacheSize == extCacheSize) { 107 assertMostlyEquals(CACHE_ALL, cacheSize); 108 } else { 109 assertMostlyEquals(CACHE_INT, cacheSize); 110 assertMostlyEquals(CACHE_EXT, extCacheSize); 111 } 112 113 // Verify APIs that don't require any special permissions 114 assertTrue(stats.getTotalBytes(StorageManager.UUID_DEFAULT) >= Environment 115 .getDataDirectory().getTotalSpace()); 116 assertTrue(stats.getFreeBytes(StorageManager.UUID_DEFAULT) >= Environment 117 .getDataDirectory().getUsableSpace()); 118 119 // Verify that we can see our own stats, and that they look sane 120 ApplicationInfo ai = getContext().getApplicationInfo(); 121 final StorageStats pstats = stats.queryStatsForPackage(ai.storageUuid, ai.packageName, 122 UserHandle.getUserHandleForUid(ai.uid)); 123 final StorageStats ustats = stats.queryStatsForUid(ai.storageUuid, ai.uid); 124 assertEquals(cacheSize, pstats.getCacheBytes()); 125 assertEquals(cacheSize, ustats.getCacheBytes()); 126 127 // Verify that other packages are off-limits 128 ai = getContext().getPackageManager().getApplicationInfo(PKG_B, 0); 129 try { 130 stats.queryStatsForPackage(ai.storageUuid, ai.packageName, 131 UserHandle.getUserHandleForUid(ai.uid)); 132 fail("Unexpected access"); 133 } catch (SecurityException expected) { 134 } 135 try { 136 stats.queryStatsForUid(ai.storageUuid, ai.uid); 137 fail("Unexpected access"); 138 } catch (SecurityException expected) { 139 } 140 try { 141 stats.queryExternalStatsForUser(StorageManager.UUID_DEFAULT, 142 android.os.Process.myUserHandle()); 143 fail("Unexpected access"); 144 } catch (SecurityException expected) { 145 } 146 } 147 148 public void testVerifyQuotaApi() throws Exception { 149 final StorageManager sm = getContext().getSystemService(StorageManager.class); 150 151 final long cacheSize = sm.getCacheQuotaBytes( 152 sm.getUuidForPath(getContext().getCacheDir())); 153 assertTrue("Apps must have at least 10MB quota", cacheSize > 10 * MB_IN_BYTES); 154 } 155 156 public void testVerifyAllocateApi() throws Exception { 157 final StorageManager sm = getContext().getSystemService(StorageManager.class); 158 159 final File filesDir = getContext().getFilesDir(); 160 final File extDir = Environment.getExternalStorageDirectory(); 161 162 final UUID filesUuid = sm.getUuidForPath(filesDir); 163 final UUID extUuid = sm.getUuidForPath(extDir); 164 165 assertTrue("Apps must be able to allocate internal space", 166 sm.getAllocatableBytes(filesUuid) > 10 * MB_IN_BYTES); 167 assertTrue("Apps must be able to allocate external space", 168 sm.getAllocatableBytes(extUuid) > 10 * MB_IN_BYTES); 169 170 // Should always be able to allocate 1MB indirectly 171 sm.allocateBytes(filesUuid, 1 * MB_IN_BYTES); 172 173 // Should always be able to allocate 1MB directly 174 final File filesFile = makeUniqueFile(filesDir); 175 assertEquals(0L, filesFile.length()); 176 try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(filesFile, 177 ParcelFileDescriptor.parseMode("rwt"))) { 178 sm.allocateBytes(pfd.getFileDescriptor(), 1 * MB_IN_BYTES); 179 } 180 assertEquals(1 * MB_IN_BYTES, filesFile.length()); 181 } 182 183 public void testBehaviorNormal() throws Exception { 184 final StorageManager sm = getContext().getSystemService(StorageManager.class); 185 186 final File dir = makeUniqueFile(getContext().getCacheDir()); 187 dir.mkdir(); 188 assertFalse(sm.isCacheBehaviorGroup(dir)); 189 assertFalse(sm.isCacheBehaviorTombstone(dir)); 190 191 final File ext = makeUniqueFile(getContext().getExternalCacheDir()); 192 ext.mkdir(); 193 try { sm.isCacheBehaviorGroup(ext); fail(); } catch (IOException expected) { } 194 try { sm.isCacheBehaviorTombstone(ext); fail(); } catch (IOException expected) { } 195 } 196 197 public void testBehaviorGroup() throws Exception { 198 final StorageManager sm = getContext().getSystemService(StorageManager.class); 199 200 final File dir = makeUniqueFile(getContext().getCacheDir()); 201 dir.mkdir(); 202 sm.setCacheBehaviorGroup(dir, true); 203 assertTrue(sm.isCacheBehaviorGroup(dir)); 204 205 final File ext = makeUniqueFile(getContext().getExternalCacheDir()); 206 ext.mkdir(); 207 try { sm.setCacheBehaviorGroup(ext, true); fail(); } catch (IOException expected) { } 208 try { sm.setCacheBehaviorGroup(ext, false); fail(); } catch (IOException expected) { } 209 } 210 211 public void testBehaviorTombstone() throws Exception { 212 final StorageManager sm = getContext().getSystemService(StorageManager.class); 213 214 final File dir = makeUniqueFile(getContext().getCacheDir()); 215 dir.mkdir(); 216 sm.setCacheBehaviorTombstone(dir, true); 217 assertTrue(sm.isCacheBehaviorTombstone(dir)); 218 219 final File ext = makeUniqueFile(getContext().getExternalCacheDir()); 220 ext.mkdir(); 221 try { sm.setCacheBehaviorTombstone(ext, true); fail(); } catch (IOException expected) { } 222 try { sm.setCacheBehaviorTombstone(ext, false); fail(); } catch (IOException expected) { } 223 } 224 } 225