diff options
-rw-r--r-- | core/api/current.txt | 1 | ||||
-rw-r--r-- | core/java/android/os/storage/IStorageManager.aidl | 3 | ||||
-rw-r--r-- | core/java/android/os/storage/StorageManager.java | 28 | ||||
-rw-r--r-- | services/core/java/com/android/server/StorageManagerService.java | 53 |
4 files changed, 85 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 00dec11c1f56..8710e613602f 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -31868,6 +31868,7 @@ package android.os.storage { method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID) throws java.io.IOException; method @WorkerThread public long getCacheQuotaBytes(@NonNull java.util.UUID) throws java.io.IOException; method @WorkerThread public long getCacheSizeBytes(@NonNull java.util.UUID) throws java.io.IOException; + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) public android.app.PendingIntent getManageSpaceActivityIntent(@NonNull String, int); method public String getMountedObbPath(String); method @NonNull public android.os.storage.StorageVolume getPrimaryStorageVolume(); method @NonNull public java.util.List<android.os.storage.StorageVolume> getRecentStorageVolumes(); diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 0041699df9ef..98b4e0b4f402 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -28,6 +28,8 @@ import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; import com.android.internal.os.AppFuseMount; +import android.app.PendingIntent; + /** * WARNING! Update IMountService.h and IMountService.cpp if you change this @@ -198,4 +200,5 @@ interface IStorageManager { void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90; void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91; void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92; + PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 93; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 7c8874cc1ea7..71a849963818 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -49,6 +49,7 @@ import android.app.Activity; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; @@ -701,6 +702,33 @@ public class StorageManager { } } + /** + * Returns a {@link PendingIntent} that can be used by Apps with + * {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission + * to launch the manageSpaceActivity for any App that implements it, irrespective of its + * exported status. + * <p> + * Caller has the responsibility of supplying a valid packageName which has + * manageSpaceActivity implemented. + * + * @param packageName package name for the App for which manageSpaceActivity is to be launched + * @param requestCode for launching the activity + * @return PendingIntent to launch the manageSpaceActivity if successful, null if the + * packageName doesn't have a manageSpaceActivity. + * @throws IllegalArgumentException an invalid packageName is supplied. + */ + @RequiresPermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE) + @Nullable + public PendingIntent getManageSpaceActivityIntent( + @NonNull String packageName, int requestCode) { + try { + return mStorageManager.getManageSpaceActivityIntent(packageName, + requestCode); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private ObbInfo getObbInfo(String canonicalPath) { try { final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 233a50d417ad..c5233f43dcb9 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -24,6 +24,10 @@ import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE; import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES; import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE; +import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.app.PendingIntent.FLAG_ONE_SHOT; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; @@ -55,6 +59,7 @@ import android.app.AnrController; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.KeyguardManager; +import android.app.PendingIntent; import android.app.admin.SecurityLog; import android.app.usage.StorageStatsManager; import android.content.BroadcastReceiver; @@ -3371,6 +3376,54 @@ class StorageManagerService extends IStorageManager.Stub } } + /** + * Returns PendingIntent which can be used by Apps with MANAGE_EXTERNAL_STORAGE permission + * to launch the manageSpaceActivity of the App specified by packageName. + */ + @Override + @Nullable + public PendingIntent getManageSpaceActivityIntent( + @NonNull String packageName, int requestCode) { + // Only Apps with MANAGE_EXTERNAL_STORAGE permission should be able to call this API. + enforcePermission(android.Manifest.permission.MANAGE_EXTERNAL_STORAGE); + + // We want to call the manageSpaceActivity as a SystemService and clear identity + // of the calling App + int originalUid = Binder.getCallingUidOrThrow(); + long token = Binder.clearCallingIdentity(); + + try { + ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0, + UserHandle.getUserId(originalUid)); + if (appInfo == null) { + throw new IllegalArgumentException( + "Invalid packageName"); + } + if (appInfo.manageSpaceActivityName == null) { + Log.i(TAG, packageName + " doesn't have a manageSpaceActivity"); + return null; + } + Context targetAppContext = mContext.createPackageContext(packageName, 0); + + Intent intent = new Intent(Intent.ACTION_DEFAULT); + intent.setClassName(packageName, + appInfo.manageSpaceActivityName); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK); + + PendingIntent activity = PendingIntent.getActivity(targetAppContext, requestCode, + intent, + FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE); + return activity; + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalArgumentException( + "packageName not found"); + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** Not thread safe */ class AppFuseMountScope extends AppFuseBridge.MountScope { private boolean mMounted = false; |