summaryrefslogtreecommitdiff
path: root/services/usage/java
diff options
context:
space:
mode:
authorFelka Chang <felkachang@google.com>2019-11-20 14:11:13 +0800
committerFelka Chang <felkachang@google.com>2019-12-18 23:04:15 +0800
commit71e3efed54880539fb5e4522ea25ba24c51d70ff (patch)
treede1626cbf628aa243cb6a922084a3c4d7e71b1fc /services/usage/java
parent344c5447f2b3e2aab1302a3d48852702cb202cac (diff)
Add query functionalities to query all of crates
Once the application called Context.getCrateDir(), the crates root directory is also created. The application can mkdir directory under the crates root. Each child directory in crates root is one crate. Each crate information is descibed by CrateInfo. CrateInfo contains the following information. * Label: It is used to display text to the users. Default is the folder name. * Expiration: When the system needs more space. The system will clean the files in the crates according to the expired or not. Default is 0. Test: atest \ CtsOsTestCases:android.os.storage.cts.CrateInfoTest \ CtsOsTestCases:android.os.storage.cts.StorageCrateTest \ CtsOsTestCases:android.os.storage.cts.StorageStatsManagerTest Bug: 141660526 Change-Id: Icdc8123c481ef7c5b4fd68ffcfd334ffbfc9d655
Diffstat (limited to 'services/usage/java')
-rw-r--r--services/usage/java/com/android/server/usage/StorageStatsService.java163
1 files changed, 156 insertions, 7 deletions
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 0f3050f9e3d3..531a93117752 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -19,6 +19,9 @@ package com.android.server.usage;
import static com.android.internal.util.ArrayUtils.defeatNullable;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.usage.ExternalStorageStats;
import android.app.usage.IStorageStatsManager;
@@ -30,6 +33,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageStats;
+import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Binder;
@@ -44,10 +48,13 @@ import android.os.StatFs;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.CrateInfo;
+import android.os.storage.CrateMetadata;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.provider.Settings;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.DataUnit;
@@ -67,6 +74,9 @@ import com.android.server.storage.CacheQuotaStrategy;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
public class StorageStatsService extends IStorageStatsManager.Stub {
private static final String TAG = "StorageStatsService";
@@ -139,7 +149,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
}
}
- private void enforcePermission(int callingUid, String callingPackage) {
+ private void enforceStatsPermission(int callingUid, String callingPackage) {
final int mode = mAppOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS,
callingUid, callingPackage);
switch (mode) {
@@ -222,7 +232,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
@Override
public long getCacheBytes(String volumeUuid, String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ enforceStatsPermission(Binder.getCallingUid(), callingPackage);
long cacheBytes = 0;
for (UserInfo user : mUser.getUsers()) {
@@ -234,7 +244,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
@Override
public long getCacheQuotaBytes(String volumeUuid, int uid, String callingPackage) {
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ enforceStatsPermission(Binder.getCallingUid(), callingPackage);
if (mCacheQuotas.containsKey(volumeUuid)) {
final SparseLongArray uidMap = mCacheQuotas.get(volumeUuid);
@@ -263,7 +273,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
if (Binder.getCallingUid() == appInfo.uid) {
// No permissions required when asking about themselves
} else {
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ enforceStatsPermission(Binder.getCallingUid(), callingPackage);
}
if (defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1) {
@@ -307,7 +317,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
if (Binder.getCallingUid() == uid) {
// No permissions required when asking about themselves
} else {
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ enforceStatsPermission(Binder.getCallingUid(), callingPackage);
}
final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
@@ -354,7 +364,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
}
// Always require permission to see user-level stats
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ enforceStatsPermission(Binder.getCallingUid(), callingPackage);
final int[] appIds = getAppIds(userId);
final PackageStats stats = new PackageStats(TAG);
@@ -381,7 +391,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
}
// Always require permission to see user-level stats
- enforcePermission(Binder.getCallingUid(), callingPackage);
+ enforceStatsPermission(Binder.getCallingUid(), callingPackage);
final int[] appIds = getAppIds(userId);
final long[] stats;
@@ -556,4 +566,143 @@ public class StorageStatsService extends IStorageStatsManager.Stub {
mContext.getContentResolver().notifyChange(
Uri.parse("content://com.android.externalstorage.documents/"), null, false);
}
+
+ /**
+ * To enforce the calling or self to have the {@link android.Manifest.permission#MANAGE_CRATES}
+ * permission.
+ * @param callingUid the calling uid
+ * @param callingPackage the calling package name
+ */
+ private void enforceCratesPermission(int callingUid, String callingPackage) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_CRATES,
+ callingPackage);
+ }
+
+ /**
+ * To copy from CrateMetadata instances into CrateInfo instances.
+ */
+ @NonNull
+ private static List<CrateInfo> convertCrateInfoFrom(@Nullable CrateMetadata[] crateMetadatas) {
+ if (ArrayUtils.isEmpty(crateMetadatas)) {
+ return Collections.EMPTY_LIST;
+ }
+
+ ArrayList<CrateInfo> crateInfos = new ArrayList<>();
+ for (CrateMetadata crateMetadata : crateMetadatas) {
+ if (crateMetadata == null || TextUtils.isEmpty(crateMetadata.id)
+ || TextUtils.isEmpty(crateMetadata.packageName)) {
+ continue;
+ }
+
+ CrateInfo crateInfo = CrateInfo.copyFrom(crateMetadata.uid,
+ crateMetadata.packageName, crateMetadata.id);
+ if (crateInfo == null) {
+ continue;
+ }
+
+ crateInfos.add(crateInfo);
+ }
+
+ return crateInfos;
+ }
+
+ @NonNull
+ private ParceledListSlice<CrateInfo> getAppCrates(String volumeUuid, String[] packageNames,
+ @UserIdInt int userId) {
+ try {
+ CrateMetadata[] crateMetadatas = mInstaller.getAppCrates(volumeUuid,
+ packageNames, userId);
+ return new ParceledListSlice<>(convertCrateInfoFrom(crateMetadatas));
+ } catch (InstallerException e) {
+ throw new ParcelableException(new IOException(e.getMessage()));
+ }
+ }
+
+ @NonNull
+ @Override
+ public ParceledListSlice<CrateInfo> queryCratesForPackage(String volumeUuid,
+ @NonNull String packageName, @UserIdInt int userId, @NonNull String callingPackage) {
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+ }
+
+ final ApplicationInfo appInfo;
+ try {
+ appInfo = mPackage.getApplicationInfoAsUser(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ } catch (NameNotFoundException e) {
+ throw new ParcelableException(e);
+ }
+
+ if (Binder.getCallingUid() == appInfo.uid) {
+ // No permissions required when asking about themselves
+ } else {
+ enforceCratesPermission(Binder.getCallingUid(), callingPackage);
+ }
+
+ final String[] packageNames = new String[] { packageName };
+ return getAppCrates(volumeUuid, packageNames, userId);
+ }
+
+ @NonNull
+ @Override
+ public ParceledListSlice<CrateInfo> queryCratesForUid(String volumeUuid, int uid,
+ @NonNull String callingPackage) {
+ final int userId = UserHandle.getUserId(uid);
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+ }
+
+ if (Binder.getCallingUid() == uid) {
+ // No permissions required when asking about themselves
+ } else {
+ enforceCratesPermission(Binder.getCallingUid(), callingPackage);
+ }
+
+ final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
+ String[] validatedPackageNames = new String[0];
+
+ for (String packageName : packageNames) {
+ if (TextUtils.isEmpty(packageName)) {
+ continue;
+ }
+
+ try {
+ final ApplicationInfo appInfo = mPackage.getApplicationInfoAsUser(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ if (appInfo == null) {
+ continue;
+ }
+
+ validatedPackageNames = ArrayUtils.appendElement(String.class,
+ validatedPackageNames, packageName);
+ } catch (NameNotFoundException e) {
+ throw new ParcelableException(e);
+ }
+ }
+
+ return getAppCrates(volumeUuid, validatedPackageNames, userId);
+ }
+
+ @NonNull
+ @Override
+ public ParceledListSlice<CrateInfo> queryCratesForUser(String volumeUuid, int userId,
+ @NonNull String callingPackage) {
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+ }
+
+ // Always require permission to see user-level stats
+ enforceCratesPermission(Binder.getCallingUid(), callingPackage);
+
+ try {
+ CrateMetadata[] crateMetadatas = mInstaller.getUserCrates(volumeUuid, userId);
+ return new ParceledListSlice<>(convertCrateInfoFrom(crateMetadatas));
+ } catch (InstallerException e) {
+ throw new ParcelableException(new IOException(e.getMessage()));
+ }
+ }
}