OSDN Git Service

Require READ_EXTERNAL_STORAGE to read wallpaper imagery
authorChristopher Tate <ctate@google.com>
Thu, 15 Jun 2017 21:48:41 +0000 (14:48 -0700)
committerChris Tate <ctate@android.com>
Wed, 5 Jul 2017 18:29:53 +0000 (18:29 +0000)
We now require the READ_EXTERNAL_STORAGE permission for an app to
be allowed to read the system's wallpaper imagery.  This is a
logged-but-benign no-op failure for apps targeting API levels up
through Android O, but a crashing failure (SecurityException) for
apps that target API levels newer than O.

Also, marked the permission-requiring parts of the formal API
with appropriate @RequiresPermission annotations.

Bug 30770233
Test: bit CtsPermissionTestCases:.NoWallpaperPermissionsTest

Change-Id: Id75181f05d05e5ca32f5fefcbe15dc81de264dff

core/java/android/app/IWallpaperManager.aidl
core/java/android/app/WallpaperManager.java
services/core/java/com/android/server/wallpaper/WallpaperManagerService.java

index 411d0e2..0e33934 100644 (file)
@@ -60,7 +60,7 @@ interface IWallpaperManager {
     /**
      * Get the wallpaper for a given user.
      */
-    ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, int which,
+    ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb, int which,
             out Bundle outParams, int userId);
 
     /**
index 0b8b689..0398b47 100644 (file)
@@ -48,6 +48,7 @@ import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.DeadSystemException;
 import android.os.Handler;
@@ -404,10 +405,18 @@ public class WallpaperManager {
                 mCachedWallpaper = null;
                 mCachedWallpaperUserId = 0;
                 try {
-                    mCachedWallpaper = getCurrentWallpaperLocked(userId);
+                    mCachedWallpaper = getCurrentWallpaperLocked(context, userId);
                     mCachedWallpaperUserId = userId;
                 } catch (OutOfMemoryError e) {
-                    Log.w(TAG, "No memory load current wallpaper", e);
+                    Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
+                } catch (SecurityException e) {
+                    if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.O) {
+                        Log.w(TAG, "No permission to access wallpaper, suppressing"
+                                + " exception to avoid crashing legacy app.");
+                    } else {
+                        // Post-O apps really most sincerely need the permission.
+                        throw e;
+                    }
                 }
                 if (mCachedWallpaper != null) {
                     return mCachedWallpaper;
@@ -434,7 +443,7 @@ public class WallpaperManager {
             }
         }
 
-        private Bitmap getCurrentWallpaperLocked(int userId) {
+        private Bitmap getCurrentWallpaperLocked(Context context, int userId) {
             if (mService == null) {
                 Log.w(TAG, "WallpaperService not running");
                 return null;
@@ -442,8 +451,8 @@ public class WallpaperManager {
 
             try {
                 Bundle params = new Bundle();
-                ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SYSTEM,
-                        params, userId);
+                ParcelFileDescriptor fd = mService.getWallpaper(context.getOpPackageName(),
+                        this, FLAG_SYSTEM, params, userId);
                 if (fd != null) {
                     try {
                         BitmapFactory.Options options = new BitmapFactory.Options();
@@ -775,6 +784,7 @@ public class WallpaperManager {
      *
      * @return Returns a Drawable object that will draw the wallpaper.
      */
