blob: 1ef15637d5785b4fa3081a20a96af2a97b6d4f08 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.usage;
import static android.os.storage.StorageManager.convert;
import android.annotation.BytesLong;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.os.ParcelableException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.CrateInfo;
import android.os.storage.StorageManager;
import com.android.internal.util.Preconditions;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
/**
* Access to detailed storage statistics. This provides a summary of how apps,
* users, and external/shared storage is utilizing disk space.
* <p class="note">
* Note: no permissions are required when calling these APIs for your own
* package or UID. However, requesting details for any other package requires
* the {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
* is a system-level permission that will not be granted to normal apps.
* Declaring that permission expresses your intention to use this API and an end
* user can then choose to grant this permission through the Settings
* application.
* </p>
*/
@SystemService(Context.STORAGE_STATS_SERVICE)
public class StorageStatsManager {
private final Context mContext;
private final IStorageStatsManager mService;
/** {@hide} */
public StorageStatsManager(Context context, IStorageStatsManager service) {
mContext = Objects.requireNonNull(context);
mService = Objects.requireNonNull(service);
}
/** {@hide} */
@TestApi
public boolean isQuotaSupported(@NonNull UUID storageUuid) {
try {
return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public boolean isQuotaSupported(String uuid) {
return isQuotaSupported(convert(uuid));
}
/** {@hide} */
@TestApi
public boolean isReservedSupported(@NonNull UUID storageUuid) {
try {
return mService.isReservedSupported(convert(storageUuid), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Return the total size of the underlying physical media that is hosting
* this storage volume.
* <p>
* This value is best suited for visual display to end users, since it's
* designed to reflect the total storage size advertised in a retail
* environment.
* <p>
* Apps making logical decisions about disk space should always use
* {@link File#getTotalSpace()} instead of this value.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @throws IOException when the storage device isn't present.
*/
@WorkerThread
public @BytesLong long getTotalBytes(@NonNull UUID storageUuid) throws IOException {
try {
return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public long getTotalBytes(String uuid) throws IOException {
return getTotalBytes(convert(uuid));
}
/**
* Return the free space on the requested storage volume.
* <p>
* This value is best suited for visual display to end users, since it's
* designed to reflect both unused space <em>and</em> and cached space that
* could be reclaimed by the system.
* <p>
* Apps making logical decisions about disk space should always use
* {@link StorageManager#getAllocatableBytes(UUID)} instead of this value.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @throws IOException when the storage device isn't present.
*/
@WorkerThread
public @BytesLong long getFreeBytes(@NonNull UUID storageUuid) throws IOException {
try {
return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public long getFreeBytes(String uuid) throws IOException {
return getFreeBytes(convert(uuid));
}
/** {@hide} */
public @BytesLong long getCacheBytes(@NonNull UUID storageUuid) throws IOException {
try {
return mService.getCacheBytes(convert(storageUuid), mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** {@hide} */
@Deprecated
public long getCacheBytes(String uuid) throws IOException {
return getCacheBytes(convert(uuid));
}
/**
* Return storage statistics for a specific package on the requested storage
* volume.
* <p class="note">
* Note: no permissions are required when calling this API for your own
* package. However, requesting details for any other package requires the
* {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
* is a system-level permission that will not be granted to normal apps.
* Declaring that permission expresses your intention to use this API and an
* end user can then choose to grant this permission through the Settings
* application.
* </p>
* <p class="note">
* Note: if the requested package uses the {@code android:sharedUserId}
* manifest feature, this call will be forced into a slower manual
* calculation path. If possible, consider always using
* {@link #queryStatsForUid(UUID, int)}, which is typically faster.
* </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @param packageName the package name you're interested in.
* @param user the user you're interested in.
* @throws PackageManager.NameNotFoundException when the requested package
* name isn't installed for the requested user.
* @throws IOException when the storage device isn't present.
* @see ApplicationInfo#storageUuid
* @see PackageInfo#packageName
*/
@WorkerThread
public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid,
@NonNull String packageName, @NonNull UserHandle user)
throws PackageManager.NameNotFoundException, IOException {
try {
return mService.queryStatsForPackage(convert(storageUuid), packageName,
user.getIdentifier(), mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(PackageManager.NameNotFoundException.class);
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public StorageStats queryStatsForPackage(String uuid, String packageName,
UserHandle user) throws PackageManager.NameNotFoundException, IOException {
return queryStatsForPackage(convert(uuid), packageName, user);
}
/**
* Return storage statistics for a specific UID on the requested storage
* volume.
* <p class="note">
* Note: no permissions are required when calling this API for your own UID.
* However, requesting details for any other UID requires the
* {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
* is a system-level permission that will not be granted to normal apps.
* Declaring that permission expresses your intention to use this API and an
* end user can then choose to grant this permission through the Settings
* application.
* </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @param uid the UID you're interested in.
* @throws IOException when the storage device isn't present.
* @see ApplicationInfo#storageUuid
* @see ApplicationInfo#uid
*/
@WorkerThread
public @NonNull StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid)
throws IOException {
try {
return mService.queryStatsForUid(convert(storageUuid), uid,
mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public StorageStats queryStatsForUid(String uuid, int uid) throws IOException {
return queryStatsForUid(convert(uuid), uid);
}
/**
* Return storage statistics for a specific {@link UserHandle} on the
* requested storage volume.
* <p class="note">
* Note: this API requires the
* {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
* is a system-level permission that will not be granted to normal apps.
* Declaring that permission expresses your intention to use this API and an
* end user can then choose to grant this permission through the Settings
* application.
* </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @param user the user you're interested in.
* @throws IOException when the storage device isn't present.
* @see android.os.Process#myUserHandle()
*/
@WorkerThread
public @NonNull StorageStats queryStatsForUser(@NonNull UUID storageUuid,
@NonNull UserHandle user) throws IOException {
try {
return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(),
mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException {
return queryStatsForUser(convert(uuid), user);
}
/**
* Return shared/external storage statistics for a specific
* {@link UserHandle} on the requested storage volume.
* <p class="note">
* Note: this API requires the
* {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
* is a system-level permission that will not be granted to normal apps.
* Declaring that permission expresses your intention to use this API and an
* end user can then choose to grant this permission through the Settings
* application.
* </p>
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @throws IOException when the storage device isn't present.
* @see android.os.Process#myUserHandle()
*/
@WorkerThread
public @NonNull ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid,
@NonNull UserHandle user) throws IOException {
try {
return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(),
mContext.getOpPackageName());
} catch (ParcelableException e) {
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @removed */
@Deprecated
public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user)
throws IOException {
return queryExternalStatsForUser(convert(uuid), user);
}
/** {@hide} */
public long getCacheQuotaBytes(String volumeUuid, int uid) {
try {
return mService.getCacheQuotaBytes(volumeUuid, uid, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Return all of crate information for the specified storageUuid, packageName, and
* userHandle.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @param uid the uid you're interested in.
* @return the collection of crate information.
* @throws PackageManager.NameNotFoundException when the package name is not found.
* @throws IOException cause by IO, not support, or the other reasons.
* @hide
*/
@TestApi
@WorkerThread
@NonNull
public Collection<CrateInfo> queryCratesForUid(@NonNull UUID storageUuid,
int uid) throws IOException, PackageManager.NameNotFoundException {
try {
ParceledListSlice<CrateInfo> crateInfoList =
mService.queryCratesForUid(convert(storageUuid), uid,
mContext.getOpPackageName());
return Objects.requireNonNull(crateInfoList).getList();
} catch (ParcelableException e) {
e.maybeRethrow(PackageManager.NameNotFoundException.class);
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Return all of crates information for the specified storageUuid, packageName, and
* userHandle.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @param packageName the package name you're interested in.
* @param user the user you're interested in.
* @return the collection of crate information.
* @throws PackageManager.NameNotFoundException when the package name is not found.
* @throws IOException cause by IO, not support, or the other reasons.
* @hide
*/
@WorkerThread
@TestApi
@NonNull
public Collection<CrateInfo> queryCratesForPackage(@NonNull UUID storageUuid,
@NonNull String packageName, @NonNull UserHandle user)
throws PackageManager.NameNotFoundException, IOException {
try {
ParceledListSlice<CrateInfo> crateInfoList =
mService.queryCratesForPackage(convert(storageUuid), packageName,
user.getIdentifier(), mContext.getOpPackageName());
return Objects.requireNonNull(crateInfoList).getList();
} catch (ParcelableException e) {
e.maybeRethrow(PackageManager.NameNotFoundException.class);
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Return all of crate information for the specified storageUuid, packageName, and
* userHandle.
*
* @param storageUuid the UUID of the storage volume you're interested in,
* such as {@link StorageManager#UUID_DEFAULT}.
* @param user the user you're interested in.
* @return the collection of crate information.
* @throws PackageManager.NameNotFoundException when the package name is not found.
* @throws IOException cause by IO, not support, or the other reasons.
* @hide
*/
@WorkerThread
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_CRATES)
@NonNull
public Collection<CrateInfo> queryCratesForUser(@NonNull UUID storageUuid,
@NonNull UserHandle user) throws PackageManager.NameNotFoundException, IOException {
try {
ParceledListSlice<CrateInfo> crateInfoList =
mService.queryCratesForUser(convert(storageUuid), user.getIdentifier(),
mContext.getOpPackageName());
return Objects.requireNonNull(crateInfoList).getList();
} catch (ParcelableException e) {
e.maybeRethrow(PackageManager.NameNotFoundException.class);
e.maybeRethrow(IOException.class);
throw new RuntimeException(e);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}