From a5dc9ce04a88cbf73f4350b0415a3f3f82ff625a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pomini?= Date: Wed, 17 May 2023 15:14:43 +0000 Subject: [PATCH] Strengthen Wallpaper clear logic The changes are (all under flag): - support calling clearWallpaperLocked(FLAG_LOCK | FLAG_SYSTEM), which can be done more efficiently than clear(FLAG_LOCK) then clear(FLAG_SYSTEM). - add a check INTERACT_ACROSS_USER_FULL instead of returning if clear is called for another userId than mCurrentUserId - use setWallpaperComponent and not bindWallpaperComponentLocked in clear, since setWallpaperComponent does other important things that we need when changing wallpapers. This is the most important change. Also amend the javadoc to clarify the clear behaviour. Flag: lock screen lwp Bug: 283091821 Test: atest WallpaperManagerTest Test: manual: disable security checks, then for all possible combinations of static/live wallpaper(s), run: "adb shell service call wallpaper 10 s16 "test" i32 X i32 0" for X in (1, 2, 3) (resp. system, lock, system | lock) Change-Id: I86a9f18a1d236633e4de3923861a5b55c7c4c996 --- core/java/android/app/WallpaperManager.java | 40 +++++++-- .../wallpaper/WallpaperManagerService.java | 85 +++++++++++++++++-- 2 files changed, 110 insertions(+), 15 deletions(-) diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 235e90dd96df5..39d146b9c8d09 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -2476,19 +2476,38 @@ public class WallpaperManager { } /** - * Reset all wallpaper to the factory default. + * Reset all wallpaper to the factory default. As opposed to {@link #clear()}, if the device + * is configured to have a live wallpaper by default, apply it. * *

This method requires the caller to hold the permission * {@link android.Manifest.permission#SET_WALLPAPER}. */ @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void clearWallpaper() { + if (isLockscreenLiveWallpaperEnabled()) { + clearWallpaper(FLAG_LOCK | FLAG_SYSTEM, mContext.getUserId()); + return; + } clearWallpaper(FLAG_LOCK, mContext.getUserId()); clearWallpaper(FLAG_SYSTEM, mContext.getUserId()); } /** - * Clear the wallpaper for a specific user. The caller must hold the + * Clear the wallpaper for a specific user. + *

+ *

+ * + * The caller must hold the * INTERACT_ACROSS_USERS_FULL permission to clear another user's * wallpaper, and must hold the SET_WALLPAPER permission in all * circumstances. @@ -2793,8 +2812,9 @@ public class WallpaperManager { /** * Remove any currently set system wallpaper, reverting to the system's built-in - * wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} - * is broadcast. + * wallpaper. As opposed to {@link #clearWallpaper()}, this method always set a static wallpaper + * with the default image, even if the device is configured to have a live wallpaper by default. + * On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast. * *

This method requires the caller to hold the permission * {@link android.Manifest.permission#SET_WALLPAPER}. @@ -2809,9 +2829,14 @@ public class WallpaperManager { /** * Remove one or more currently set wallpapers, reverting to the system default - * display for each one. If {@link #FLAG_SYSTEM} is set in the {@code which} - * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast - * upon success. + * display for each one. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} + * is broadcast. + *

* * @param which A bitwise combination of {@link #FLAG_SYSTEM} or * {@link #FLAG_LOCK} @@ -2821,6 +2846,7 @@ public class WallpaperManager { public void clear(@SetWallpaperFlags int which) throws IOException { if ((which & FLAG_SYSTEM) != 0) { clear(); + if (isLockscreenLiveWallpaperEnabled()) return; } if ((which & FLAG_LOCK) != 0) { clearWallpaper(FLAG_LOCK, mContext.getUserId()); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index c329d6bf25782..1769f060807af 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1991,7 +1991,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperData data = null; synchronized (mLock) { - clearWallpaperLocked(false, which, userId, null); + if (mIsLockscreenLiveWallpaperEnabled) { + clearWallpaperLocked(callingPackage, false, which, userId); + } else { + clearWallpaperLocked(false, which, userId, null); + } if (which == FLAG_LOCK) { data = mLockWallpaperMap.get(userId); @@ -2008,7 +2012,64 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) { + private void clearWallpaperLocked(String callingPackage, boolean defaultFailed, + int which, int userId) { + + // Might need to bring it in the first time to establish our rewrite + if (!mWallpaperMap.contains(userId)) { + loadSettingsLocked(userId, false, FLAG_LOCK | FLAG_SYSTEM); + } + final WallpaperData wallpaper = mWallpaperMap.get(userId); + final WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); + if (which == FLAG_LOCK && lockWallpaper == null) { + // It's already gone; we're done. + if (DEBUG) { + Slog.i(TAG, "Lock wallpaper already cleared"); + } + return; + } + + RuntimeException e = null; + try { + if (userId != mCurrentUserId && !hasCrossUserPermission()) return; + + final ComponentName component; + final int finalWhich; + + if ((which & FLAG_LOCK) > 0 && lockWallpaper != null) { + clearWallpaperBitmaps(lockWallpaper); + } + if ((which & FLAG_SYSTEM) > 0) { + clearWallpaperBitmaps(wallpaper); + } + + // lock only case: set the system wallpaper component to both screens + if (which == FLAG_LOCK) { + component = wallpaper.wallpaperComponent; + finalWhich = FLAG_LOCK | FLAG_SYSTEM; + } else { + component = defaultFailed ? mImageWallpaper : null; + finalWhich = which; + } + + boolean success = withCleanCallingIdentity(() -> setWallpaperComponent( + component, callingPackage, finalWhich, userId)); + if (success) return; + } catch (IllegalArgumentException e1) { + e = e1; + } + + // This can happen if the default wallpaper component doesn't + // exist. This should be a system configuration problem, but + // let's not let it crash the system and just live with no + // wallpaper. + Slog.e(TAG, "Default wallpaper component not found!", e); + withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper)); + } + + // TODO(b/266818039) remove this version of the method + private void clearWallpaperLocked(boolean defaultFailed, int which, int userId, + IRemoteCallback reply) { if (which != FLAG_SYSTEM && which != FLAG_LOCK) { throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear"); } @@ -3099,8 +3160,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Migrate the bitmap files outright; no need to copy try { - Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath()); - Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath()); + if (!mIsLockscreenLiveWallpaperEnabled || sysWP.wallpaperFile.exists()) { + Os.rename(sysWP.wallpaperFile.getAbsolutePath(), + lockWP.wallpaperFile.getAbsolutePath()); + } + if (!mIsLockscreenLiveWallpaperEnabled || sysWP.cropFile.exists()) { + Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath()); + } mLockWallpaperMap.put(userId, lockWP); if (mIsLockscreenLiveWallpaperEnabled) { SELinux.restorecon(lockWP.wallpaperFile); @@ -3163,16 +3229,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } @VisibleForTesting - void setWallpaperComponent(ComponentName name, String callingPackage, + boolean setWallpaperComponent(ComponentName name, String callingPackage, @SetWallpaperFlags int which, int userId) { if (mIsLockscreenLiveWallpaperEnabled) { - setWallpaperComponentInternal(name, callingPackage, which, userId); + return setWallpaperComponentInternal(name, callingPackage, which, userId); } else { setWallpaperComponentInternalLegacy(name, callingPackage, which, userId); + return true; } } - private void setWallpaperComponentInternal(ComponentName name, String callingPackage, + private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage, @SetWallpaperFlags int which, int userIdIn) { if (DEBUG) { Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name); @@ -3183,6 +3250,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); boolean shouldNotifyColors = false; + boolean bindSuccess; final WallpaperData newWallpaper; synchronized (mLock) { @@ -3231,7 +3299,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub */ boolean forceRebind = same && systemIsBoth && which == FLAG_SYSTEM; - boolean bindSuccess = bindWallpaperComponentLocked(name, /* force */ + bindSuccess = bindWallpaperComponentLocked(name, /* force */ forceRebind, /* fromUser */ true, newWallpaper, callback); if (bindSuccess) { if (!same) { @@ -3281,6 +3349,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub notifyWallpaperColorsChanged(newWallpaper, which); notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); } + return bindSuccess; } // TODO(b/266818039) Remove this method