+    @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public Drawable getFastDrawable() {
         Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM);
         if (bm != null) {
@@ -790,6 +800,7 @@ public class WallpaperManager {
      * @return Returns an optimized Drawable object that will draw the
      * wallpaper or a null pointer if these is none.
      */
+    @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public Drawable peekFastDrawable() {
        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false, FLAG_SYSTEM);
         if (bm != null) {
@@ -827,10 +838,14 @@ public class WallpaperManager {
      * @param which The wallpaper whose image file is to be retrieved.  Must be a single
      *     defined kind of wallpaper, either {@link #FLAG_SYSTEM} or
      *     {@link #FLAG_LOCK}.
+     * @return An open, readable file desriptor to the requested wallpaper image file;
+     *     or {@code null} if no such wallpaper is configured or if the calling app does
+     *     not have permission to read the current wallpaper.
      *
      * @see #FLAG_LOCK
      * @see #FLAG_SYSTEM
      */
+    @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
     public ParcelFileDescriptor getWallpaperFile(@SetWallpaperFlags int which) {
         return getWallpaperFile(which, mContext.getUserId());
     }
@@ -900,9 +915,18 @@ public class WallpaperManager {
         } else {
             try {
                 Bundle outParams = new Bundle();
-                return sGlobals.mService.getWallpaper(null, which, outParams, userId);
+                return sGlobals.mService.getWallpaper(mContext.getOpPackageName(), null, which,
+                        outParams, userId);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
+            } catch (SecurityException e) {
+                if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.O) {
+                    Log.w(TAG, "No permission to access wallpaper, suppressing"
+                            + " exception to avoid crashing legacy app.");
+                    return null;
+                } else {
+                    throw e;
+                }
             }
         }
     }
@@ -1042,6 +1066,7 @@ public class WallpaperManager {
      * @throws IOException If an error occurs reverting to the built-in
      * wallpaper.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void setResource(@RawRes int resid) throws IOException {
         setResource(resid, FLAG_SYSTEM | FLAG_LOCK);
     }
@@ -1060,6 +1085,7 @@ public class WallpaperManager {
      *
      * @throws IOException
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setResource(@RawRes int resid, @SetWallpaperFlags int which)
             throws IOException {
         if (sGlobals.mService == null) {
@@ -1115,6 +1141,7 @@ public class WallpaperManager {
      * @throws IOException If an error occurs when attempting to set the wallpaper
      *     to the provided image.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void setBitmap(Bitmap bitmap) throws IOException {
         setBitmap(bitmap, null, true);
     }
@@ -1147,6 +1174,7 @@ public class WallpaperManager {
      * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
      *     empty or invalid.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
         return setBitmap(fullImage, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
@@ -1172,6 +1200,7 @@ public class WallpaperManager {
      *
      * @throws IOException
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
             boolean allowBackup, @SetWallpaperFlags int which)
             throws IOException {
@@ -1243,6 +1272,7 @@ public class WallpaperManager {
      * @throws IOException If an error occurs when attempting to set the wallpaper
      *     based on the provided image data.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void setStream(InputStream bitmapData) throws IOException {
         setStream(bitmapData, null, true);
     }
@@ -1285,6 +1315,7 @@ public class WallpaperManager {
      * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
      *     empty or invalid.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
             throws IOException {
         return setStream(bitmapData, visibleCropHint, allowBackup, FLAG_SYSTEM | FLAG_LOCK);
@@ -1311,6 +1342,7 @@ public class WallpaperManager {
      *
      * @throws IOException
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setStream(InputStream bitmapData, Rect visibleCropHint,
             boolean allowBackup, @SetWallpaperFlags int which)
                     throws IOException {
@@ -1572,6 +1604,7 @@ public class WallpaperManager {
      *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
     public boolean setWallpaperComponent(ComponentName name, int userId) {
         if (sGlobals.mService == null) {
             Log.w(TAG, "WallpaperService not running");
@@ -1716,6 +1749,7 @@ public class WallpaperManager {
      * @throws IOException If an error occurs reverting to the built-in
      * wallpaper.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void clear() throws IOException {
         setStream(openDefaultWallpaper(mContext, FLAG_SYSTEM), null, false);
     }
@@ -1730,6 +1764,7 @@ public class WallpaperManager {
      *   {@link #FLAG_LOCK}
      * @throws IOException If an error occurs reverting to the built-in wallpaper.
      */
+    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public void clear(@SetWallpaperFlags int which) throws IOException {
         if ((which & FLAG_SYSTEM) != 0) {
             clear();
index dfcc166..917f0b9 100644 (file)
@@ -1527,9 +1527,26 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
         }
     }
 
+    private void enforceCallingOrSelfPermissionAndAppOp(String permission, final String callingPkg,
+            final int callingUid, String message) {
+        mContext.enforceCallingOrSelfPermission(permission, message);
+
+        final String opName = AppOpsManager.permissionToOp(permission);
+        if (opName != null) {
+            final int appOpMode = mAppOpsManager.noteOp(opName, callingUid, callingPkg);
+            if (appOpMode != AppOpsManager.MODE_ALLOWED) {
+                throw new SecurityException(
+                        message + ": " + callingPkg + " is not allowed to " + permission);
+            }
+        }
+    }
+
     @Override
-    public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which,
-            Bundle outParams, int wallpaperUserId) {
+    public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
+            final int which, Bundle outParams, int wallpaperUserId) {
+        enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
+                callingPkg, Binder.getCallingUid(), "read wallpaper");
+
         wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);