Merge "Add queryStatsForPackage() API."
This commit is contained in:
@@ -6882,6 +6882,7 @@ package android.app.usage {
|
||||
method public long getFreeBytes(java.lang.String);
|
||||
method public long getTotalBytes(java.lang.String);
|
||||
method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle);
|
||||
method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
|
||||
method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle);
|
||||
}
|
||||
|
||||
@@ -7304,6 +7304,7 @@ package android.app.usage {
|
||||
method public long getFreeBytes(java.lang.String);
|
||||
method public long getTotalBytes(java.lang.String);
|
||||
method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle);
|
||||
method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
|
||||
method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle);
|
||||
}
|
||||
|
||||
@@ -6908,6 +6908,7 @@ package android.app.usage {
|
||||
method public long getFreeBytes(java.lang.String);
|
||||
method public long getTotalBytes(java.lang.String);
|
||||
method public android.app.usage.ExternalStorageStats queryExternalStatsForUser(java.lang.String, android.os.UserHandle);
|
||||
method public android.app.usage.StorageStats queryStatsForPackage(java.lang.String, java.lang.String, android.os.UserHandle);
|
||||
method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
|
||||
method public android.app.usage.StorageStats queryStatsForUser(java.lang.String, android.os.UserHandle);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ interface IStorageStatsManager {
|
||||
boolean isQuotaSupported(String volumeUuid, String callingPackage);
|
||||
long getTotalBytes(String volumeUuid, String callingPackage);
|
||||
long getFreeBytes(String volumeUuid, String callingPackage);
|
||||
StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId, String callingPackage);
|
||||
StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage);
|
||||
StorageStats queryStatsForUser(String volumeUuid, int userId, String callingPackage);
|
||||
ExternalStorageStats queryExternalStatsForUser(String volumeUuid, int userId, String callingPackage);
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.app.usage;
|
||||
import android.annotation.WorkerThread;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
|
||||
@@ -99,6 +100,37 @@ public class StorageStatsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return storage statistics for a specific package on the requested storage
|
||||
* volume.
|
||||
* <p>
|
||||
* This method may take several seconds to calculate the requested values,
|
||||
* so it should only be called from a worker thread.
|
||||
* <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(String, int)}, which is typically faster.
|
||||
* </p>
|
||||
*
|
||||
* @param volumeUuid the UUID of the storage volume you're interested in, or
|
||||
* {@code null} to specify the default internal storage.
|
||||
* @param packageName the package name you're interested in.
|
||||
* @param user the user you're interested in.
|
||||
* @see ApplicationInfo#volumeUuid
|
||||
* @see PackageInfo#packageName
|
||||
*/
|
||||
@WorkerThread
|
||||
public StorageStats queryStatsForPackage(String volumeUuid, String packageName,
|
||||
UserHandle user) {
|
||||
try {
|
||||
return mService.queryStatsForPackage(volumeUuid, packageName, user.getIdentifier(),
|
||||
mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return storage statistics for a specific UID on the requested storage
|
||||
* volume.
|
||||
|
||||
@@ -770,4 +770,17 @@ public class FileUtils {
|
||||
|
||||
return dir.mkdir() ? dir : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the given size of a storage device to a nice round power-of-two
|
||||
* value, such as 256MB or 32GB. This avoids showing weird values like
|
||||
* "29.5GB" in UI.
|
||||
*/
|
||||
public static long roundStorageSize(long size) {
|
||||
long res = 1;
|
||||
while (res < size) {
|
||||
res <<= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +311,28 @@ public class FileUtilsTest extends AndroidTestCase {
|
||||
assertNameEquals("test.foo (1).bar", FileUtils.buildUniqueFile(mTarget, "test.foo.bar"));
|
||||
}
|
||||
|
||||
public void testRoundStorageSize() throws Exception {
|
||||
final long M128 = 134217728L;
|
||||
final long M256 = M128 * 2;
|
||||
final long M512 = M256 * 2;
|
||||
final long M1024 = M512 * 2;
|
||||
final long G16 = M1024 * 16;
|
||||
final long G32 = M1024 * 32;
|
||||
final long G64 = M1024 * 64;
|
||||
|
||||
assertEquals(M128, FileUtils.roundStorageSize(M128));
|
||||
assertEquals(M256, FileUtils.roundStorageSize(M128 + 1));
|
||||
assertEquals(M256, FileUtils.roundStorageSize(M256 - 1));
|
||||
assertEquals(M256, FileUtils.roundStorageSize(M256));
|
||||
assertEquals(M512, FileUtils.roundStorageSize(M256 + 1));
|
||||
|
||||
assertEquals(G16, FileUtils.roundStorageSize(G16));
|
||||
assertEquals(G32, FileUtils.roundStorageSize(G16 + 1));
|
||||
assertEquals(G32, FileUtils.roundStorageSize(G32 - 1));
|
||||
assertEquals(G32, FileUtils.roundStorageSize(G32));
|
||||
assertEquals(G64, FileUtils.roundStorageSize(G32 + 1));
|
||||
}
|
||||
|
||||
private static void assertNameEquals(String expected, File actual) {
|
||||
assertEquals(expected, actual.getName());
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.content.pm.PackageStats;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
@@ -148,11 +149,10 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
enforcePermission(Binder.getCallingUid(), callingPackage);
|
||||
|
||||
if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
|
||||
// TODO: round total size to nearest power of two
|
||||
return mStorage.getPrimaryStorageSize();
|
||||
return FileUtils.roundStorageSize(mStorage.getPrimaryStorageSize());
|
||||
} else {
|
||||
final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
|
||||
return vol.disk.size;
|
||||
return FileUtils.roundStorageSize(vol.disk.size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,43 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId,
|
||||
String callingPackage) {
|
||||
enforcePermission(Binder.getCallingUid(), callingPackage);
|
||||
if (userId != UserHandle.getCallingUserId()) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
|
||||
}
|
||||
|
||||
final ApplicationInfo appInfo;
|
||||
try {
|
||||
appInfo = mPackage.getApplicationInfoAsUser(packageName, 0, userId);
|
||||
} catch (NameNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
if (mPackage.getPackagesForUid(appInfo.uid).length == 1) {
|
||||
// Only one package inside UID means we can fast-path
|
||||
return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
|
||||
} else {
|
||||
// Multiple packages means we need to go manual
|
||||
final int appId = UserHandle.getUserId(appInfo.uid);
|
||||
final String[] packageNames = new String[] { packageName };
|
||||
final long[] ceDataInodes = new long[1];
|
||||
final String[] codePaths = new String[] { appInfo.getCodePath() };
|
||||
|
||||
final PackageStats stats = new PackageStats(TAG);
|
||||
try {
|
||||
mInstaller.getAppSize(volumeUuid, packageNames, userId, 0,
|
||||
appId, ceDataInodes, codePaths, stats);
|
||||
} catch (InstallerException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return translate(stats);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage) {
|
||||
enforcePermission(Binder.getCallingUid(), callingPackage);
|
||||
|
||||
Reference in New Issue
Block a user