diff options
author | Felka Chang <felkachang@google.com> | 2019-11-20 14:11:13 +0800 |
---|---|---|
committer | Felka Chang <felkachang@google.com> | 2019-12-18 23:04:15 +0800 |
commit | 71e3efed54880539fb5e4522ea25ba24c51d70ff (patch) | |
tree | de1626cbf628aa243cb6a922084a3c4d7e71b1fc /services/usage | |
parent | 344c5447f2b3e2aab1302a3d48852702cb202cac (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')
-rw-r--r-- | services/usage/java/com/android/server/usage/StorageStatsService.java | 163 |
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())); + } + } } |