Merge "Fix code accounting bugs, track external app data." into oc-dev
This commit is contained in:
@@ -6925,6 +6925,7 @@ package android.app.usage {
|
||||
|
||||
public final class ExternalStorageStats implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public long getAppBytes();
|
||||
method public long getAudioBytes();
|
||||
method public long getImageBytes();
|
||||
method public long getTotalBytes();
|
||||
|
||||
@@ -7390,6 +7390,7 @@ package android.app.usage {
|
||||
|
||||
public final class ExternalStorageStats implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public long getAppBytes();
|
||||
method public long getAudioBytes();
|
||||
method public long getImageBytes();
|
||||
method public long getTotalBytes();
|
||||
|
||||
@@ -6955,6 +6955,7 @@ package android.app.usage {
|
||||
|
||||
public final class ExternalStorageStats implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public long getAppBytes();
|
||||
method public long getAudioBytes();
|
||||
method public long getImageBytes();
|
||||
method public long getTotalBytes();
|
||||
|
||||
@@ -31,6 +31,7 @@ public final class ExternalStorageStats implements Parcelable {
|
||||
/** {@hide} */ public long audioBytes;
|
||||
/** {@hide} */ public long videoBytes;
|
||||
/** {@hide} */ public long imageBytes;
|
||||
/** {@hide} */ public long appBytes;
|
||||
|
||||
/**
|
||||
* Return the total bytes used by all files in the shared/external storage
|
||||
@@ -64,6 +65,17 @@ public final class ExternalStorageStats implements Parcelable {
|
||||
return imageBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total bytes used by app files in the shared/external storage
|
||||
* hosted on this volume.
|
||||
* <p>
|
||||
* This data is already accounted against individual apps as returned
|
||||
* through {@link StorageStats}.
|
||||
*/
|
||||
public long getAppBytes() {
|
||||
return appBytes;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public ExternalStorageStats() {
|
||||
}
|
||||
@@ -74,6 +86,7 @@ public final class ExternalStorageStats implements Parcelable {
|
||||
this.audioBytes = in.readLong();
|
||||
this.videoBytes = in.readLong();
|
||||
this.imageBytes = in.readLong();
|
||||
this.appBytes = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,6 +100,7 @@ public final class ExternalStorageStats implements Parcelable {
|
||||
dest.writeLong(audioBytes);
|
||||
dest.writeLong(videoBytes);
|
||||
dest.writeLong(imageBytes);
|
||||
dest.writeLong(appBytes);
|
||||
}
|
||||
|
||||
public static final Creator<ExternalStorageStats> CREATOR = new Creator<ExternalStorageStats>() {
|
||||
|
||||
@@ -22,12 +22,8 @@ import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
* Storage statistics for a UID or {@link UserHandle} on a single storage
|
||||
* volume.
|
||||
* <p class="note">
|
||||
* Note: multiple packages using the same {@code sharedUserId} in their manifest
|
||||
* will be merged into a single UID.
|
||||
* </p>
|
||||
* Storage statistics for a UID, package, or {@link UserHandle} on a single
|
||||
* storage volume.
|
||||
*
|
||||
* @see StorageStatsManager
|
||||
*/
|
||||
@@ -40,6 +36,9 @@ public final class StorageStats implements Parcelable {
|
||||
* Return the size of all code. This includes {@code APK} files and
|
||||
* optimized compiler output.
|
||||
* <p>
|
||||
* If the primary external/shared storage is hosted on this storage device,
|
||||
* then this includes files stored under {@link Context#getObbDir()}.
|
||||
* <p>
|
||||
* Code is shared between all users on a multiuser device.
|
||||
*/
|
||||
public long getCodeBytes() {
|
||||
@@ -51,6 +50,12 @@ public final class StorageStats implements Parcelable {
|
||||
* {@link Context#getDataDir()}, {@link Context#getCacheDir()},
|
||||
* {@link Context#getCodeCacheDir()}.
|
||||
* <p>
|
||||
* If the primary external/shared storage is hosted on this storage device,
|
||||
* then this includes files stored under
|
||||
* {@link Context#getExternalFilesDir(String)},
|
||||
* {@link Context#getExternalCacheDir()}, and
|
||||
* {@link Context#getExternalMediaDirs()}.
|
||||
* <p>
|
||||
* Data is isolated for each user on a multiuser device.
|
||||
*/
|
||||
public long getDataBytes() {
|
||||
@@ -61,6 +66,10 @@ public final class StorageStats implements Parcelable {
|
||||
* Return the size of all cached data. This includes files stored under
|
||||
* {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}.
|
||||
* <p>
|
||||
* If the primary external/shared storage is hosted on this storage device,
|
||||
* then this includes files stored under
|
||||
* {@link Context#getExternalCacheDir()}.
|
||||
* <p>
|
||||
* Cached data is isolated for each user on a multiuser device.
|
||||
*/
|
||||
public long getCacheBytes() {
|
||||
|
||||
@@ -73,7 +73,8 @@ public class StorageStatsManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total size of the media hosting this storage volume.
|
||||
* Return the total size of the underlying media that is hosting this
|
||||
* storage volume.
|
||||
* <p>
|
||||
* To reduce end user confusion, this value matches the total storage size
|
||||
* advertised in a retail environment, which is typically larger than the
|
||||
|
||||
@@ -730,7 +730,7 @@ public class StorageManager {
|
||||
*/
|
||||
public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
|
||||
Preconditions.checkNotNull(path);
|
||||
final String pathString = path.getAbsolutePath();
|
||||
final String pathString = path.getCanonicalPath();
|
||||
if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
|
||||
return UUID_DEFAULT;
|
||||
}
|
||||
|
||||
@@ -258,10 +258,11 @@ public class Installer extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
public long[] getExternalSize(String uuid, int userId, int flags) throws InstallerException {
|
||||
public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds)
|
||||
throws InstallerException {
|
||||
if (!checkBeforeRemote()) return new long[4];
|
||||
try {
|
||||
return mInstalld.getExternalSize(uuid, userId, flags);
|
||||
return mInstalld.getExternalSize(uuid, userId, flags, appIds);
|
||||
} catch (Exception e) {
|
||||
throw InstallerException.from(e);
|
||||
}
|
||||
|
||||
@@ -120,15 +120,7 @@ public class InstallerTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testGetUserSize() throws Exception {
|
||||
int[] appIds = null;
|
||||
|
||||
final PackageManager pm = getContext().getPackageManager();
|
||||
for (ApplicationInfo app : pm.getInstalledApplications(0)) {
|
||||
final int appId = UserHandle.getAppId(app.uid);
|
||||
if (!ArrayUtils.contains(appIds, appId)) {
|
||||
appIds = ArrayUtils.appendInt(appIds, appId);
|
||||
}
|
||||
}
|
||||
final int[] appIds = getAppIds(UserHandle.USER_SYSTEM);
|
||||
|
||||
final PackageStats stats = new PackageStats("android");
|
||||
final PackageStats quotaStats = new PackageStats("android");
|
||||
@@ -147,13 +139,15 @@ public class InstallerTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testGetExternalSize() throws Exception {
|
||||
final int[] appIds = getAppIds(UserHandle.USER_SYSTEM);
|
||||
|
||||
mManual.start();
|
||||
final long[] stats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 0);
|
||||
final long[] stats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM, 0, appIds);
|
||||
mManual.stop();
|
||||
|
||||
mQuota.start();
|
||||
final long[] quotaStats = mInstaller.getExternalSize(null, UserHandle.USER_SYSTEM,
|
||||
Installer.FLAG_USE_QUOTA);
|
||||
Installer.FLAG_USE_QUOTA, appIds);
|
||||
mQuota.stop();
|
||||
|
||||
for (int i = 0; i < stats.length; i++) {
|
||||
@@ -161,6 +155,18 @@ public class InstallerTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private int[] getAppIds(int userId) {
|
||||
int[] appIds = null;
|
||||
for (ApplicationInfo app : getContext().getPackageManager().getInstalledApplicationsAsUser(
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) {
|
||||
final int appId = UserHandle.getAppId(app.uid);
|
||||
if (!ArrayUtils.contains(appIds, appId)) {
|
||||
appIds = ArrayUtils.appendInt(appIds, appId);
|
||||
}
|
||||
}
|
||||
return appIds;
|
||||
}
|
||||
|
||||
private static void checkEquals(String msg, PackageStats a, PackageStats b) {
|
||||
checkEquals(msg + " codeSize", a.codeSize, b.codeSize);
|
||||
checkEquals(msg + " dataSize", a.dataSize, b.dataSize);
|
||||
|
||||
@@ -235,7 +235,14 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
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() };
|
||||
String[] codePaths = new String[0];
|
||||
|
||||
if (appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
|
||||
// We don't count code baked into system image
|
||||
} else {
|
||||
codePaths = ArrayUtils.appendElement(String.class, codePaths,
|
||||
appInfo.getCodePath());
|
||||
}
|
||||
|
||||
final PackageStats stats = new PackageStats(TAG);
|
||||
try {
|
||||
@@ -261,12 +268,18 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
|
||||
final String[] packageNames = mPackage.getPackagesForUid(uid);
|
||||
final long[] ceDataInodes = new long[packageNames.length];
|
||||
final String[] codePaths = new String[packageNames.length];
|
||||
String[] codePaths = new String[0];
|
||||
|
||||
for (int i = 0; i < packageNames.length; i++) {
|
||||
try {
|
||||
codePaths[i] = mPackage.getApplicationInfoAsUser(packageNames[i],
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId).getCodePath();
|
||||
final ApplicationInfo appInfo = mPackage.getApplicationInfoAsUser(packageNames[i],
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
|
||||
if (appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
|
||||
// We don't count code baked into system image
|
||||
} else {
|
||||
codePaths = ArrayUtils.appendElement(String.class, codePaths,
|
||||
appInfo.getCodePath());
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
throw new ParcelableException(e);
|
||||
}
|
||||
@@ -297,15 +310,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
|
||||
}
|
||||
|
||||
int[] appIds = null;
|
||||
for (ApplicationInfo app : mPackage.getInstalledApplicationsAsUser(
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) {
|
||||
final int appId = UserHandle.getAppId(app.uid);
|
||||
if (!ArrayUtils.contains(appIds, appId)) {
|
||||
appIds = ArrayUtils.appendInt(appIds, appId);
|
||||
}
|
||||
}
|
||||
|
||||
final int[] appIds = getAppIds(userId);
|
||||
final PackageStats stats = new PackageStats(TAG);
|
||||
try {
|
||||
mInstaller.getUserSize(volumeUuid, userId, getDefaultFlags(), appIds, stats);
|
||||
@@ -330,12 +335,14 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
|
||||
}
|
||||
|
||||
final int[] appIds = getAppIds(userId);
|
||||
final long[] stats;
|
||||
try {
|
||||
stats = mInstaller.getExternalSize(volumeUuid, userId, getDefaultFlags());
|
||||
stats = mInstaller.getExternalSize(volumeUuid, userId, getDefaultFlags(), appIds);
|
||||
|
||||
if (SystemProperties.getBoolean(PROP_VERIFY_STORAGE, false)) {
|
||||
final long[] manualStats = mInstaller.getExternalSize(volumeUuid, userId, 0);
|
||||
final long[] manualStats = mInstaller.getExternalSize(volumeUuid, userId, 0,
|
||||
appIds);
|
||||
checkEquals("External " + userId, manualStats, stats);
|
||||
}
|
||||
} catch (InstallerException e) {
|
||||
@@ -347,9 +354,22 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
|
||||
res.audioBytes = stats[1];
|
||||
res.videoBytes = stats[2];
|
||||
res.imageBytes = stats[3];
|
||||
res.appBytes = stats[4];
|
||||
return res;
|
||||
}
|
||||
|
||||
private int[] getAppIds(int userId) {
|
||||
int[] appIds = null;
|
||||
for (ApplicationInfo app : mPackage.getInstalledApplicationsAsUser(
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId)) {
|
||||
final int appId = UserHandle.getAppId(app.uid);
|
||||
if (!ArrayUtils.contains(appIds, appId)) {
|
||||
appIds = ArrayUtils.appendInt(appIds, appId);
|
||||
}
|
||||
}
|
||||
return appIds;
|
||||
}
|
||||
|
||||
private static int getDefaultFlags() {
|
||||
if (SystemProperties.getBoolean(PROP_DISABLE_QUOTA, false)) {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user