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 1/2] 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 From f8af5a2f54c612c44aa33a17821b495a251bfedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pomini?= Date: Thu, 8 Jun 2023 12:58:20 +0000 Subject: [PATCH 2/2] Clear lock bitmaps when wallpaper applied to home+lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's never keep old bitmap in files. Otherwise if a user has a live wallpaper on lock screen only, and backups & restore to an older device, the old bitmap will reappear. Also otherwise, getWallpaperFile() may return an old bitmap even if the user has a lockscreen live wallpaper. Only effective with the lockscreen lwp flag Flag: lockscreen live wallpaper Bug: 283091821 Test: atest WallpaperManagerTest Change-Id: I8cd9af52e1a5f3a0388b3af22ab6c8c441520a8e --- .../android/server/wallpaper/WallpaperManagerService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 1769f060807af..26cac79f16384 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -366,6 +366,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (lockedWallpaper != null) { detachWallpaperLocked(lockedWallpaper); } + clearWallpaperBitmaps(mWallpaper.userId, FLAG_LOCK); mLockWallpaperMap.remove(wallpaper.userId); notifyColorsWhich |= FLAG_LOCK; } @@ -3318,8 +3319,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub }); } } + boolean lockBitmapCleared = false; if (!mImageWallpaper.equals(newWallpaper.wallpaperComponent)) { clearWallpaperBitmaps(newWallpaper); + lockBitmapCleared = newWallpaper.mWhich == FLAG_LOCK; } newWallpaper.wallpaperId = makeWallpaperIdLocked(); notifyCallbacksLocked(newWallpaper); @@ -3337,6 +3340,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub updateEngineFlags(newWallpaper); } } + if (!lockBitmapCleared) { + clearWallpaperBitmaps(newWallpaper.userId, FLAG_LOCK); + } mLockWallpaperMap.remove(newWallpaper.userId); } }