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 android.app.usage; 18 19 import static android.os.storage.StorageManager.convert; 20 21 import android.annotation.BytesLong; 22 import android.annotation.NonNull; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemService; 25 import android.annotation.TestApi; 26 import android.annotation.WorkerThread; 27 import android.content.Context; 28 import android.content.pm.ApplicationInfo; 29 import android.content.pm.PackageInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.ParceledListSlice; 32 import android.os.ParcelableException; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.os.storage.CrateInfo; 36 import android.os.storage.StorageManager; 37 38 import com.android.internal.util.Preconditions; 39 40 import java.io.File; 41 import java.io.IOException; 42 import java.util.Collection; 43 import java.util.Objects; 44 import java.util.UUID; 45 46 /** 47 * Access to detailed storage statistics. This provides a summary of how apps, 48 * users, and external/shared storage is utilizing disk space. 49 * <p class="note"> 50 * Note: no permissions are required when calling these APIs for your own 51 * package or UID. However, requesting details for any other package requires 52 * the {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 53 * is a system-level permission that will not be granted to normal apps. 54 * Declaring that permission expresses your intention to use this API and an end 55 * user can then choose to grant this permission through the Settings 56 * application. 57 * </p> 58 */ 59 @SystemService(Context.STORAGE_STATS_SERVICE) 60 public class StorageStatsManager { 61 private final Context mContext; 62 private final IStorageStatsManager mService; 63 64 /** {@hide} */ StorageStatsManager(Context context, IStorageStatsManager service)65 public StorageStatsManager(Context context, IStorageStatsManager service) { 66 mContext = Objects.requireNonNull(context); 67 mService = Objects.requireNonNull(service); 68 } 69 70 /** {@hide} */ 71 @TestApi isQuotaSupported(@onNull UUID storageUuid)72 public boolean isQuotaSupported(@NonNull UUID storageUuid) { 73 try { 74 return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName()); 75 } catch (RemoteException e) { 76 throw e.rethrowFromSystemServer(); 77 } 78 } 79 80 /** @removed */ 81 @Deprecated isQuotaSupported(String uuid)82 public boolean isQuotaSupported(String uuid) { 83 return isQuotaSupported(convert(uuid)); 84 } 85 86 /** {@hide} */ 87 @TestApi isReservedSupported(@onNull UUID storageUuid)88 public boolean isReservedSupported(@NonNull UUID storageUuid) { 89 try { 90 return mService.isReservedSupported(convert(storageUuid), mContext.getOpPackageName()); 91 } catch (RemoteException e) { 92 throw e.rethrowFromSystemServer(); 93 } 94 } 95 96 /** 97 * Return the total size of the underlying physical media that is hosting 98 * this storage volume. 99 * <p> 100 * This value is best suited for visual display to end users, since it's 101 * designed to reflect the total storage size advertised in a retail 102 * environment. 103 * <p> 104 * Apps making logical decisions about disk space should always use 105 * {@link File#getTotalSpace()} instead of this value. 106 * 107 * @param storageUuid the UUID of the storage volume you're interested in, 108 * such as {@link StorageManager#UUID_DEFAULT}. 109 * @throws IOException when the storage device isn't present. 110 */ 111 @WorkerThread getTotalBytes(@onNull UUID storageUuid)112 public @BytesLong long getTotalBytes(@NonNull UUID storageUuid) throws IOException { 113 try { 114 return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName()); 115 } catch (ParcelableException e) { 116 e.maybeRethrow(IOException.class); 117 throw new RuntimeException(e); 118 } catch (RemoteException e) { 119 throw e.rethrowFromSystemServer(); 120 } 121 } 122 123 /** @removed */ 124 @Deprecated getTotalBytes(String uuid)125 public long getTotalBytes(String uuid) throws IOException { 126 return getTotalBytes(convert(uuid)); 127 } 128 129 /** 130 * Return the free space on the requested storage volume. 131 * <p> 132 * This value is best suited for visual display to end users, since it's 133 * designed to reflect both unused space <em>and</em> and cached space that 134 * could be reclaimed by the system. 135 * <p> 136 * Apps making logical decisions about disk space should always use 137 * {@link StorageManager#getAllocatableBytes(UUID)} instead of this value. 138 * 139 * @param storageUuid the UUID of the storage volume you're interested in, 140 * such as {@link StorageManager#UUID_DEFAULT}. 141 * @throws IOException when the storage device isn't present. 142 */ 143 @WorkerThread getFreeBytes(@onNull UUID storageUuid)144 public @BytesLong long getFreeBytes(@NonNull UUID storageUuid) throws IOException { 145 try { 146 return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName()); 147 } catch (ParcelableException e) { 148 e.maybeRethrow(IOException.class); 149 throw new RuntimeException(e); 150 } catch (RemoteException e) { 151 throw e.rethrowFromSystemServer(); 152 } 153 } 154 155 /** @removed */ 156 @Deprecated getFreeBytes(String uuid)157 public long getFreeBytes(String uuid) throws IOException { 158 return getFreeBytes(convert(uuid)); 159 } 160 161 /** {@hide} */ getCacheBytes(@onNull UUID storageUuid)162 public @BytesLong long getCacheBytes(@NonNull UUID storageUuid) throws IOException { 163 try { 164 return mService.getCacheBytes(convert(storageUuid), mContext.getOpPackageName()); 165 } catch (ParcelableException e) { 166 e.maybeRethrow(IOException.class); 167 throw new RuntimeException(e); 168 } catch (RemoteException e) { 169 throw e.rethrowFromSystemServer(); 170 } 171 } 172 173 /** {@hide} */ 174 @Deprecated getCacheBytes(String uuid)175 public long getCacheBytes(String uuid) throws IOException { 176 return getCacheBytes(convert(uuid)); 177 } 178 179 /** 180 * Return storage statistics for a specific package on the requested storage 181 * volume. 182 * <p class="note"> 183 * Note: no permissions are required when calling this API for your own 184 * package. However, requesting details for any other package requires the 185 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 186 * is a system-level permission that will not be granted to normal apps. 187 * Declaring that permission expresses your intention to use this API and an 188 * end user can then choose to grant this permission through the Settings 189 * application. 190 * </p> 191 * <p class="note"> 192 * Note: if the requested package uses the {@code android:sharedUserId} 193 * manifest feature, this call will be forced into a slower manual 194 * calculation path. If possible, consider always using 195 * {@link #queryStatsForUid(UUID, int)}, which is typically faster. 196 * </p> 197 * 198 * @param storageUuid the UUID of the storage volume you're interested in, 199 * such as {@link StorageManager#UUID_DEFAULT}. 200 * @param packageName the package name you're interested in. 201 * @param user the user you're interested in. 202 * @throws PackageManager.NameNotFoundException when the requested package 203 * name isn't installed for the requested user. 204 * @throws IOException when the storage device isn't present. 205 * @see ApplicationInfo#storageUuid 206 * @see PackageInfo#packageName 207 */ 208 @WorkerThread queryStatsForPackage(@onNull UUID storageUuid, @NonNull String packageName, @NonNull UserHandle user)209 public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid, 210 @NonNull String packageName, @NonNull UserHandle user) 211 throws PackageManager.NameNotFoundException, IOException { 212 try { 213 return mService.queryStatsForPackage(convert(storageUuid), packageName, 214 user.getIdentifier(), mContext.getOpPackageName()); 215 } catch (ParcelableException e) { 216 e.maybeRethrow(PackageManager.NameNotFoundException.class); 217 e.maybeRethrow(IOException.class); 218 throw new RuntimeException(e); 219 } catch (RemoteException e) { 220 throw e.rethrowFromSystemServer(); 221 } 222 } 223 224 /** @removed */ 225 @Deprecated queryStatsForPackage(String uuid, String packageName, UserHandle user)226 public StorageStats queryStatsForPackage(String uuid, String packageName, 227 UserHandle user) throws PackageManager.NameNotFoundException, IOException { 228 return queryStatsForPackage(convert(uuid), packageName, user); 229 } 230 231 /** 232 * Return storage statistics for a specific UID on the requested storage 233 * volume. 234 * <p class="note"> 235 * Note: no permissions are required when calling this API for your own UID. 236 * However, requesting details for any other UID requires the 237 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 238 * is a system-level permission that will not be granted to normal apps. 239 * Declaring that permission expresses your intention to use this API and an 240 * end user can then choose to grant this permission through the Settings 241 * application. 242 * </p> 243 * 244 * @param storageUuid the UUID of the storage volume you're interested in, 245 * such as {@link StorageManager#UUID_DEFAULT}. 246 * @param uid the UID you're interested in. 247 * @throws IOException when the storage device isn't present. 248 * @see ApplicationInfo#storageUuid 249 * @see ApplicationInfo#uid 250 */ 251 @WorkerThread queryStatsForUid(@onNull UUID storageUuid, int uid)252 public @NonNull StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid) 253 throws IOException { 254 try { 255 return mService.queryStatsForUid(convert(storageUuid), uid, 256 mContext.getOpPackageName()); 257 } catch (ParcelableException e) { 258 e.maybeRethrow(IOException.class); 259 throw new RuntimeException(e); 260 } catch (RemoteException e) { 261 throw e.rethrowFromSystemServer(); 262 } 263 } 264 265 /** @removed */ 266 @Deprecated queryStatsForUid(String uuid, int uid)267 public StorageStats queryStatsForUid(String uuid, int uid) throws IOException { 268 return queryStatsForUid(convert(uuid), uid); 269 } 270 271 /** 272 * Return storage statistics for a specific {@link UserHandle} on the 273 * requested storage volume. 274 * <p class="note"> 275 * Note: this API requires the 276 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 277 * is a system-level permission that will not be granted to normal apps. 278 * Declaring that permission expresses your intention to use this API and an 279 * end user can then choose to grant this permission through the Settings 280 * application. 281 * </p> 282 * 283 * @param storageUuid the UUID of the storage volume you're interested in, 284 * such as {@link StorageManager#UUID_DEFAULT}. 285 * @param user the user you're interested in. 286 * @throws IOException when the storage device isn't present. 287 * @see android.os.Process#myUserHandle() 288 */ 289 @WorkerThread queryStatsForUser(@onNull UUID storageUuid, @NonNull UserHandle user)290 public @NonNull StorageStats queryStatsForUser(@NonNull UUID storageUuid, 291 @NonNull UserHandle user) throws IOException { 292 try { 293 return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(), 294 mContext.getOpPackageName()); 295 } catch (ParcelableException e) { 296 e.maybeRethrow(IOException.class); 297 throw new RuntimeException(e); 298 } catch (RemoteException e) { 299 throw e.rethrowFromSystemServer(); 300 } 301 } 302 303 /** @removed */ 304 @Deprecated queryStatsForUser(String uuid, UserHandle user)305 public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException { 306 return queryStatsForUser(convert(uuid), user); 307 } 308 309 /** 310 * Return shared/external storage statistics for a specific 311 * {@link UserHandle} on the requested storage volume. 312 * <p class="note"> 313 * Note: this API requires the 314 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 315 * is a system-level permission that will not be granted to normal apps. 316 * Declaring that permission expresses your intention to use this API and an 317 * end user can then choose to grant this permission through the Settings 318 * application. 319 * </p> 320 * 321 * @param storageUuid the UUID of the storage volume you're interested in, 322 * such as {@link StorageManager#UUID_DEFAULT}. 323 * @throws IOException when the storage device isn't present. 324 * @see android.os.Process#myUserHandle() 325 */ 326 @WorkerThread queryExternalStatsForUser(@onNull UUID storageUuid, @NonNull UserHandle user)327 public @NonNull ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid, 328 @NonNull UserHandle user) throws IOException { 329 try { 330 return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(), 331 mContext.getOpPackageName()); 332 } catch (ParcelableException e) { 333 e.maybeRethrow(IOException.class); 334 throw new RuntimeException(e); 335 } catch (RemoteException e) { 336 throw e.rethrowFromSystemServer(); 337 } 338 } 339 340 /** @removed */ 341 @Deprecated queryExternalStatsForUser(String uuid, UserHandle user)342 public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user) 343 throws IOException { 344 return queryExternalStatsForUser(convert(uuid), user); 345 } 346 347 /** {@hide} */ getCacheQuotaBytes(String volumeUuid, int uid)348 public long getCacheQuotaBytes(String volumeUuid, int uid) { 349 try { 350 return mService.getCacheQuotaBytes(volumeUuid, uid, mContext.getOpPackageName()); 351 } catch (RemoteException e) { 352 throw e.rethrowFromSystemServer(); 353 } 354 } 355 356 /** 357 * Return all of crate information for the specified storageUuid, packageName, and 358 * userHandle. 359 * 360 * @param storageUuid the UUID of the storage volume you're interested in, 361 * such as {@link StorageManager#UUID_DEFAULT}. 362 * @param uid the uid you're interested in. 363 * @return the collection of crate information. 364 * @throws PackageManager.NameNotFoundException when the package name is not found. 365 * @throws IOException cause by IO, not support, or the other reasons. 366 * @hide 367 */ 368 @TestApi 369 @WorkerThread 370 @NonNull queryCratesForUid(@onNull UUID storageUuid, int uid)371 public Collection<CrateInfo> queryCratesForUid(@NonNull UUID storageUuid, 372 int uid) throws IOException, PackageManager.NameNotFoundException { 373 try { 374 ParceledListSlice<CrateInfo> crateInfoList = 375 mService.queryCratesForUid(convert(storageUuid), uid, 376 mContext.getOpPackageName()); 377 return Objects.requireNonNull(crateInfoList).getList(); 378 } catch (ParcelableException e) { 379 e.maybeRethrow(PackageManager.NameNotFoundException.class); 380 e.maybeRethrow(IOException.class); 381 throw new RuntimeException(e); 382 } catch (RemoteException e) { 383 throw e.rethrowFromSystemServer(); 384 } 385 } 386 387 /** 388 * Return all of crates information for the specified storageUuid, packageName, and 389 * userHandle. 390 * 391 * @param storageUuid the UUID of the storage volume you're interested in, 392 * such as {@link StorageManager#UUID_DEFAULT}. 393 * @param packageName the package name you're interested in. 394 * @param user the user you're interested in. 395 * @return the collection of crate information. 396 * @throws PackageManager.NameNotFoundException when the package name is not found. 397 * @throws IOException cause by IO, not support, or the other reasons. 398 * @hide 399 */ 400 @WorkerThread 401 @TestApi 402 @NonNull queryCratesForPackage(@onNull UUID storageUuid, @NonNull String packageName, @NonNull UserHandle user)403 public Collection<CrateInfo> queryCratesForPackage(@NonNull UUID storageUuid, 404 @NonNull String packageName, @NonNull UserHandle user) 405 throws PackageManager.NameNotFoundException, IOException { 406 try { 407 ParceledListSlice<CrateInfo> crateInfoList = 408 mService.queryCratesForPackage(convert(storageUuid), packageName, 409 user.getIdentifier(), mContext.getOpPackageName()); 410 return Objects.requireNonNull(crateInfoList).getList(); 411 } catch (ParcelableException e) { 412 e.maybeRethrow(PackageManager.NameNotFoundException.class); 413 e.maybeRethrow(IOException.class); 414 throw new RuntimeException(e); 415 } catch (RemoteException e) { 416 throw e.rethrowFromSystemServer(); 417 } 418 } 419 420 /** 421 * Return all of crate information for the specified storageUuid, packageName, and 422 * userHandle. 423 * 424 * @param storageUuid the UUID of the storage volume you're interested in, 425 * such as {@link StorageManager#UUID_DEFAULT}. 426 * @param user the user you're interested in. 427 * @return the collection of crate information. 428 * @throws PackageManager.NameNotFoundException when the package name is not found. 429 * @throws IOException cause by IO, not support, or the other reasons. 430 * @hide 431 */ 432 @WorkerThread 433 @TestApi 434 @RequiresPermission(android.Manifest.permission.MANAGE_CRATES) 435 @NonNull queryCratesForUser(@onNull UUID storageUuid, @NonNull UserHandle user)436 public Collection<CrateInfo> queryCratesForUser(@NonNull UUID storageUuid, 437 @NonNull UserHandle user) throws PackageManager.NameNotFoundException, IOException { 438 try { 439 ParceledListSlice<CrateInfo> crateInfoList = 440 mService.queryCratesForUser(convert(storageUuid), user.getIdentifier(), 441 mContext.getOpPackageName()); 442 return Objects.requireNonNull(crateInfoList).getList(); 443 } catch (ParcelableException e) { 444 e.maybeRethrow(PackageManager.NameNotFoundException.class); 445 e.maybeRethrow(IOException.class); 446 throw new RuntimeException(e); 447 } catch (RemoteException e) { 448 throw e.rethrowFromSystemServer(); 449 } 450 } 451 } 452