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.SystemService; 24 import android.annotation.TestApi; 25 import android.annotation.WorkerThread; 26 import android.content.Context; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageManager; 30 import android.os.ParcelableException; 31 import android.os.RemoteException; 32 import android.os.UserHandle; 33 import android.os.storage.StorageManager; 34 35 import com.android.internal.util.Preconditions; 36 37 import java.io.File; 38 import java.io.IOException; 39 import java.util.UUID; 40 41 /** 42 * Access to detailed storage statistics. This provides a summary of how apps, 43 * users, and external/shared storage is utilizing disk space. 44 * <p class="note"> 45 * Note: no permissions are required when calling these APIs for your own 46 * package or UID. However, requesting details for any other package requires 47 * the {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 48 * is a system-level permission that will not be granted to normal apps. 49 * Declaring that permission expresses your intention to use this API and an end 50 * user can then choose to grant this permission through the Settings 51 * application. 52 * </p> 53 */ 54 @SystemService(Context.STORAGE_STATS_SERVICE) 55 public class StorageStatsManager { 56 private final Context mContext; 57 private final IStorageStatsManager mService; 58 59 /** {@hide} */ StorageStatsManager(Context context, IStorageStatsManager service)60 public StorageStatsManager(Context context, IStorageStatsManager service) { 61 mContext = Preconditions.checkNotNull(context); 62 mService = Preconditions.checkNotNull(service); 63 } 64 65 /** {@hide} */ 66 @TestApi isQuotaSupported(@onNull UUID storageUuid)67 public boolean isQuotaSupported(@NonNull UUID storageUuid) { 68 try { 69 return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName()); 70 } catch (RemoteException e) { 71 throw e.rethrowFromSystemServer(); 72 } 73 } 74 75 /** @removed */ 76 @Deprecated isQuotaSupported(String uuid)77 public boolean isQuotaSupported(String uuid) { 78 return isQuotaSupported(convert(uuid)); 79 } 80 81 /** 82 * Return the total size of the underlying physical media that is hosting 83 * this storage volume. 84 * <p> 85 * This value is best suited for visual display to end users, since it's 86 * designed to reflect the total storage size advertised in a retail 87 * environment. 88 * <p> 89 * Apps making logical decisions about disk space should always use 90 * {@link File#getTotalSpace()} instead of this value. 91 * 92 * @param storageUuid the UUID of the storage volume you're interested in, 93 * such as {@link StorageManager#UUID_DEFAULT}. 94 * @throws IOException when the storage device isn't present. 95 */ 96 @WorkerThread getTotalBytes(@onNull UUID storageUuid)97 public @BytesLong long getTotalBytes(@NonNull UUID storageUuid) throws IOException { 98 try { 99 return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName()); 100 } catch (ParcelableException e) { 101 e.maybeRethrow(IOException.class); 102 throw new RuntimeException(e); 103 } catch (RemoteException e) { 104 throw e.rethrowFromSystemServer(); 105 } 106 } 107 108 /** @removed */ 109 @Deprecated getTotalBytes(String uuid)110 public long getTotalBytes(String uuid) throws IOException { 111 return getTotalBytes(convert(uuid)); 112 } 113 114 /** 115 * Return the free space on the requested storage volume. 116 * <p> 117 * This value is best suited for visual display to end users, since it's 118 * designed to reflect both unused space <em>and</em> and cached space that 119 * could be reclaimed by the system. 120 * <p> 121 * Apps making logical decisions about disk space should always use 122 * {@link StorageManager#getAllocatableBytes(UUID, int)} instead of this 123 * value. 124 * 125 * @param storageUuid the UUID of the storage volume you're interested in, 126 * such as {@link StorageManager#UUID_DEFAULT}. 127 * @throws IOException when the storage device isn't present. 128 */ 129 @WorkerThread getFreeBytes(@onNull UUID storageUuid)130 public @BytesLong long getFreeBytes(@NonNull UUID storageUuid) throws IOException { 131 try { 132 return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName()); 133 } catch (ParcelableException e) { 134 e.maybeRethrow(IOException.class); 135 throw new RuntimeException(e); 136 } catch (RemoteException e) { 137 throw e.rethrowFromSystemServer(); 138 } 139 } 140 141 /** @removed */ 142 @Deprecated getFreeBytes(String uuid)143 public long getFreeBytes(String uuid) throws IOException { 144 return getFreeBytes(convert(uuid)); 145 } 146 147 /** {@hide} */ getCacheBytes(@onNull UUID storageUuid)148 public @BytesLong long getCacheBytes(@NonNull UUID storageUuid) throws IOException { 149 try { 150 return mService.getCacheBytes(convert(storageUuid), mContext.getOpPackageName()); 151 } catch (ParcelableException e) { 152 e.maybeRethrow(IOException.class); 153 throw new RuntimeException(e); 154 } catch (RemoteException e) { 155 throw e.rethrowFromSystemServer(); 156 } 157 } 158 159 /** {@hide} */ 160 @Deprecated getCacheBytes(String uuid)161 public long getCacheBytes(String uuid) throws IOException { 162 return getCacheBytes(convert(uuid)); 163 } 164 165 /** 166 * Return storage statistics for a specific package on the requested storage 167 * volume. 168 * <p class="note"> 169 * Note: no permissions are required when calling this API for your own 170 * package. However, requesting details for any other package requires the 171 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 172 * is a system-level permission that will not be granted to normal apps. 173 * Declaring that permission expresses your intention to use this API and an 174 * end user can then choose to grant this permission through the Settings 175 * application. 176 * </p> 177 * <p class="note"> 178 * Note: if the requested package uses the {@code android:sharedUserId} 179 * manifest feature, this call will be forced into a slower manual 180 * calculation path. If possible, consider always using 181 * {@link #queryStatsForUid(UUID, int)}, which is typically faster. 182 * </p> 183 * 184 * @param storageUuid the UUID of the storage volume you're interested in, 185 * such as {@link StorageManager#UUID_DEFAULT}. 186 * @param packageName the package name you're interested in. 187 * @param user the user you're interested in. 188 * @throws PackageManager.NameNotFoundException when the requested package 189 * name isn't installed for the requested user. 190 * @throws IOException when the storage device isn't present. 191 * @see ApplicationInfo#storageUuid 192 * @see PackageInfo#packageName 193 */ 194 @WorkerThread queryStatsForPackage(@onNull UUID storageUuid, @NonNull String packageName, @NonNull UserHandle user)195 public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid, 196 @NonNull String packageName, @NonNull UserHandle user) 197 throws PackageManager.NameNotFoundException, IOException { 198 try { 199 return mService.queryStatsForPackage(convert(storageUuid), packageName, 200 user.getIdentifier(), mContext.getOpPackageName()); 201 } catch (ParcelableException e) { 202 e.maybeRethrow(PackageManager.NameNotFoundException.class); 203 e.maybeRethrow(IOException.class); 204 throw new RuntimeException(e); 205 } catch (RemoteException e) { 206 throw e.rethrowFromSystemServer(); 207 } 208 } 209 210 /** @removed */ 211 @Deprecated queryStatsForPackage(String uuid, String packageName, UserHandle user)212 public StorageStats queryStatsForPackage(String uuid, String packageName, 213 UserHandle user) throws PackageManager.NameNotFoundException, IOException { 214 return queryStatsForPackage(convert(uuid), packageName, user); 215 } 216 217 /** 218 * Return storage statistics for a specific UID on the requested storage 219 * volume. 220 * <p class="note"> 221 * Note: no permissions are required when calling this API for your own UID. 222 * However, requesting details for any other UID requires the 223 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 224 * is a system-level permission that will not be granted to normal apps. 225 * Declaring that permission expresses your intention to use this API and an 226 * end user can then choose to grant this permission through the Settings 227 * application. 228 * </p> 229 * 230 * @param storageUuid the UUID of the storage volume you're interested in, 231 * such as {@link StorageManager#UUID_DEFAULT}. 232 * @param uid the UID you're interested in. 233 * @throws IOException when the storage device isn't present. 234 * @see ApplicationInfo#storageUuid 235 * @see ApplicationInfo#uid 236 */ 237 @WorkerThread queryStatsForUid(@onNull UUID storageUuid, int uid)238 public @NonNull StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid) 239 throws IOException { 240 try { 241 return mService.queryStatsForUid(convert(storageUuid), uid, 242 mContext.getOpPackageName()); 243 } catch (ParcelableException e) { 244 e.maybeRethrow(IOException.class); 245 throw new RuntimeException(e); 246 } catch (RemoteException e) { 247 throw e.rethrowFromSystemServer(); 248 } 249 } 250 251 /** @removed */ 252 @Deprecated queryStatsForUid(String uuid, int uid)253 public StorageStats queryStatsForUid(String uuid, int uid) throws IOException { 254 return queryStatsForUid(convert(uuid), uid); 255 } 256 257 /** 258 * Return storage statistics for a specific {@link UserHandle} on the 259 * requested storage volume. 260 * <p class="note"> 261 * Note: this API requires the 262 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 263 * is a system-level permission that will not be granted to normal apps. 264 * Declaring that permission expresses your intention to use this API and an 265 * end user can then choose to grant this permission through the Settings 266 * application. 267 * </p> 268 * 269 * @param storageUuid the UUID of the storage volume you're interested in, 270 * such as {@link StorageManager#UUID_DEFAULT}. 271 * @param user the user you're interested in. 272 * @throws IOException when the storage device isn't present. 273 * @see android.os.Process#myUserHandle() 274 */ 275 @WorkerThread queryStatsForUser(@onNull UUID storageUuid, @NonNull UserHandle user)276 public @NonNull StorageStats queryStatsForUser(@NonNull UUID storageUuid, 277 @NonNull UserHandle user) throws IOException { 278 try { 279 return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(), 280 mContext.getOpPackageName()); 281 } catch (ParcelableException e) { 282 e.maybeRethrow(IOException.class); 283 throw new RuntimeException(e); 284 } catch (RemoteException e) { 285 throw e.rethrowFromSystemServer(); 286 } 287 } 288 289 /** @removed */ 290 @Deprecated queryStatsForUser(String uuid, UserHandle user)291 public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException { 292 return queryStatsForUser(convert(uuid), user); 293 } 294 295 /** 296 * Return shared/external storage statistics for a specific 297 * {@link UserHandle} on the requested storage volume. 298 * <p class="note"> 299 * Note: this API requires the 300 * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which 301 * is a system-level permission that will not be granted to normal apps. 302 * Declaring that permission expresses your intention to use this API and an 303 * end user can then choose to grant this permission through the Settings 304 * application. 305 * </p> 306 * 307 * @param storageUuid the UUID of the storage volume you're interested in, 308 * such as {@link StorageManager#UUID_DEFAULT}. 309 * @throws IOException when the storage device isn't present. 310 * @see android.os.Process#myUserHandle() 311 */ 312 @WorkerThread queryExternalStatsForUser(@onNull UUID storageUuid, @NonNull UserHandle user)313 public @NonNull ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid, 314 @NonNull UserHandle user) throws IOException { 315 try { 316 return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(), 317 mContext.getOpPackageName()); 318 } catch (ParcelableException e) { 319 e.maybeRethrow(IOException.class); 320 throw new RuntimeException(e); 321 } catch (RemoteException e) { 322 throw e.rethrowFromSystemServer(); 323 } 324 } 325 326 /** @removed */ 327 @Deprecated queryExternalStatsForUser(String uuid, UserHandle user)328 public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user) 329 throws IOException { 330 return queryExternalStatsForUser(convert(uuid), user); 331 } 332 333 /** {@hide} */ getCacheQuotaBytes(String volumeUuid, int uid)334 public long getCacheQuotaBytes(String volumeUuid, int uid) { 335 try { 336 return mService.getCacheQuotaBytes(volumeUuid, uid, mContext.getOpPackageName()); 337 } catch (RemoteException e) { 338 throw e.rethrowFromSystemServer(); 339 } 340 } 341 } 342