450 lines
18 KiB
Java
450 lines
18 KiB
Java
/*
|
|
* 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 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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
|
|
/** {@hide} */
|
|
@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();
|
|
}
|
|
}
|
|
}
|