1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wallpaper; 18 19 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; 20 import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE; 21 import static android.Manifest.permission.READ_WALLPAPER_INTERNAL; 22 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 23 import static android.app.Flags.fixWallpaperChanged; 24 import static android.app.Flags.liveWallpaperContentHandling; 25 import static android.app.Flags.notifyKeyguardEvents; 26 import static android.app.Flags.removeNextWallpaperComponent; 27 import static android.app.WallpaperManager.COMMAND_REAPPLY; 28 import static android.app.WallpaperManager.FLAG_LOCK; 29 import static android.app.WallpaperManager.FLAG_SYSTEM; 30 import static android.app.WallpaperManager.ORIENTATION_UNKNOWN; 31 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; 32 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 33 import static android.os.ParcelFileDescriptor.MODE_CREATE; 34 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; 35 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; 36 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; 37 import static android.os.Process.THREAD_PRIORITY_FOREGROUND; 38 import static android.view.Display.DEFAULT_DISPLAY; 39 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 40 41 import static com.android.server.wallpaper.WallpaperDisplayHelper.DisplayData; 42 import static com.android.server.wallpaper.WallpaperUtils.RECORD_FILE; 43 import static com.android.server.wallpaper.WallpaperUtils.RECORD_LOCK_FILE; 44 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER; 45 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_INFO; 46 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG; 47 import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir; 48 import static com.android.server.wallpaper.WallpaperUtils.makeWallpaperIdLocked; 49 import static com.android.server.wm.DesktopModeHelper.isDeviceEligibleForDesktopExperienceWallpaper; 50 import static com.android.window.flags.Flags.avoidRebindingIntentionallyDisconnectedWallpaper; 51 import static com.android.window.flags.Flags.multiCrop; 52 import static com.android.window.flags.Flags.offloadColorExtraction; 53 54 import android.annotation.NonNull; 55 import android.annotation.Nullable; 56 import android.app.ActivityManager; 57 import android.app.ActivityOptions; 58 import android.app.AppGlobals; 59 import android.app.AppOpsManager; 60 import android.app.ApplicationExitInfo; 61 import android.app.ILocalWallpaperColorConsumer; 62 import android.app.IWallpaperManager; 63 import android.app.IWallpaperManagerCallback; 64 import android.app.KeyguardManager; 65 import android.app.PendingIntent; 66 import android.app.UidObserver; 67 import android.app.UserSwitchObserver; 68 import android.app.WallpaperColors; 69 import android.app.WallpaperInfo; 70 import android.app.WallpaperManager; 71 import android.app.WallpaperManager.SetWallpaperFlags; 72 import android.app.admin.DevicePolicyManagerInternal; 73 import android.app.wallpaper.WallpaperDescription; 74 import android.app.wallpaper.WallpaperInstance; 75 import android.content.BroadcastReceiver; 76 import android.content.ComponentName; 77 import android.content.Context; 78 import android.content.Intent; 79 import android.content.IntentFilter; 80 import android.content.ServiceConnection; 81 import android.content.pm.IPackageManager; 82 import android.content.pm.PackageManager; 83 import android.content.pm.PackageManager.NameNotFoundException; 84 import android.content.pm.PackageManagerInternal; 85 import android.content.pm.ResolveInfo; 86 import android.content.pm.ServiceInfo; 87 import android.content.pm.UserInfo; 88 import android.graphics.Bitmap; 89 import android.graphics.BitmapFactory; 90 import android.graphics.Point; 91 import android.graphics.Rect; 92 import android.graphics.RectF; 93 import android.hardware.display.DisplayManager; 94 import android.hardware.display.DisplayManager.DisplayListener; 95 import android.multiuser.Flags; 96 import android.os.Binder; 97 import android.os.Bundle; 98 import android.os.FileObserver; 99 import android.os.FileUtils; 100 import android.os.Handler; 101 import android.os.IBinder; 102 import android.os.IInterface; 103 import android.os.IRemoteCallback; 104 import android.os.ParcelFileDescriptor; 105 import android.os.Process; 106 import android.os.RemoteCallbackList; 107 import android.os.RemoteException; 108 import android.os.ResultReceiver; 109 import android.os.SELinux; 110 import android.os.ShellCallback; 111 import android.os.SystemClock; 112 import android.os.UserHandle; 113 import android.os.UserManager; 114 import android.os.storage.StorageManager; 115 import android.service.wallpaper.IWallpaperConnection; 116 import android.service.wallpaper.IWallpaperEngine; 117 import android.service.wallpaper.IWallpaperService; 118 import android.service.wallpaper.WallpaperService; 119 import android.system.ErrnoException; 120 import android.system.Os; 121 import android.text.TextUtils; 122 import android.util.EventLog; 123 import android.util.IntArray; 124 import android.util.Slog; 125 import android.util.SparseArray; 126 import android.util.SparseBooleanArray; 127 import android.view.Display; 128 import android.view.View; 129 import android.view.WindowManager; 130 131 import com.android.internal.R; 132 import com.android.internal.annotations.VisibleForTesting; 133 import com.android.internal.content.PackageMonitor; 134 import com.android.internal.os.BackgroundThread; 135 import com.android.internal.util.DumpUtils; 136 import com.android.server.EventLogTags; 137 import com.android.server.FgThread; 138 import com.android.server.LocalServices; 139 import com.android.server.ServiceThread; 140 import com.android.server.SystemService; 141 import com.android.server.pm.UserManagerInternal; 142 import com.android.server.utils.TimingsTraceAndSlog; 143 import com.android.server.wallpaper.WallpaperData.BindSource; 144 import com.android.server.wm.ActivityTaskManagerInternal; 145 import com.android.server.wm.WindowManagerInternal; 146 import com.android.tools.r8.keepanno.annotations.KeepItemKind; 147 import com.android.tools.r8.keepanno.annotations.KeepTarget; 148 import com.android.tools.r8.keepanno.annotations.UsesReflection; 149 150 import org.xmlpull.v1.XmlPullParserException; 151 152 import java.io.File; 153 import java.io.FileDescriptor; 154 import java.io.FileNotFoundException; 155 import java.io.IOException; 156 import java.io.InputStream; 157 import java.io.PrintWriter; 158 import java.util.ArrayList; 159 import java.util.Arrays; 160 import java.util.List; 161 import java.util.Locale; 162 import java.util.Map; 163 import java.util.Objects; 164 import java.util.function.Consumer; 165 import java.util.function.Predicate; 166 167 public class WallpaperManagerService extends IWallpaperManager.Stub 168 implements IWallpaperManagerService { 169 private static final String TAG = "WallpaperManagerService"; 170 private static final boolean DEBUG = false; 171 private static final boolean DEBUG_LIVE = true; 172 173 private static final @NonNull RectF LOCAL_COLOR_BOUNDS = 174 new RectF(0, 0, 1, 1); 175 176 public static class Lifecycle extends SystemService { 177 private IWallpaperManagerService mService; 178 Lifecycle(Context context)179 public Lifecycle(Context context) { 180 super(context); 181 } 182 183 @Override 184 @UsesReflection( 185 value = { 186 @KeepTarget( 187 kind = KeepItemKind.CLASS_AND_MEMBERS, 188 instanceOfClassConstantExclusive = IWallpaperManagerService.class, 189 methodName = "<init>") 190 }) onStart()191 public void onStart() { 192 try { 193 final Class<? extends IWallpaperManagerService> klass = 194 (Class<? extends IWallpaperManagerService>)Class.forName( 195 getContext().getResources().getString( 196 R.string.config_wallpaperManagerServiceName)); 197 mService = klass.getConstructor(Context.class).newInstance(getContext()); 198 publishBinderService(Context.WALLPAPER_SERVICE, mService); 199 } catch (Exception exp) { 200 Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp); 201 } 202 } 203 204 @Override onBootPhase(int phase)205 public void onBootPhase(int phase) { 206 if (mService != null) { 207 mService.onBootPhase(phase); 208 } 209 } 210 211 @Override onUserUnlocking(@onNull TargetUser user)212 public void onUserUnlocking(@NonNull TargetUser user) { 213 if (mService != null) { 214 mService.onUnlockUser(user.getUserIdentifier()); 215 } 216 } 217 } 218 219 private final Object mLock = new Object(); 220 /** Tracks wallpaper being migrated from system+lock to lock when setting static wp. */ 221 WallpaperDestinationChangeHandler mPendingMigrationViaStatic; 222 223 private static final double LMK_LOW_THRESHOLD_MEMORY_PERCENTAGE = 10; 224 private static final int LMK_RECONNECT_REBIND_RETRIES = 3; 225 private static final long LMK_RECONNECT_DELAY_MS = 5000; 226 227 /** 228 * Minimum time between crashes of a wallpaper service for us to consider 229 * restarting it vs. just reverting to the static wallpaper. 230 */ 231 private static final long MIN_WALLPAPER_CRASH_TIME = 10000; 232 private static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128; 233 234 /** 235 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks 236 * that the wallpaper has changed. The CREATE is triggered when there is no 237 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered 238 * every time the wallpaper is changed. 239 */ 240 class WallpaperObserver extends FileObserver { 241 242 final int mUserId; 243 final WallpaperData mWallpaper; 244 final File mWallpaperDir; 245 final File mWallpaperFile; 246 final File mWallpaperLockFile; 247 WallpaperObserver(WallpaperData wallpaper)248 public WallpaperObserver(WallpaperData wallpaper) { 249 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(), 250 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF); 251 mUserId = wallpaper.userId; 252 mWallpaperDir = getWallpaperDir(wallpaper.userId); 253 mWallpaper = wallpaper; 254 mWallpaperFile = new File(mWallpaperDir, WALLPAPER); 255 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG); 256 } 257 dataForEvent(boolean lockChanged)258 WallpaperData dataForEvent(boolean lockChanged) { 259 WallpaperData wallpaper = null; 260 synchronized (mLock) { 261 if (lockChanged) { 262 wallpaper = mLockWallpaperMap.get(mUserId); 263 } 264 if (wallpaper == null) { 265 // no lock-specific wallpaper exists, or sys case, handled together 266 wallpaper = mWallpaperMap.get(mUserId); 267 } 268 } 269 return (wallpaper != null) ? wallpaper : mWallpaper; 270 } 271 272 // Handles static wallpaper changes generated by WallpaperObserver events when 273 // enableSeparateLockScreenEngine() is true. updateWallpapers(int event, String path)274 private void updateWallpapers(int event, String path) { 275 // System and system+lock changes happen on the system wallpaper input file; 276 // lock-only changes happen on the dedicated lock wallpaper input file 277 final File changedFile = new File(mWallpaperDir, path); 278 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile)); 279 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile)); 280 final WallpaperData wallpaper = dataForEvent(lockWallpaperChanged); 281 282 final boolean moved = (event == MOVED_TO); 283 final boolean written = (event == CLOSE_WRITE || moved); 284 final boolean isMigration = moved && lockWallpaperChanged; 285 final boolean isRestore = moved && !isMigration; 286 final boolean isAppliedToLock = (wallpaper.mWhich & FLAG_LOCK) != 0; 287 final boolean needsUpdate = wallpaper.getComponent() == null 288 || event != CLOSE_WRITE // includes the MOVED_TO case 289 || wallpaper.imageWallpaperPending; 290 291 if (isMigration) { 292 // When separate lock screen engine is supported, migration will be handled by 293 // WallpaperDestinationChangeHandler. 294 return; 295 } 296 if (!(sysWallpaperChanged || lockWallpaperChanged)) { 297 return; 298 } 299 300 if (DEBUG) { 301 Slog.v(TAG, "Wallpaper file change: evt=" + event 302 + " path=" + path 303 + " sys=" + sysWallpaperChanged 304 + " lock=" + lockWallpaperChanged 305 + " imagePending=" + wallpaper.imageWallpaperPending 306 + " mWhich=0x" + Integer.toHexString(wallpaper.mWhich) 307 + " written=" + written 308 + " isMigration=" + isMigration 309 + " isRestore=" + isRestore 310 + " isAppliedToLock=" + isAppliedToLock 311 + " needsUpdate=" + needsUpdate); 312 } 313 314 synchronized (mLock) { 315 notifyCallbacksLocked(wallpaper); 316 317 if (!written || !needsUpdate) { 318 return; 319 } 320 321 if (DEBUG) { 322 Slog.v(TAG, "Setting new static wallpaper: which=" + wallpaper.mWhich); 323 } 324 325 WallpaperDestinationChangeHandler localSync = mPendingMigrationViaStatic; 326 mPendingMigrationViaStatic = null; 327 // The image source has finished writing the source image, 328 // so we now produce the crop rect (in the background), and 329 // only publish the new displayable (sub)image as a result 330 // of that work. 331 SELinux.restorecon(changedFile); 332 if (isRestore) { 333 // This is a restore, so generate the crop using any just-restored new 334 // crop guidelines, making sure to preserve our local dimension hints. 335 // We also make sure to reapply the correct SELinux label. 336 if (DEBUG) { 337 Slog.v(TAG, "Wallpaper restore; reloading metadata"); 338 } 339 loadSettingsLocked(wallpaper.userId, true, FLAG_SYSTEM | FLAG_LOCK); 340 } 341 if (DEBUG) { 342 Slog.v(TAG, "Wallpaper written; generating crop"); 343 } 344 mWallpaperCropper.generateCrop(wallpaper); 345 if (DEBUG) { 346 Slog.v(TAG, "Crop done; invoking completion callback"); 347 } 348 wallpaper.imageWallpaperPending = false; 349 350 if (sysWallpaperChanged) { 351 if (DEBUG) { 352 Slog.v(TAG, "Home screen wallpaper changed"); 353 } 354 IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { 355 @Override 356 public void sendResult(Bundle data) throws RemoteException { 357 if (DEBUG) { 358 Slog.d(TAG, "publish system wallpaper changed!"); 359 } 360 notifyWallpaperComplete(wallpaper); 361 if (fixWallpaperChanged()) { 362 notifyWallpaperChanged(wallpaper); 363 } 364 } 365 }; 366 367 // If this was the system wallpaper, rebind... 368 wallpaper.mBindSource = BindSource.SET_STATIC; 369 bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper, callback); 370 } 371 372 if (lockWallpaperChanged) { 373 // This is lock-only, so (re)bind to the static engine. 374 if (DEBUG) { 375 Slog.v(TAG, "Lock screen wallpaper changed"); 376 } 377 IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { 378 @Override 379 public void sendResult(Bundle data) throws RemoteException { 380 if (DEBUG) { 381 Slog.d(TAG, "publish lock wallpaper changed!"); 382 } 383 notifyWallpaperComplete(wallpaper); 384 if (fixWallpaperChanged()) { 385 notifyWallpaperChanged(wallpaper); 386 } 387 } 388 }; 389 390 wallpaper.mBindSource = BindSource.SET_STATIC; 391 bindWallpaperComponentLocked(mImageWallpaper, true /* force */, 392 false /* fromUser */, wallpaper, callback); 393 } else if (isAppliedToLock) { 394 // This is system-plus-lock: we need to wipe the lock bookkeeping since 395 // we're falling back to displaying the system wallpaper there. 396 if (DEBUG) { 397 Slog.v(TAG, "Lock screen wallpaper changed to same as home"); 398 } 399 detachWallpaperLocked(mLockWallpaperMap.get(mWallpaper.userId)); 400 clearWallpaperBitmaps(mWallpaper.userId, FLAG_LOCK); 401 mLockWallpaperMap.remove(wallpaper.userId); 402 } 403 404 saveSettingsLocked(wallpaper.userId); 405 if (localSync != null) { 406 localSync.complete(); 407 } 408 } 409 410 // Outside of the lock since it will synchronize itself 411 if (!offloadColorExtraction()) notifyWallpaperColorsChanged(wallpaper); 412 } 413 414 @Override onEvent(int event, String path)415 public void onEvent(int event, String path) { 416 if (path != null) updateWallpapers(event, path); 417 } 418 } 419 420 /* 421 * Calls wallpaper setComplete methods. Called for static wallpapers after the wallpaper is set 422 * and changes are persisted. 423 */ notifyWallpaperComplete(WallpaperData wallpaper)424 private void notifyWallpaperComplete(WallpaperData wallpaper) { 425 if (wallpaper.setComplete != null) { 426 try { 427 wallpaper.setComplete.onWallpaperChanged(); 428 } catch (RemoteException e) { 429 // if this fails we don't really care; the setting app may just 430 // have crashed and that sort of thing is a fact of life. 431 Slog.w(TAG, "onWallpaperChanged threw an exception", e); 432 } 433 } 434 } 435 notifyWallpaperColorsChanged(@onNull WallpaperData wallpaper)436 void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper) { 437 notifyWallpaperColorsChanged(wallpaper, wallpaper.mWhich); 438 } 439 notifyWallpaperColorsChanged(@onNull WallpaperData wallpaper, int which)440 private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) { 441 if (DEBUG) { 442 Slog.i(TAG, "Notifying wallpaper colors changed"); 443 } 444 if (wallpaper.connection != null) { 445 wallpaper.connection.forEachDisplayConnector(connector -> 446 notifyWallpaperColorsChangedOnDisplay(wallpaper, connector.mDisplayId, which)); 447 } 448 } 449 getWallpaperCallbacks(int userId, int displayId)450 private RemoteCallbackList<IWallpaperManagerCallback> getWallpaperCallbacks(int userId, 451 int displayId) { 452 RemoteCallbackList<IWallpaperManagerCallback> listeners = null; 453 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> displayListeners = 454 mColorsChangedListeners.get(userId); 455 if (displayListeners != null) { 456 listeners = displayListeners.get(displayId); 457 } 458 return listeners; 459 } 460 notifyWallpaperColorsChangedOnDisplay(@onNull WallpaperData wallpaper, int displayId)461 private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, 462 int displayId) { 463 notifyWallpaperColorsChangedOnDisplay(wallpaper, displayId, wallpaper.mWhich); 464 } 465 notifyWallpaperColorsChangedOnDisplay(@onNull WallpaperData wallpaper, int displayId, int which)466 private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, 467 int displayId, int which) { 468 boolean needsExtraction; 469 synchronized (mLock) { 470 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners = 471 getWallpaperCallbacks(wallpaper.userId, displayId); 472 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners = 473 getWallpaperCallbacks(UserHandle.USER_ALL, displayId); 474 // No-op until someone is listening to it. 475 if (emptyCallbackList(currentUserColorListeners) && 476 emptyCallbackList(userAllColorListeners)) { 477 return; 478 } 479 480 if (DEBUG) { 481 Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + wallpaper.mWhich); 482 } 483 484 needsExtraction = wallpaper.primaryColors == null || wallpaper.mIsColorExtractedFromDim; 485 } 486 487 boolean notify = true; 488 if (needsExtraction) { 489 notify = extractColors(wallpaper); 490 } 491 if (notify) { 492 notifyColorListeners(getAdjustedWallpaperColorsOnDimming(wallpaper), which, 493 wallpaper.userId, displayId); 494 } 495 } 496 emptyCallbackList(RemoteCallbackList<T> list)497 private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) { 498 return (list == null || list.getRegisteredCallbackCount() == 0); 499 } 500 notifyColorListeners(@onNull WallpaperColors wallpaperColors, int which, int userId, int displayId)501 private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which, 502 int userId, int displayId) { 503 final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>(); 504 synchronized (mLock) { 505 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners = 506 getWallpaperCallbacks(userId, displayId); 507 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners = 508 getWallpaperCallbacks(UserHandle.USER_ALL, displayId); 509 510 if (currentUserColorListeners != null) { 511 final int count = currentUserColorListeners.beginBroadcast(); 512 for (int i = 0; i < count; i++) { 513 colorListeners.add(currentUserColorListeners.getBroadcastItem(i)); 514 } 515 currentUserColorListeners.finishBroadcast(); 516 } 517 518 if (userAllColorListeners != null) { 519 final int count = userAllColorListeners.beginBroadcast(); 520 for (int i = 0; i < count; i++) { 521 colorListeners.add(userAllColorListeners.getBroadcastItem(i)); 522 } 523 userAllColorListeners.finishBroadcast(); 524 } 525 } 526 527 final int count = colorListeners.size(); 528 for (int i = 0; i < count; i++) { 529 try { 530 colorListeners.get(i).onWallpaperColorsChanged(wallpaperColors, which, userId); 531 } catch (RemoteException e) { 532 // Callback is gone, it's not necessary to unregister it since 533 // RemoteCallbackList#getBroadcastItem will take care of it. 534 Slog.w(TAG, "onWallpaperColorsChanged() threw an exception", e); 535 } 536 } 537 } 538 539 /** 540 * We can easily extract colors from an ImageWallpaper since it's only a bitmap. 541 * In this case, using the crop is more than enough. Live wallpapers are just ignored. 542 * 543 * @param wallpaper a wallpaper representation 544 * @return true unless the wallpaper changed during the color computation 545 */ extractColors(WallpaperData wallpaper)546 private boolean extractColors(WallpaperData wallpaper) { 547 if (offloadColorExtraction()) return true; 548 String cropFile = null; 549 boolean defaultImageWallpaper = false; 550 int wallpaperId; 551 float dimAmount; 552 553 synchronized (mLock) { 554 wallpaper.mIsColorExtractedFromDim = false; 555 } 556 557 if (wallpaper.equals(mFallbackWallpaper)) { 558 synchronized (mLock) { 559 if (mFallbackWallpaper.primaryColors != null) return true; 560 } 561 final WallpaperColors colors = extractDefaultImageWallpaperColors(wallpaper); 562 synchronized (mLock) { 563 mFallbackWallpaper.primaryColors = colors; 564 } 565 return true; 566 } 567 568 synchronized (mLock) { 569 // Not having a wallpaperComponent means it's a lock screen wallpaper. 570 final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.getComponent()) 571 || wallpaper.getComponent() == null; 572 if (imageWallpaper && wallpaper.getCropFile().exists()) { 573 cropFile = wallpaper.getCropFile().getAbsolutePath(); 574 } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) { 575 defaultImageWallpaper = true; 576 } 577 wallpaperId = wallpaper.wallpaperId; 578 dimAmount = wallpaper.mWallpaperDimAmount; 579 } 580 581 WallpaperColors colors = null; 582 if (cropFile != null) { 583 Bitmap bitmap = BitmapFactory.decodeFile(cropFile); 584 if (bitmap != null) { 585 colors = WallpaperColors.fromBitmap(bitmap, dimAmount); 586 bitmap.recycle(); 587 } 588 } else if (defaultImageWallpaper) { 589 // There is no crop and source file because this is default image wallpaper. 590 colors = extractDefaultImageWallpaperColors(wallpaper); 591 } 592 593 if (colors == null) { 594 Slog.w(TAG, "Cannot extract colors because wallpaper could not be read."); 595 return true; 596 } 597 598 synchronized (mLock) { 599 if (wallpaper.wallpaperId == wallpaperId) { 600 wallpaper.primaryColors = colors; 601 // Now that we have the colors, let's save them into the xml 602 // to avoid having to run this again. 603 saveSettingsLocked(wallpaper.userId); 604 return true; 605 } else { 606 Slog.w(TAG, "Not setting primary colors since wallpaper changed"); 607 return false; 608 } 609 } 610 } 611 extractDefaultImageWallpaperColors(WallpaperData wallpaper)612 private WallpaperColors extractDefaultImageWallpaperColors(WallpaperData wallpaper) { 613 if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors"); 614 float dimAmount; 615 616 synchronized (mLock) { 617 if (mCacheDefaultImageWallpaperColors != null) return mCacheDefaultImageWallpaperColors; 618 dimAmount = wallpaper.mWallpaperDimAmount; 619 } 620 621 WallpaperColors colors = null; 622 try (InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) { 623 if (is == null) { 624 Slog.w(TAG, "Can't open default wallpaper stream"); 625 return null; 626 } 627 628 final BitmapFactory.Options options = new BitmapFactory.Options(); 629 final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); 630 if (bitmap != null) { 631 colors = WallpaperColors.fromBitmap(bitmap, dimAmount); 632 bitmap.recycle(); 633 } 634 } catch (OutOfMemoryError e) { 635 Slog.w(TAG, "Can't decode default wallpaper stream", e); 636 } catch (IOException e) { 637 Slog.w(TAG, "Can't close default wallpaper stream", e); 638 } 639 640 if (colors == null) { 641 Slog.e(TAG, "Extract default image wallpaper colors failed"); 642 } else { 643 synchronized (mLock) { 644 mCacheDefaultImageWallpaperColors = colors; 645 } 646 } 647 648 return colors; 649 } 650 651 private final Context mContext; 652 private boolean mInitialUserSwitch = true; 653 private ServiceThread mHandlerThread; 654 private final WindowManagerInternal mWindowManagerInternal; 655 private final PackageManagerInternal mPackageManagerInternal; 656 private final IPackageManager mIPackageManager; 657 private final ActivityManager mActivityManager; 658 private final MyPackageMonitor mMonitor; 659 private final AppOpsManager mAppOpsManager; 660 661 private final DisplayListener mDisplayListener = new DisplayListener() { 662 663 @Override 664 public void onDisplayAdded(int displayId) { 665 } 666 667 @Override 668 public void onDisplayRemoved(int displayId) { 669 onDisplayRemovedInternal(displayId); 670 } 671 672 @Override 673 public void onDisplayChanged(int displayId) { 674 } 675 }; 676 677 /** 678 * Map of color listeners per user id. 679 * The first key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners. 680 * The secondary key will be the display id, which means which display the listener is 681 * interested in. 682 */ 683 private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>> 684 mColorsChangedListeners; 685 // The currently bound home or home+lock wallpaper 686 protected WallpaperData mLastWallpaper; 687 // The currently bound lock screen only wallpaper, or null if none 688 protected WallpaperData mLastLockWallpaper; 689 690 /** 691 * Flag set to true after reboot if the home wallpaper is waiting for the device to be unlocked. 692 * This happens for wallpapers that are not direct-boot aware; they can only be rendered after 693 * the user unlocks the device for the first time after a reboot. In the meantime, the default 694 * wallpaper is shown instead. 695 */ 696 private boolean mHomeWallpaperWaitingForUnlock; 697 698 /** 699 * Flag set to true after reboot if the lock wallpaper is waiting for the device to be unlocked. 700 */ 701 private boolean mLockWallpaperWaitingForUnlock; 702 703 private boolean mShuttingDown; 704 705 /** 706 * Name of the component used to display bitmap wallpapers from either the gallery or 707 * built-in wallpapers. 708 */ 709 private final ComponentName mImageWallpaper; 710 711 /** 712 * Name of the component that is used when the user-selected wallpaper is incompatible with the 713 * display's resolution or aspect ratio. 714 */ 715 @Nullable private final ComponentName mFallbackWallpaperComponent; 716 717 /** 718 * Default image wallpaper shall never changed after system service started, caching it when we 719 * first read the image file. 720 */ 721 private WallpaperColors mCacheDefaultImageWallpaperColors; 722 723 /** 724 * Name of the default wallpaper component; might be different from mImageWallpaper 725 */ 726 private final ComponentName mDefaultWallpaperComponent; 727 728 private final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>(); 729 private final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>(); 730 731 protected WallpaperData mFallbackWallpaper; 732 733 private final SparseBooleanArray mUserRestorecon = new SparseBooleanArray(); 734 private int mCurrentUserId = UserHandle.USER_NULL; 735 private boolean mInAmbientMode; 736 private LocalColorRepository mLocalColorRepo = new LocalColorRepository(); 737 738 @VisibleForTesting 739 final WallpaperDataParser mWallpaperDataParser; 740 741 @VisibleForTesting 742 final WallpaperDisplayHelper mWallpaperDisplayHelper; 743 final WallpaperCropper mWallpaperCropper; 744 745 @VisibleForTesting isWallpaperCompatibleForDisplay(int displayId, WallpaperConnection connection)746 boolean isWallpaperCompatibleForDisplay(int displayId, WallpaperConnection connection) { 747 if (connection == null) { 748 return false; 749 } 750 // Non image wallpaper. 751 if (connection.mInfo != null) { 752 return connection.mInfo.supportsMultipleDisplays(); 753 } 754 755 // Image wallpaper 756 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { 757 return mWallpaperCropper.isWallpaperCompatibleForDisplay(displayId, 758 connection.mWallpaper); 759 } 760 // When enableConnectedDisplaysWallpaper is off, we assume the image wallpaper supports all 761 // usable displays. 762 return true; 763 } 764 updateFallbackConnection(int clientUid)765 private void updateFallbackConnection(int clientUid) { 766 if (mLastWallpaper == null || mFallbackWallpaper == null) return; 767 final WallpaperConnection systemConnection = mLastWallpaper.connection; 768 final WallpaperConnection fallbackConnection = mFallbackWallpaper.connection; 769 final WallpaperConnection lockConnection; 770 if (mLastLockWallpaper != null) { 771 lockConnection = mLastLockWallpaper.connection; 772 } else { 773 lockConnection = null; 774 } 775 if (fallbackConnection == null) { 776 Slog.w(TAG, "Fallback wallpaper connection has not been created yet!!"); 777 return; 778 } 779 780 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { 781 Display[] displays = mWallpaperDisplayHelper.getDisplays(); 782 for (int i = displays.length - 1; i >= 0; i--) { 783 int displayId = displays[i].getDisplayId(); 784 if (!mWallpaperDisplayHelper.isUsableDisplay(displayId, clientUid)) { 785 continue; 786 } 787 // If the display is already connected to the desired wallpaper(s), either the 788 // same wallpaper for both lock and system, or different wallpapers for each, 789 // any existing fallback wallpaper connection will be removed. 790 if (systemConnection.containsDisplay(displayId) 791 && (lockConnection == null || lockConnection.containsDisplay(displayId))) { 792 DisplayConnector fallbackConnector = 793 mFallbackWallpaper.connection.mDisplayConnector.get(displayId); 794 if (fallbackConnector != null) { 795 if (fallbackConnector.mEngine != null) { 796 fallbackConnector.disconnectLocked(mFallbackWallpaper.connection); 797 } 798 mFallbackWallpaper.connection.mDisplayConnector.remove(displayId); 799 } 800 continue; 801 } 802 803 // Identify if the fallback wallpaper should be use for lock or system or both. 804 int which = 0; 805 if (!systemConnection.containsDisplay(displayId)) { 806 which |= FLAG_SYSTEM; 807 } 808 if (lockConnection == null || !lockConnection.containsDisplay(displayId)) { 809 which |= FLAG_LOCK; 810 } 811 if (mFallbackWallpaper.connection.containsDisplay(displayId)) { 812 // For existing fallback wallpaper connection, update the `which` flags. 813 DisplayConnector fallbackConnector = 814 mFallbackWallpaper.connection.mDisplayConnector.get(displayId); 815 try { 816 if (fallbackConnector != null && fallbackConnector.mEngine != null 817 && fallbackConnector.mWhich != which) { 818 fallbackConnector.mEngine.setWallpaperFlags(which); 819 mWindowManagerInternal.setWallpaperShowWhenLocked( 820 fallbackConnector.mToken, 821 /* showWhenLocked= */ (which & FLAG_LOCK) != 0); 822 fallbackConnector.mWhich = which; 823 } 824 } catch (RemoteException e) { 825 Slog.e(TAG, "Failed to update fallback wallpaper engine flags", e); 826 } 827 } else { 828 // For new fallback connection, establish the connection with the desired 829 // `which` flag. 830 DisplayConnector fallbackConnector = 831 mFallbackWallpaper.connection.getDisplayConnectorOrCreate(displayId); 832 if (fallbackConnector != null) { 833 fallbackConnector.mWhich = which; 834 fallbackConnector.connectLocked(mFallbackWallpaper.connection, 835 mFallbackWallpaper); 836 } 837 } 838 } 839 } else if (isWallpaperCompatibleForDisplay(DEFAULT_DISPLAY, systemConnection)) { 840 if (fallbackConnection.mDisplayConnector.size() != 0) { 841 fallbackConnection.forEachDisplayConnector(connector -> { 842 if (connector.mEngine != null) { 843 connector.disconnectLocked(fallbackConnection); 844 } 845 }); 846 fallbackConnection.mDisplayConnector.clear(); 847 } 848 } else { 849 fallbackConnection.appendConnectorWithCondition(display -> 850 mWallpaperDisplayHelper.isUsableDisplay(display, fallbackConnection.mClientUid) 851 && display.getDisplayId() != DEFAULT_DISPLAY 852 && !fallbackConnection.containsDisplay(display.getDisplayId())); 853 fallbackConnection.forEachDisplayConnector(connector -> { 854 if (connector.mEngine == null) { 855 connector.connectLocked(fallbackConnection, mFallbackWallpaper); 856 } 857 }); 858 } 859 } 860 861 /** 862 * Collect needed info for a display. 863 */ 864 @VisibleForTesting 865 final class DisplayConnector { 866 final int mDisplayId; 867 final Binder mToken = new Binder(); 868 IWallpaperEngine mEngine; 869 boolean mDimensionsChanged; 870 boolean mPaddingChanged; 871 872 // This field is added for the fallback wallpaper, which may have a different which flag for 873 // a different display. 874 int mWhich; 875 DisplayConnector(int displayId, int which)876 DisplayConnector(int displayId, int which) { 877 mDisplayId = displayId; 878 mWhich = which; 879 } 880 ensureStatusHandled()881 void ensureStatusHandled() { 882 final DisplayData wpdData = 883 mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId); 884 if (mDimensionsChanged) { 885 try { 886 mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight); 887 } catch (RemoteException e) { 888 Slog.w(TAG, "Failed to set wallpaper dimensions", e); 889 } 890 mDimensionsChanged = false; 891 } 892 if (mPaddingChanged) { 893 try { 894 mEngine.setDisplayPadding(wpdData.mPadding); 895 } catch (RemoteException e) { 896 Slog.w(TAG, "Failed to set wallpaper padding", e); 897 } 898 mPaddingChanged = false; 899 } 900 } 901 connectLocked(WallpaperConnection connection, WallpaperData wallpaper)902 void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) { 903 if (connection.mService == null) { 904 Slog.w(TAG, "WallpaperService is not connected yet"); 905 return; 906 } 907 int which = wallpaper.mWhich; 908 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { 909 which = mWhich; 910 } 911 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 912 t.traceBegin("WPMS.connectLocked-" + wallpaper.getComponent()); 913 if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken); 914 mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId, 915 null /* options */); 916 mWindowManagerInternal.setWallpaperShowWhenLocked( 917 mToken, (which & FLAG_LOCK) != 0); 918 if (multiCrop() && mImageWallpaper.equals(wallpaper.getComponent())) { 919 mWindowManagerInternal.setWallpaperCropHints(mToken, 920 mWallpaperCropper.getRelativeCropHints(wallpaper)); 921 } else { 922 mWindowManagerInternal.setWallpaperCropHints(mToken, new SparseArray<>()); 923 } 924 final DisplayData wpdData = 925 mWallpaperDisplayHelper.getDisplayDataOrCreate(mDisplayId); 926 try { 927 if (liveWallpaperContentHandling()) { 928 connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, 929 wpdData.mWidth, wpdData.mHeight, wpdData.mPadding, mDisplayId, which, 930 connection.mInfo, wallpaper.getDescription()); 931 } else { 932 WallpaperDescription desc = new WallpaperDescription.Builder().setComponent( 933 (connection.mInfo != null) ? connection.mInfo.getComponent() 934 : null).build(); 935 connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, 936 wpdData.mWidth, wpdData.mHeight, wpdData.mPadding, mDisplayId, which, 937 connection.mInfo, desc); 938 } 939 } catch (RemoteException e) { 940 Slog.w(TAG, "Failed attaching wallpaper on display", e); 941 if (wallpaper != null && !wallpaper.wallpaperUpdating 942 && connection.getConnectedEngineSize() == 0) { 943 wallpaper.mBindSource = BindSource.CONNECT_LOCKED; 944 bindWallpaperComponentLocked(null, false /* force */, false /* fromUser */, 945 wallpaper, null /* reply */); 946 } 947 } 948 t.traceEnd(); 949 } 950 disconnectLocked(WallpaperConnection connection)951 void disconnectLocked(WallpaperConnection connection) { 952 if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken); 953 mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */, 954 mDisplayId); 955 try { 956 if (connection.mService != null) { 957 connection.mService.detach(mToken); 958 } 959 } catch (RemoteException e) { 960 Slog.w(TAG, "connection.mService.destroy() threw a RemoteException", e); 961 } 962 mEngine = null; 963 } 964 } 965 966 class WallpaperConnection extends IWallpaperConnection.Stub 967 implements ServiceConnection { 968 969 /** 970 * A map for each display. 971 * Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable. 972 */ 973 private final SparseArray<DisplayConnector> mDisplayConnector = new SparseArray<>(); 974 975 /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the 976 * middle of an update). If exceeded, the wallpaper gets reset to the system default. */ 977 private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000; 978 private int mLmkLimitRebindRetries = LMK_RECONNECT_REBIND_RETRIES; 979 980 final WallpaperInfo mInfo; 981 IWallpaperService mService; 982 WallpaperData mWallpaper; 983 final int mClientUid; 984 IRemoteCallback mReply; 985 986 private Runnable mResetRunnable = () -> { 987 synchronized (mLock) { 988 if (mShuttingDown) { 989 // Don't expect wallpaper services to relaunch during shutdown 990 if (DEBUG_LIVE) { 991 Slog.i(TAG, "Ignoring relaunch timeout during shutdown"); 992 } 993 return; 994 } 995 996 if (avoidRebindingIntentionallyDisconnectedWallpaper() 997 && mWallpaper.connection == null) { 998 Slog.w(TAG, "Trying to reset an intentionally disconnected wallpaper!"); 999 return; 1000 } 1001 1002 if (!mWallpaper.wallpaperUpdating && mWallpaper.userId == mCurrentUserId) { 1003 Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.getComponent() 1004 + ", reverting to built-in wallpaper!"); 1005 clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null); 1006 } 1007 } 1008 }; 1009 1010 private Runnable mTryToRebindRunnable = this::tryToRebind; 1011 WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid)1012 WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) { 1013 mInfo = info; 1014 mWallpaper = wallpaper; 1015 mClientUid = clientUid; 1016 initDisplayState(); 1017 } 1018 initDisplayState()1019 private void initDisplayState() { 1020 // Do not initialize fallback wallpaper 1021 if (!mWallpaper.equals(mFallbackWallpaper)) { 1022 appendConnectorWithCondition(display -> { 1023 final int displayId = display.getDisplayId(); 1024 if (display.getDisplayId() == DEFAULT_DISPLAY) { 1025 return true; 1026 } 1027 return mWallpaperDisplayHelper.isUsableDisplay(display, mClientUid) 1028 && isWallpaperCompatibleForDisplay(displayId, /* connection= */ this); 1029 }); 1030 } 1031 } 1032 appendConnectorWithCondition(Predicate<Display> tester)1033 private void appendConnectorWithCondition(Predicate<Display> tester) { 1034 final Display[] displays = mWallpaperDisplayHelper.getDisplays(); 1035 for (Display display : displays) { 1036 if (tester.test(display)) { 1037 final int displayId = display.getDisplayId(); 1038 final DisplayConnector connector = mDisplayConnector.get(displayId); 1039 if (connector == null) { 1040 mDisplayConnector.append(displayId, 1041 new DisplayConnector(displayId, mWallpaper.mWhich)); 1042 } 1043 } 1044 } 1045 } 1046 forEachDisplayConnector(Consumer<DisplayConnector> action)1047 void forEachDisplayConnector(Consumer<DisplayConnector> action) { 1048 for (int i = mDisplayConnector.size() - 1; i >= 0; i--) { 1049 final DisplayConnector connector = mDisplayConnector.valueAt(i); 1050 action.accept(connector); 1051 } 1052 } 1053 getConnectedEngineSize()1054 int getConnectedEngineSize() { 1055 int engineSize = 0; 1056 for (int i = mDisplayConnector.size() - 1; i >= 0; i--) { 1057 final DisplayConnector connector = mDisplayConnector.valueAt(i); 1058 if (connector.mEngine != null) engineSize++; 1059 } 1060 return engineSize; 1061 } 1062 getDisplayConnectorOrCreate(int displayId)1063 DisplayConnector getDisplayConnectorOrCreate(int displayId) { 1064 DisplayConnector connector = mDisplayConnector.get(displayId); 1065 if (connector == null) { 1066 if (mWallpaperDisplayHelper.isUsableDisplay(displayId, mClientUid)) { 1067 connector = new DisplayConnector(displayId, mWallpaper.mWhich); 1068 mDisplayConnector.append(displayId, connector); 1069 } 1070 } 1071 return connector; 1072 } 1073 containsDisplay(int displayId)1074 boolean containsDisplay(int displayId) { 1075 return mDisplayConnector.get(displayId) != null; 1076 } 1077 removeDisplayConnector(int displayId)1078 void removeDisplayConnector(int displayId) { 1079 final DisplayConnector connector = mDisplayConnector.get(displayId); 1080 if (connector != null) { 1081 mDisplayConnector.remove(displayId); 1082 } 1083 } 1084 1085 @Override onServiceConnected(ComponentName name, IBinder service)1086 public void onServiceConnected(ComponentName name, IBinder service) { 1087 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 1088 t.traceBegin("WPMS.onServiceConnected-" + name); 1089 synchronized (mLock) { 1090 if (mWallpaper.connection == this) { 1091 mService = IWallpaperService.Stub.asInterface(service); 1092 attachServiceLocked(this, mWallpaper); 1093 // XXX should probably do saveSettingsLocked() later 1094 // when we have an engine, but I'm not sure about 1095 // locking there and anyway we always need to be able to 1096 // recover if there is something wrong. 1097 if (!mWallpaper.equals(mFallbackWallpaper)) { 1098 saveSettingsLocked(mWallpaper.userId); 1099 } 1100 FgThread.getHandler().removeCallbacks(mResetRunnable); 1101 mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable); 1102 mContext.getMainThreadHandler().removeCallbacks(mDisconnectRunnable); 1103 } 1104 } 1105 t.traceEnd(); 1106 } 1107 1108 @Override onLocalWallpaperColorsChanged(RectF area, WallpaperColors colors, int displayId)1109 public void onLocalWallpaperColorsChanged(RectF area, WallpaperColors colors, 1110 int displayId) { 1111 forEachDisplayConnector(displayConnector -> { 1112 Consumer<ILocalWallpaperColorConsumer> callback = cb -> { 1113 try { 1114 cb.onColorsChanged(area, colors); 1115 } catch (RemoteException e) { 1116 Slog.w(TAG, "Failed to notify local color callbacks", e); 1117 } 1118 }; 1119 synchronized (mLock) { 1120 // it is safe to make an IPC call since it is one way (returns immediately) 1121 mLocalColorRepo.forEachCallback(callback, area, displayId); 1122 } 1123 }); 1124 } 1125 1126 1127 @Override onServiceDisconnected(ComponentName name)1128 public void onServiceDisconnected(ComponentName name) { 1129 synchronized (mLock) { 1130 Slog.w(TAG, "Wallpaper service gone: " + name); 1131 if (!Objects.equals(name, mWallpaper.getComponent())) { 1132 Slog.e(TAG, "Does not match expected wallpaper component " 1133 + mWallpaper.getComponent()); 1134 } 1135 mService = null; 1136 forEachDisplayConnector(connector -> connector.mEngine = null); 1137 if (mWallpaper.connection == this) { 1138 // There is an inherent ordering race between this callback and the 1139 // package monitor that receives notice that a package is being updated, 1140 // so we cannot quite trust at this moment that we know for sure that 1141 // this is not an update. If we think this is a genuine non-update 1142 // wallpaper outage, we do our "wait for reset" work as a continuation, 1143 // a short time in the future, specifically to allow any pending package 1144 // update message on this same looper thread to be processed. 1145 if (!mWallpaper.wallpaperUpdating) { 1146 mContext.getMainThreadHandler().postDelayed(mDisconnectRunnable, 1147 1000); 1148 } 1149 } 1150 } 1151 } 1152 scheduleTimeoutLocked()1153 private void scheduleTimeoutLocked() { 1154 // If we didn't reset it right away, do so after we couldn't connect to 1155 // it for an extended amount of time to avoid having a black wallpaper. 1156 final Handler fgHandler = FgThread.getHandler(); 1157 fgHandler.removeCallbacks(mResetRunnable); 1158 fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS); 1159 if (DEBUG_LIVE) { 1160 Slog.i(TAG, 1161 "Started wallpaper reconnect timeout for " + mWallpaper.getComponent()); 1162 } 1163 } 1164 tryToRebind()1165 private void tryToRebind() { 1166 synchronized (mLock) { 1167 if (mWallpaper.wallpaperUpdating) { 1168 return; 1169 } 1170 1171 if (avoidRebindingIntentionallyDisconnectedWallpaper() 1172 && mWallpaper.connection == null) { 1173 Slog.w(TAG, "Trying to rebind an intentionally disconnected wallpaper!"); 1174 return; 1175 } 1176 1177 // The broadcast of package update could be delayed after service disconnected. Try 1178 // to re-bind the service for 10 seconds. 1179 mWallpaper.mBindSource = BindSource.CONNECTION_TRY_TO_REBIND; 1180 boolean success; 1181 if (liveWallpaperContentHandling()) { 1182 success = bindWallpaperDescriptionLocked( 1183 mWallpaper.getDescription(), /* force= */ true, 1184 /* fromUser= */ false, mWallpaper, /* reply= */ null); 1185 } else { 1186 success = bindWallpaperComponentLocked(mWallpaper.getComponent(), /* force= */ 1187 true, /* fromUser= */false, mWallpaper, /* reply= */ null); 1188 } 1189 if (success) { 1190 mWallpaper.connection.scheduleTimeoutLocked(); 1191 } else if (SystemClock.uptimeMillis() - mWallpaper.lastDiedTime 1192 < WALLPAPER_RECONNECT_TIMEOUT_MS) { 1193 // Bind fail without timeout, schedule rebind 1194 Slog.w(TAG, "Rebind fail! Try again later"); 1195 mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1000); 1196 } else { 1197 // Timeout 1198 Slog.w(TAG, "Reverting to built-in wallpaper!"); 1199 clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null); 1200 final String flattened = mWallpaper.getComponent().flattenToString(); 1201 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED, 1202 flattened.substring(0, Math.min(flattened.length(), 1203 MAX_WALLPAPER_COMPONENT_LOG_LENGTH))); 1204 } 1205 } 1206 } 1207 1208 private Runnable mDisconnectRunnable = () -> { 1209 synchronized (mLock) { 1210 // The wallpaper disappeared. If this isn't a system-default one, track 1211 // crashes and fall back to default if it continues to misbehave. 1212 if (this == mWallpaper.connection) { 1213 final ComponentName wpService = mWallpaper.getComponent(); 1214 if (!mWallpaper.wallpaperUpdating 1215 && mWallpaper.userId == mCurrentUserId 1216 && !Objects.equals(mDefaultWallpaperComponent, wpService) 1217 && !Objects.equals(mImageWallpaper, wpService)) { 1218 List<ApplicationExitInfo> reasonList = 1219 mActivityManager.getHistoricalProcessExitReasons( 1220 wpService.getPackageName(), 0, 1); 1221 int exitReason = ApplicationExitInfo.REASON_UNKNOWN; 1222 if (reasonList != null && !reasonList.isEmpty()) { 1223 ApplicationExitInfo info = reasonList.get(0); 1224 exitReason = info.getReason(); 1225 } 1226 Slog.d(TAG, "exitReason: " + exitReason); 1227 // If exit reason is LOW_MEMORY_KILLER 1228 // delay the mTryToRebindRunnable for 10s 1229 if (exitReason == ApplicationExitInfo.REASON_LOW_MEMORY) { 1230 if (isRunningOnLowMemory()) { 1231 Slog.i(TAG, "Rebind is delayed due to lmk"); 1232 mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1233 LMK_RECONNECT_DELAY_MS); 1234 mLmkLimitRebindRetries = LMK_RECONNECT_REBIND_RETRIES; 1235 } else { 1236 if (mLmkLimitRebindRetries <= 0) { 1237 Slog.w(TAG, "Reverting to built-in wallpaper due to lmk!"); 1238 clearWallpaperLocked( 1239 mWallpaper.mWhich, mWallpaper.userId, false, null); 1240 mLmkLimitRebindRetries = LMK_RECONNECT_REBIND_RETRIES; 1241 return; 1242 } 1243 mLmkLimitRebindRetries--; 1244 mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1245 LMK_RECONNECT_DELAY_MS); 1246 } 1247 } else { 1248 // There is a race condition which causes 1249 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is 1250 // currently updating since the broadcast notifying us is async. 1251 // This race is overcome by the general rule that we only reset the 1252 // wallpaper if its service was shut down twice 1253 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis. 1254 if (mWallpaper.lastDiedTime != 0 1255 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME 1256 > SystemClock.uptimeMillis()) { 1257 Slog.w(TAG, "Reverting to built-in wallpaper!"); 1258 clearWallpaperLocked(FLAG_SYSTEM, mWallpaper.userId, false, null); 1259 } else { 1260 mWallpaper.lastDiedTime = SystemClock.uptimeMillis(); 1261 tryToRebind(); 1262 } 1263 } 1264 } 1265 } else { 1266 if (DEBUG_LIVE) { 1267 Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring"); 1268 } 1269 } 1270 } 1271 }; 1272 isRunningOnLowMemory()1273 private boolean isRunningOnLowMemory() { 1274 ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); 1275 mActivityManager.getMemoryInfo(memoryInfo); 1276 double availableMBsInPercentage = memoryInfo.availMem / (double)memoryInfo.totalMem * 1277 100.0; 1278 return availableMBsInPercentage < LMK_LOW_THRESHOLD_MEMORY_PERCENTAGE; 1279 } 1280 1281 /** 1282 * Called by a live wallpaper if its colors have changed. 1283 * @param primaryColors representation of wallpaper primary colors 1284 * @param displayId for which display 1285 */ 1286 @Override onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId)1287 public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) { 1288 synchronized (mLock) { 1289 // Do not broadcast changes on ImageWallpaper since it's handled 1290 // internally by this class. 1291 boolean isImageWallpaper = mImageWallpaper.equals(mWallpaper.getComponent()); 1292 if (isImageWallpaper && (!offloadColorExtraction() || primaryColors == null)) { 1293 return; 1294 } 1295 mWallpaper.primaryColors = primaryColors; 1296 // only save the colors for ImageWallpaper - for live wallpapers, the colors 1297 // are always recomputed after a reboot. 1298 if (offloadColorExtraction() && isImageWallpaper) { 1299 saveSettingsLocked(mWallpaper.userId); 1300 } 1301 } 1302 notifyWallpaperColorsChangedOnDisplay(mWallpaper, displayId); 1303 } 1304 1305 @Override attachEngine(IWallpaperEngine engine, int displayId)1306 public void attachEngine(IWallpaperEngine engine, int displayId) { 1307 synchronized (mLock) { 1308 final DisplayConnector connector = getDisplayConnectorOrCreate(displayId); 1309 if (connector == null) { 1310 throw new IllegalStateException("Connector has already been destroyed"); 1311 } 1312 connector.mEngine = engine; 1313 connector.ensureStatusHandled(); 1314 1315 // TODO(multi-display) TBD. 1316 if (mInfo != null && mInfo.supportsAmbientMode() && displayId == DEFAULT_DISPLAY) { 1317 try { 1318 connector.mEngine.setInAmbientMode(mInAmbientMode, 0L /* duration */); 1319 } catch (RemoteException e) { 1320 Slog.w(TAG, "Failed to set ambient mode state", e); 1321 } 1322 } 1323 try { 1324 // This will trigger onComputeColors in the wallpaper engine. 1325 // It's fine to be locked in here since the binder is oneway. 1326 if (!offloadColorExtraction() || mWallpaper.primaryColors == null) { 1327 connector.mEngine.requestWallpaperColors(); 1328 } 1329 } catch (RemoteException e) { 1330 Slog.w(TAG, "Failed to request wallpaper colors", e); 1331 } 1332 1333 List<RectF> areas = mLocalColorRepo.getAreasByDisplayId(displayId); 1334 if (areas != null && areas.size() != 0) { 1335 try { 1336 connector.mEngine.addLocalColorsAreas(areas); 1337 } catch (RemoteException e) { 1338 Slog.w(TAG, "Failed to register local colors areas", e); 1339 } 1340 } 1341 1342 if (mWallpaper.mWallpaperDimAmount != 0f) { 1343 try { 1344 connector.mEngine.applyDimming(mWallpaper.mWallpaperDimAmount); 1345 } catch (RemoteException e) { 1346 Slog.w(TAG, "Failed to dim wallpaper", e); 1347 } 1348 } 1349 } 1350 } 1351 1352 @Override engineShown(IWallpaperEngine engine)1353 public void engineShown(IWallpaperEngine engine) { 1354 synchronized (mLock) { 1355 if (mReply != null) { 1356 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 1357 t.traceBegin("WPMS.mReply.sendResult"); 1358 final long ident = Binder.clearCallingIdentity(); 1359 try { 1360 mReply.sendResult(null); 1361 } catch (RemoteException e) { 1362 Slog.d(TAG, "Failed to send callback!", e); 1363 } finally { 1364 Binder.restoreCallingIdentity(ident); 1365 } 1366 t.traceEnd(); 1367 mReply = null; 1368 } 1369 } 1370 } 1371 1372 @Override setWallpaper(String name)1373 public ParcelFileDescriptor setWallpaper(String name) { 1374 synchronized (mLock) { 1375 if (mWallpaper.connection == this) { 1376 return updateWallpaperBitmapLocked(name, mWallpaper, null); 1377 } 1378 return null; 1379 } 1380 } 1381 } 1382 1383 /** 1384 * Tracks wallpaper information during a wallpaper change and does bookkeeping afterwards to 1385 * update Engine destination, wallpaper maps, and last wallpaper. 1386 */ 1387 class WallpaperDestinationChangeHandler { 1388 final WallpaperData mNewWallpaper; 1389 final WallpaperData mOriginalSystem; 1390 WallpaperDestinationChangeHandler(WallpaperData newWallpaper)1391 WallpaperDestinationChangeHandler(WallpaperData newWallpaper) { 1392 this.mNewWallpaper = newWallpaper; 1393 WallpaperData sysWp = mWallpaperMap.get(newWallpaper.userId); 1394 mOriginalSystem = new WallpaperData(sysWp); 1395 } 1396 complete()1397 void complete() { 1398 // Only changes from home+lock to just home or lock need attention 1399 if (mNewWallpaper.mSystemWasBoth) { 1400 if (DEBUG) { 1401 Slog.v(TAG, "Handling change from system+lock wallpaper"); 1402 } 1403 if (mNewWallpaper.mWhich == FLAG_SYSTEM) { 1404 // New wp is system only, so old system+lock is now lock only 1405 final boolean originalIsStatic = mImageWallpaper.equals( 1406 mOriginalSystem.getComponent()); 1407 if (originalIsStatic) { 1408 // Static wp: image file rename has already been tried via 1409 // migrateStaticSystemToLockWallpaperLocked() and added to the lock wp map 1410 // if successful. 1411 WallpaperData lockWp = mLockWallpaperMap.get(mNewWallpaper.userId); 1412 if (lockWp != null && mOriginalSystem.connection != null) { 1413 // Successful rename, set old system+lock to the pending lock wp 1414 if (DEBUG) { 1415 Slog.v(TAG, "static system+lock to system success"); 1416 } 1417 if (liveWallpaperContentHandling()) { 1418 lockWp.setDescription(mOriginalSystem.getDescription()); 1419 } else { 1420 lockWp.setComponent(mOriginalSystem.getComponent()); 1421 } 1422 lockWp.connection = mOriginalSystem.connection; 1423 lockWp.connection.mWallpaper = lockWp; 1424 mOriginalSystem.mWhich = FLAG_LOCK; 1425 updateEngineFlags(mOriginalSystem); 1426 } else { 1427 // Failed rename, use current system wp for both 1428 if (DEBUG) { 1429 Slog.v(TAG, "static system+lock to system failure"); 1430 } 1431 WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId); 1432 // In the constructor, we copied the system+lock wallpaper to 1433 // mOriginalSystem. However, the copied WallpaperData#connection is a 1434 // reference, not a deep copy. This means 1435 // currentSystem.connection.mWallpaper points to mOriginalSystem, so 1436 // changes to currentSystem.mWhich alone won't update the corresponding 1437 // flag in currentSystem.connection.mWallpaper.mWhich. Let's point 1438 // currentSystem.connection.mWallpaper back to currentSystem. 1439 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext) 1440 && currentSystem.connection != null) { 1441 currentSystem.connection.mWallpaper = currentSystem; 1442 } 1443 currentSystem.mWhich = FLAG_SYSTEM | FLAG_LOCK; 1444 updateEngineFlags(currentSystem); 1445 mLockWallpaperMap.remove(mNewWallpaper.userId); 1446 } 1447 } else { 1448 // Live wp: just update old system+lock to lock only 1449 if (DEBUG) { 1450 Slog.v(TAG, "live system+lock to system success"); 1451 } 1452 mOriginalSystem.mWhich = FLAG_LOCK; 1453 updateEngineFlags(mOriginalSystem); 1454 mLockWallpaperMap.put(mNewWallpaper.userId, mOriginalSystem); 1455 mLastLockWallpaper = mOriginalSystem; 1456 } 1457 } else if (mNewWallpaper.mWhich == FLAG_LOCK) { 1458 // New wp is lock only, so old system+lock is now system only 1459 if (DEBUG) { 1460 Slog.v(TAG, "system+lock to lock"); 1461 } 1462 WallpaperData currentSystem = mWallpaperMap.get(mNewWallpaper.userId); 1463 if (currentSystem.wallpaperId == mOriginalSystem.wallpaperId) { 1464 // Fixing the reference, see above for more details. 1465 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext) 1466 && currentSystem.connection != null) { 1467 currentSystem.connection.mWallpaper = currentSystem; 1468 } 1469 currentSystem.mWhich = FLAG_SYSTEM; 1470 updateEngineFlags(currentSystem); 1471 } 1472 } 1473 } 1474 saveSettingsLocked(mNewWallpaper.userId); 1475 1476 if (DEBUG) { 1477 Slog.v(TAG, "--- wallpaper changed --"); 1478 Slog.v(TAG, "new sysWp: " + mWallpaperMap.get(mCurrentUserId)); 1479 Slog.v(TAG, "new lockWp: " + mLockWallpaperMap.get(mCurrentUserId)); 1480 Slog.v(TAG, "new lastWp: " + mLastWallpaper); 1481 Slog.v(TAG, "new lastLockWp: " + mLastLockWallpaper); 1482 } 1483 } 1484 } 1485 1486 class MyPackageMonitor extends PackageMonitor { MyPackageMonitor()1487 private MyPackageMonitor() { 1488 super(true); 1489 } 1490 1491 @Override onPackageUpdateFinished(String packageName, int uid)1492 public void onPackageUpdateFinished(String packageName, int uid) { 1493 synchronized (mLock) { 1494 if (mCurrentUserId != getChangingUserId()) { 1495 return; 1496 } 1497 for (WallpaperData wallpaper: getWallpapers()) { 1498 final ComponentName wpService = wallpaper.getComponent(); 1499 if (wpService != null && wpService.getPackageName().equals(packageName)) { 1500 if (DEBUG_LIVE) { 1501 Slog.i(TAG, "Wallpaper " + wpService + " update has finished"); 1502 } 1503 wallpaper.wallpaperUpdating = false; 1504 detachWallpaperLocked(wallpaper); 1505 wallpaper.mBindSource = BindSource.PACKAGE_UPDATE_FINISHED; 1506 if (!bindWallpaperComponentLocked(wpService, false, false, 1507 wallpaper, null)) { 1508 Slog.w(TAG, "Wallpaper " + wpService 1509 + " no longer available; reverting to default"); 1510 clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null); 1511 } 1512 } 1513 } 1514 } 1515 } 1516 1517 @Override onPackageModified(String packageName)1518 public void onPackageModified(String packageName) { 1519 synchronized (mLock) { 1520 if (mCurrentUserId != getChangingUserId()) { 1521 return; 1522 } 1523 for (WallpaperData wallpaper: getWallpapers()) { 1524 if (wallpaper.getComponent() != null 1525 && wallpaper.getComponent().getPackageName().equals(packageName)) { 1526 doPackagesChangedLocked(true, wallpaper); 1527 } 1528 } 1529 } 1530 } 1531 1532 @Override onPackageUpdateStarted(String packageName, int uid)1533 public void onPackageUpdateStarted(String packageName, int uid) { 1534 synchronized (mLock) { 1535 if (mCurrentUserId != getChangingUserId()) { 1536 return; 1537 } 1538 for (WallpaperData wallpaper: getWallpapers()) { 1539 if (wallpaper.getComponent() != null 1540 && wallpaper.getComponent().getPackageName().equals(packageName)) { 1541 if (DEBUG_LIVE) { 1542 Slog.i(TAG, "Wallpaper service " + wallpaper.getComponent() 1543 + " is updating"); 1544 } 1545 wallpaper.wallpaperUpdating = true; 1546 if (wallpaper.connection != null) { 1547 FgThread.getHandler().removeCallbacks( 1548 wallpaper.connection.mResetRunnable); 1549 } 1550 } 1551 } 1552 } 1553 } 1554 1555 @Override onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)1556 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 1557 synchronized (mLock) { 1558 boolean changed = false; 1559 if (mCurrentUserId != getChangingUserId()) { 1560 return false; 1561 } 1562 for (WallpaperData wallpaper: getWallpapers()) { 1563 boolean res = doPackagesChangedLocked(doit, wallpaper); 1564 changed |= res; 1565 } 1566 return changed; 1567 } 1568 } 1569 1570 @Override onSomePackagesChanged()1571 public void onSomePackagesChanged() { 1572 synchronized (mLock) { 1573 if (mCurrentUserId != getChangingUserId()) { 1574 return; 1575 } 1576 for (WallpaperData wallpaper: getWallpapers()) { 1577 doPackagesChangedLocked(true, wallpaper); 1578 } 1579 } 1580 } 1581 doPackagesChangedLocked(boolean doit, WallpaperData wallpaper)1582 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) { 1583 boolean changed = false; 1584 if (wallpaper.getComponent() != null) { 1585 int change = isPackageDisappearing(wallpaper.getComponent() 1586 .getPackageName()); 1587 if (change == PACKAGE_PERMANENT_CHANGE 1588 || change == PACKAGE_TEMPORARY_CHANGE) { 1589 changed = true; 1590 if (doit) { 1591 Slog.e(TAG, "Wallpaper uninstalled, removing: " 1592 + wallpaper.getComponent()); 1593 clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null); 1594 } 1595 } 1596 } 1597 if (!removeNextWallpaperComponent()) { 1598 if (wallpaper.nextWallpaperComponent != null) { 1599 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent 1600 .getPackageName()); 1601 if (change == PACKAGE_PERMANENT_CHANGE 1602 || change == PACKAGE_TEMPORARY_CHANGE) { 1603 wallpaper.nextWallpaperComponent = null; 1604 } 1605 } 1606 } 1607 if (wallpaper.getComponent() != null 1608 && isPackageModified(wallpaper.getComponent().getPackageName())) { 1609 ServiceInfo serviceInfo = null; 1610 try { 1611 serviceInfo = mIPackageManager.getServiceInfo( 1612 wallpaper.getComponent(), PackageManager.MATCH_DIRECT_BOOT_AWARE 1613 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId); 1614 } catch (RemoteException e) { 1615 Slog.w(TAG, "Failed to call IPackageManager.getServiceInfo", e); 1616 } 1617 if (serviceInfo == null) { 1618 Slog.e(TAG, "Wallpaper component gone, removing: " 1619 + wallpaper.getComponent()); 1620 clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null); 1621 } 1622 } 1623 if (!removeNextWallpaperComponent()) { 1624 if (wallpaper.nextWallpaperComponent != null 1625 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) { 1626 try { 1627 mContext.getPackageManager().getServiceInfo( 1628 wallpaper.nextWallpaperComponent, 1629 PackageManager.MATCH_DIRECT_BOOT_AWARE 1630 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 1631 } catch (NameNotFoundException e) { 1632 wallpaper.nextWallpaperComponent = null; 1633 } 1634 } 1635 } 1636 return changed; 1637 } 1638 } 1639 1640 @VisibleForTesting getCurrentWallpaperData(@etWallpaperFlags int which, int userId)1641 WallpaperData getCurrentWallpaperData(@SetWallpaperFlags int which, int userId) { 1642 synchronized (mLock) { 1643 final SparseArray<WallpaperData> wallpaperDataMap = 1644 which == FLAG_SYSTEM ? mWallpaperMap : mLockWallpaperMap; 1645 return wallpaperDataMap.get(userId); 1646 } 1647 } 1648 WallpaperManagerService(Context context)1649 public WallpaperManagerService(Context context) { 1650 if (DEBUG) Slog.v(TAG, "WallpaperService startup"); 1651 mContext = context; 1652 mShuttingDown = false; 1653 mImageWallpaper = ComponentName.unflattenFromString( 1654 context.getResources().getString(R.string.image_wallpaper_component)); 1655 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { 1656 mFallbackWallpaperComponent = ComponentName.unflattenFromString( 1657 context.getResources().getString(R.string.fallback_wallpaper_component)); 1658 } else { 1659 mFallbackWallpaperComponent = null; 1660 } 1661 ComponentName defaultComponent = WallpaperManager.getCmfDefaultWallpaperComponent(context); 1662 mDefaultWallpaperComponent = defaultComponent == null ? mImageWallpaper : defaultComponent; 1663 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 1664 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 1665 mIPackageManager = AppGlobals.getPackageManager(); 1666 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 1667 DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); 1668 displayManager.registerDisplayListener(mDisplayListener, null /* handler */); 1669 WindowManager windowManager = mContext.getSystemService(WindowManager.class); 1670 mWallpaperDisplayHelper = new WallpaperDisplayHelper( 1671 displayManager, windowManager, mWindowManagerInternal, mContext.getResources()); 1672 mWallpaperCropper = new WallpaperCropper(mWallpaperDisplayHelper); 1673 mActivityManager = mContext.getSystemService(ActivityManager.class); 1674 1675 if (mContext.getResources().getBoolean( 1676 R.bool.config_pauseWallpaperRenderWhenStateChangeEnabled)) { 1677 // Pause wallpaper rendering engine as soon as a performance impacted app is launched. 1678 final String[] pauseRenderList = mContext.getResources().getStringArray( 1679 R.array.pause_wallpaper_render_when_state_change); 1680 final IntArray pauseRenderUids = new IntArray(); 1681 for (String pauseRenderApp : pauseRenderList) { 1682 try { 1683 int uid = mContext.getPackageManager().getApplicationInfo( 1684 pauseRenderApp, 0).uid; 1685 pauseRenderUids.add(uid); 1686 } catch (Exception e) { 1687 Slog.e(TAG, e.toString()); 1688 } 1689 } 1690 if (pauseRenderUids.size() > 0) { 1691 try { 1692 ActivityManager.getService().registerUidObserverForUids(new UidObserver() { 1693 @Override 1694 public void onUidStateChanged(int uid, int procState, long procStateSeq, 1695 int capability) { 1696 pauseOrResumeRenderingImmediately( 1697 procState == ActivityManager.PROCESS_STATE_TOP); 1698 } 1699 }, ActivityManager.UID_OBSERVER_PROCSTATE, 1700 ActivityManager.PROCESS_STATE_TOP, "android", 1701 pauseRenderUids.toArray()); 1702 } catch (RemoteException e) { 1703 Slog.e(TAG, e.toString()); 1704 } 1705 } 1706 } 1707 1708 mMonitor = new MyPackageMonitor(); 1709 mColorsChangedListeners = new SparseArray<>(); 1710 mWallpaperDataParser = new WallpaperDataParser(mContext, mWallpaperDisplayHelper, 1711 mWallpaperCropper); 1712 LocalServices.addService(WallpaperManagerInternal.class, new LocalService()); 1713 1714 LocalServices.getService(ActivityTaskManagerInternal.class) 1715 .registerScreenObserver(mKeyguardObserver); 1716 1717 } 1718 1719 private final ActivityTaskManagerInternal.ScreenObserver mKeyguardObserver = 1720 new ActivityTaskManagerInternal.ScreenObserver() { 1721 @Override 1722 public void onKeyguardStateChanged(boolean isShowing) { 1723 if (!notifyKeyguardEvents()) { 1724 return; 1725 } 1726 if (isShowing) { 1727 notifyKeyguardAppearing(); 1728 } else { 1729 notifyKeyguardGoingAway(); 1730 } 1731 } 1732 1733 @Override 1734 public void onKeyguardGoingAway() { 1735 notifyKeyguardGoingAway(); 1736 } 1737 }; 1738 1739 private final class LocalService extends WallpaperManagerInternal { 1740 @Override onDisplayAddSystemDecorations(int displayId)1741 public void onDisplayAddSystemDecorations(int displayId) { 1742 onDisplayAddSystemDecorationsInternal(displayId); 1743 } 1744 1745 @Override onDisplayRemoveSystemDecorations(int displayId)1746 public void onDisplayRemoveSystemDecorations(int displayId) { 1747 // The display mirroring starts. The handling logic is the same as when removing a 1748 // display. 1749 onDisplayRemovedInternal(displayId); 1750 } 1751 1752 @Override onScreenTurnedOn(int displayId)1753 public void onScreenTurnedOn(int displayId) { 1754 notifyScreenTurnedOn(displayId); 1755 } 1756 1757 @Override onScreenTurningOn(int displayId)1758 public void onScreenTurningOn(int displayId) { 1759 notifyScreenTurningOn(displayId); 1760 } 1761 } 1762 initialize()1763 void initialize() { 1764 mMonitor.register(mContext, null, UserHandle.ALL, true); 1765 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs(); 1766 1767 // Initialize state from the persistent store, then guarantee that the 1768 // WallpaperData for the system imagery is instantiated & active, creating 1769 // it from defaults if necessary. 1770 loadSettingsLocked(UserHandle.USER_SYSTEM, false, FLAG_SYSTEM | FLAG_LOCK); 1771 getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM); 1772 } 1773 1774 @Override finalize()1775 protected void finalize() throws Throwable { 1776 super.finalize(); 1777 for (int i = 0; i < mWallpaperMap.size(); i++) { 1778 WallpaperData wallpaper = mWallpaperMap.valueAt(i); 1779 wallpaper.wallpaperObserver.stopWatching(); 1780 } 1781 } 1782 systemReady()1783 void systemReady() { 1784 if (DEBUG) Slog.v(TAG, "systemReady"); 1785 initialize(); 1786 1787 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM); 1788 // If we think we're going to be using the system image wallpaper imagery, make 1789 // sure we have something to render 1790 boolean isImageComponent; 1791 if (removeNextWallpaperComponent()) { 1792 isImageComponent = wallpaper.getComponent() == null 1793 || mImageWallpaper.equals(wallpaper.getComponent()); 1794 } else { 1795 isImageComponent = mImageWallpaper.equals(wallpaper.nextWallpaperComponent); 1796 } 1797 if (isImageComponent) { 1798 // No crop file? Make sure we've finished the processing sequence if necessary 1799 if (!wallpaper.cropExists()) { 1800 if (DEBUG) { 1801 Slog.i(TAG, "No crop; regenerating from source"); 1802 } 1803 mWallpaperCropper.generateCrop(wallpaper); 1804 } 1805 // Still nothing? Fall back to default. 1806 if (!wallpaper.cropExists()) { 1807 if (DEBUG) { 1808 Slog.i(TAG, "Unable to regenerate crop; resetting"); 1809 } 1810 clearWallpaperLocked(wallpaper.mWhich, UserHandle.USER_SYSTEM, false, null); 1811 } 1812 } else { 1813 if (DEBUG) { 1814 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring"); 1815 } 1816 } 1817 1818 IntentFilter userFilter = new IntentFilter(); 1819 userFilter.addAction(Intent.ACTION_USER_REMOVED); 1820 mContext.registerReceiver(new BroadcastReceiver() { 1821 @Override 1822 public void onReceive(Context context, Intent intent) { 1823 final String action = intent.getAction(); 1824 if (Intent.ACTION_USER_REMOVED.equals(action)) { 1825 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1826 UserHandle.USER_NULL)); 1827 } 1828 } 1829 }, userFilter); 1830 1831 final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); 1832 mContext.registerReceiver(new BroadcastReceiver() { 1833 @Override 1834 public void onReceive(Context context, Intent intent) { 1835 if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { 1836 if (DEBUG) { 1837 Slog.i(TAG, "Shutting down"); 1838 } 1839 synchronized (mLock) { 1840 mShuttingDown = true; 1841 } 1842 } 1843 } 1844 }, shutdownFilter); 1845 1846 try { 1847 ActivityManager.getService().registerUserSwitchObserver( 1848 new UserSwitchObserver() { 1849 @Override 1850 public void onUserSwitching(int newUserId, IRemoteCallback reply) { 1851 errorCheck(newUserId); 1852 switchUser(newUserId, reply); 1853 } 1854 }, TAG); 1855 } catch (RemoteException e) { 1856 e.rethrowAsRuntimeException(); 1857 } 1858 } 1859 1860 /** Called by SystemBackupAgent */ getName()1861 public String getName() { 1862 // Verify caller is the system 1863 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 1864 throw new RuntimeException("getName() can only be called from the system process"); 1865 } 1866 synchronized (mLock) { 1867 return mWallpaperMap.get(0).name; 1868 } 1869 } 1870 stopObserver(WallpaperData wallpaper)1871 void stopObserver(WallpaperData wallpaper) { 1872 if (wallpaper != null) { 1873 if (wallpaper.wallpaperObserver != null) { 1874 wallpaper.wallpaperObserver.stopWatching(); 1875 wallpaper.wallpaperObserver = null; 1876 } 1877 } 1878 } 1879 stopObserversLocked(int userId)1880 void stopObserversLocked(int userId) { 1881 stopObserver(mWallpaperMap.get(userId)); 1882 stopObserver(mLockWallpaperMap.get(userId)); 1883 mWallpaperMap.remove(userId); 1884 mLockWallpaperMap.remove(userId); 1885 } 1886 1887 @Override onBootPhase(int phase)1888 public void onBootPhase(int phase) { 1889 // If someone set too large jpg file as wallpaper, system_server may be killed by lmk in 1890 // generateCrop(), so we create a file in generateCrop() before ImageDecoder starts working 1891 // and delete this file after ImageDecoder finishing. If the specific file exists, that 1892 // means ImageDecoder can't handle the original wallpaper file, in order to avoid 1893 // system_server restart again and again and rescue party will trigger factory reset, 1894 // so we reset default wallpaper in case system_server is trapped into a restart loop. 1895 errorCheck(UserHandle.USER_SYSTEM); 1896 1897 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 1898 systemReady(); 1899 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1900 switchUser(UserHandle.USER_SYSTEM, null); 1901 } 1902 } 1903 1904 private static final Map<Integer, String> sWallpaperType = Map.of( 1905 FLAG_SYSTEM, RECORD_FILE, 1906 FLAG_LOCK, RECORD_LOCK_FILE); 1907 errorCheck(int userID)1908 private void errorCheck(int userID) { 1909 sWallpaperType.forEach((type, filename) -> { 1910 final File record = new File(getWallpaperDir(userID), filename); 1911 if (record.exists()) { 1912 Slog.w(TAG, "User:" + userID + ", wallpaper type = " + type 1913 + ", wallpaper fail detect!! reset to default wallpaper"); 1914 clearWallpaperBitmaps(userID, type); 1915 record.delete(); 1916 } 1917 }); 1918 } 1919 clearWallpaperBitmaps(int userID, int wallpaperType)1920 private void clearWallpaperBitmaps(int userID, int wallpaperType) { 1921 final WallpaperData wallpaper = new WallpaperData(userID, wallpaperType); 1922 clearWallpaperBitmaps(wallpaper); 1923 } 1924 clearWallpaperBitmaps(WallpaperData wallpaper)1925 private boolean clearWallpaperBitmaps(WallpaperData wallpaper) { 1926 boolean sourceExists = wallpaper.sourceExists(); 1927 boolean cropExists = wallpaper.cropExists(); 1928 if (sourceExists) wallpaper.getWallpaperFile().delete(); 1929 if (cropExists) wallpaper.getCropFile().delete(); 1930 return sourceExists || cropExists; 1931 } 1932 1933 @Override onUnlockUser(final int userId)1934 public void onUnlockUser(final int userId) { 1935 synchronized (mLock) { 1936 if (mCurrentUserId == userId) { 1937 if (mHomeWallpaperWaitingForUnlock) { 1938 final WallpaperData systemWallpaper = 1939 getWallpaperSafeLocked(userId, FLAG_SYSTEM); 1940 systemWallpaper.mBindSource = BindSource.SWITCH_WALLPAPER_UNLOCK_USER; 1941 switchWallpaper(systemWallpaper, null); 1942 // TODO(b/278261563): call notifyCallbacksLocked inside switchWallpaper 1943 notifyCallbacksLocked(systemWallpaper); 1944 if (fixWallpaperChanged()) { 1945 notifyWallpaperChanged(systemWallpaper); 1946 } 1947 } 1948 if (mLockWallpaperWaitingForUnlock) { 1949 final WallpaperData lockWallpaper = 1950 getWallpaperSafeLocked(userId, FLAG_LOCK); 1951 lockWallpaper.mBindSource = BindSource.SWITCH_WALLPAPER_UNLOCK_USER; 1952 switchWallpaper(lockWallpaper, null); 1953 notifyCallbacksLocked(lockWallpaper); 1954 if (fixWallpaperChanged()) { 1955 notifyWallpaperChanged(lockWallpaper); 1956 } 1957 } 1958 1959 // Make sure that the SELinux labeling of all the relevant files is correct. 1960 // This corrects for mislabeling bugs that might have arisen from move-to 1961 // operations involving the wallpaper files. This isn't timing-critical, 1962 // so we do it in the background to avoid holding up the user unlock operation. 1963 if (!mUserRestorecon.get(userId)) { 1964 mUserRestorecon.put(userId, true); 1965 Runnable relabeler = () -> { 1966 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 1967 t.traceBegin("Wallpaper_selinux_restorecon-" + userId); 1968 try { 1969 for (File file: WallpaperUtils.getWallpaperFiles(userId)) { 1970 if (file.exists()) { 1971 SELinux.restorecon(file); 1972 } 1973 } 1974 } finally { 1975 t.traceEnd(); 1976 } 1977 }; 1978 BackgroundThread.getHandler().post(relabeler); 1979 } 1980 } 1981 } 1982 } 1983 onRemoveUser(int userId)1984 void onRemoveUser(int userId) { 1985 if (userId < 1) return; 1986 1987 synchronized (mLock) { 1988 stopObserversLocked(userId); 1989 WallpaperUtils.getWallpaperFiles(userId).forEach(File::delete); 1990 mUserRestorecon.delete(userId); 1991 } 1992 } 1993 switchUser(int userId, IRemoteCallback reply)1994 void switchUser(int userId, IRemoteCallback reply) { 1995 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 1996 t.traceBegin("Wallpaper_switch-user-" + userId); 1997 try { 1998 final WallpaperData systemWallpaper; 1999 final WallpaperData lockWallpaper; 2000 synchronized (mLock) { 2001 if (mCurrentUserId == userId) { 2002 return; 2003 } 2004 mCurrentUserId = userId; 2005 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); 2006 lockWallpaper = systemWallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM) 2007 ? systemWallpaper : getWallpaperSafeLocked(userId, FLAG_LOCK); 2008 2009 // Not started watching yet, in case wallpaper data was loaded for other reasons. 2010 if (systemWallpaper.wallpaperObserver == null) { 2011 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper); 2012 systemWallpaper.wallpaperObserver.startWatching(); 2013 } 2014 if (Flags.reorderWallpaperDuringUserSwitch()) { 2015 detachWallpaperLocked(mLastLockWallpaper); 2016 detachWallpaperLocked(mLastWallpaper); 2017 if (lockWallpaper == systemWallpaper) { 2018 switchWallpaper(systemWallpaper, reply); 2019 } else { 2020 KeyguardManager km = mContext.getSystemService(KeyguardManager.class); 2021 boolean isDeviceSecure = km != null && km.isDeviceSecure(userId); 2022 switchWallpaper(isDeviceSecure ? lockWallpaper : systemWallpaper, reply); 2023 switchWallpaper(isDeviceSecure ? systemWallpaper : lockWallpaper, null); 2024 } 2025 } else { 2026 if (lockWallpaper != systemWallpaper) { 2027 switchWallpaper(lockWallpaper, null); 2028 } 2029 switchWallpaper(systemWallpaper, reply); 2030 } 2031 mInitialUserSwitch = false; 2032 } 2033 2034 // Offload color extraction to another thread since switchUser will be called 2035 // from the main thread. 2036 FgThread.getHandler().post(() -> { 2037 if (offloadColorExtraction()) return; 2038 notifyWallpaperColorsChanged(systemWallpaper); 2039 if (lockWallpaper != systemWallpaper) notifyWallpaperColorsChanged(lockWallpaper); 2040 notifyWallpaperColorsChanged(mFallbackWallpaper); 2041 }); 2042 } finally { 2043 t.traceEnd(); 2044 } 2045 } 2046 switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply)2047 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) { 2048 synchronized (mLock) { 2049 if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false; 2050 if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false; 2051 2052 if (liveWallpaperContentHandling()) { 2053 final WallpaperDescription description = wallpaper.getDescription(); 2054 if (!bindWallpaperDescriptionLocked(description, true, false, wallpaper, reply)) { 2055 // We failed to bind the desired wallpaper, but that might 2056 // happen if the wallpaper isn't direct-boot aware 2057 ServiceInfo si = null; 2058 try { 2059 si = mIPackageManager.getServiceInfo(description.getComponent(), 2060 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId); 2061 } catch (RemoteException e) { 2062 Slog.w(TAG, "Failure starting previous wallpaper; clearing", e); 2063 } 2064 onSwitchWallpaperFailLocked(wallpaper, reply, si); 2065 } 2066 return; 2067 } 2068 2069 final ComponentName cname; 2070 if (removeNextWallpaperComponent()) { 2071 cname = wallpaper.getComponent(); 2072 } else { 2073 cname = (wallpaper.getComponent() != null) 2074 ? wallpaper.getComponent() : wallpaper.nextWallpaperComponent; 2075 } 2076 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) { 2077 // We failed to bind the desired wallpaper, but that might 2078 // happen if the wallpaper isn't direct-boot aware 2079 ServiceInfo si = null; 2080 try { 2081 si = mIPackageManager.getServiceInfo(cname, 2082 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId); 2083 } catch (RemoteException e) { 2084 Slog.w(TAG, "Failure starting previous wallpaper; clearing", e); 2085 } 2086 onSwitchWallpaperFailLocked(wallpaper, reply, si); 2087 } 2088 } 2089 } 2090 2091 /** 2092 * Fallback method if a wallpaper fails to load on boot or after a user switch. 2093 */ onSwitchWallpaperFailLocked( WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo)2094 private void onSwitchWallpaperFailLocked( 2095 WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) { 2096 2097 if (serviceInfo == null) { 2098 clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, reply); 2099 return; 2100 } 2101 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked"); 2102 if (!removeNextWallpaperComponent()) { 2103 // We might end up persisting the current wallpaper data 2104 // while locked, so pretend like the component was actually 2105 // bound into place 2106 wallpaper.setComponent(wallpaper.nextWallpaperComponent); 2107 } 2108 final WallpaperData fallback = new WallpaperData(wallpaper.userId, wallpaper.mWhich); 2109 2110 // files from the previous static wallpaper may still be stored in memory. 2111 // delete them in order to show the default wallpaper. 2112 clearWallpaperBitmaps(wallpaper); 2113 2114 fallback.mBindSource = BindSource.SWITCH_WALLPAPER_FAILURE; 2115 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply); 2116 if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = true; 2117 if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = true; 2118 } 2119 2120 @Override clearWallpaper(String callingPackage, int which, int userId)2121 public void clearWallpaper(String callingPackage, int which, int userId) { 2122 if (DEBUG) Slog.v(TAG, "clearWallpaper: " + which); 2123 checkPermission(android.Manifest.permission.SET_WALLPAPER); 2124 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) { 2125 return; 2126 } 2127 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2128 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null); 2129 2130 WallpaperData data = null; 2131 synchronized (mLock) { 2132 boolean fromForeground = isFromForegroundApp(callingPackage); 2133 clearWallpaperLocked(which, userId, fromForeground, null); 2134 2135 if (which == FLAG_LOCK) { 2136 data = mLockWallpaperMap.get(userId); 2137 } 2138 if (which == FLAG_SYSTEM || data == null) { 2139 data = mWallpaperMap.get(userId); 2140 } 2141 } 2142 } 2143 clearWallpaperLocked(int which, int userId, boolean fromForeground, IRemoteCallback reply)2144 private void clearWallpaperLocked(int which, int userId, boolean fromForeground, 2145 IRemoteCallback reply) { 2146 2147 // Might need to bring it in the first time to establish our rewrite 2148 if (!mWallpaperMap.contains(userId)) { 2149 loadSettingsLocked(userId, false, FLAG_LOCK | FLAG_SYSTEM); 2150 } 2151 final WallpaperData wallpaper = mWallpaperMap.get(userId); 2152 final WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); 2153 if (which == FLAG_LOCK && lockWallpaper == null) { 2154 // It's already gone; we're done. 2155 if (DEBUG) { 2156 Slog.i(TAG, "Lock wallpaper already cleared"); 2157 } 2158 return; 2159 } 2160 2161 RuntimeException e = null; 2162 try { 2163 if (userId != mCurrentUserId && !hasCrossUserPermission()) return; 2164 2165 // Clear any previous ImageWallpaper related fields 2166 List<WallpaperData> toClear = new ArrayList<>(); 2167 if ((which & FLAG_LOCK) > 0 && lockWallpaper != null) toClear.add(lockWallpaper); 2168 if ((which & FLAG_SYSTEM) > 0) toClear.add(wallpaper); 2169 for (WallpaperData wallpaperToClear : toClear) { 2170 clearWallpaperBitmaps(wallpaperToClear); 2171 if (multiCrop()) { 2172 wallpaperToClear.mCropHints.clear(); 2173 wallpaperToClear.cropHint.set(0, 0, 0, 0); 2174 wallpaperToClear.mSampleSize = 1; 2175 } 2176 } 2177 2178 final WallpaperDescription description; 2179 final int finalWhich; 2180 2181 if (liveWallpaperContentHandling()) { 2182 if (which == FLAG_LOCK) { 2183 // lock only case: set the system wallpaper component to both screens 2184 description = wallpaper.getDescription(); 2185 finalWhich = FLAG_LOCK | FLAG_SYSTEM; 2186 } else { 2187 description = new WallpaperDescription.Builder().build(); 2188 finalWhich = which; 2189 } 2190 } else { 2191 if (which == FLAG_LOCK) { 2192 // lock only case: set the system wallpaper component to both screens 2193 description = new WallpaperDescription.Builder().setComponent( 2194 wallpaper.getComponent()).build(); 2195 finalWhich = FLAG_LOCK | FLAG_SYSTEM; 2196 } else { 2197 description = new WallpaperDescription.Builder().build(); 2198 finalWhich = which; 2199 } 2200 } 2201 2202 // except for the lock case (for which we keep the system wallpaper as-is), force rebind 2203 boolean force = which != FLAG_LOCK; 2204 boolean success = withCleanCallingIdentity(() -> setWallpaperDescriptionInternal( 2205 description, finalWhich, userId, force, fromForeground, reply)); 2206 if (success) return; 2207 } catch (IllegalArgumentException e1) { 2208 e = e1; 2209 } 2210 2211 // This can happen if the default wallpaper component doesn't 2212 // exist. This should be a system configuration problem, but 2213 // let's not let it crash the system and just live with no 2214 // wallpaper. 2215 Slog.e(TAG, "Default wallpaper component not found!", e); 2216 withCleanCallingIdentity(() -> { 2217 wallpaper.mBindSource = BindSource.FALLBACK_DEFAULT_MISSING; 2218 bindWallpaperComponentLocked(mImageWallpaper, true, false, wallpaper, reply); 2219 }); 2220 if (reply != null) { 2221 try { 2222 reply.sendResult(null); 2223 } catch (RemoteException e1) { 2224 Slog.w(TAG, "Failed to notify callback after wallpaper clear", e1); 2225 } 2226 } 2227 } 2228 hasCrossUserPermission()2229 private boolean hasCrossUserPermission() { 2230 final int interactPermission = 2231 mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL); 2232 return interactPermission == PERMISSION_GRANTED; 2233 } 2234 2235 @Override hasNamedWallpaper(String name)2236 public boolean hasNamedWallpaper(String name) { 2237 final int callingUser = UserHandle.getCallingUserId(); 2238 final boolean allowCrossUser = hasCrossUserPermission(); 2239 if (DEBUG) { 2240 Slog.d(TAG, "hasNamedWallpaper() caller " + Binder.getCallingUid() 2241 + " cross-user?: " + allowCrossUser); 2242 } 2243 2244 synchronized (mLock) { 2245 List<UserInfo> users; 2246 final long ident = Binder.clearCallingIdentity(); 2247 try { 2248 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers(); 2249 } finally { 2250 Binder.restoreCallingIdentity(ident); 2251 } 2252 for (UserInfo user: users) { 2253 if (!allowCrossUser && callingUser != user.id) { 2254 // No cross-user information for callers without permission 2255 continue; 2256 } 2257 2258 // ignore profiles 2259 if (user.isProfile()) { 2260 continue; 2261 } 2262 WallpaperData wd = mWallpaperMap.get(user.id); 2263 if (wd == null) { 2264 // User hasn't started yet, so load their settings to peek at the wallpaper 2265 loadSettingsLocked(user.id, false, FLAG_SYSTEM | FLAG_LOCK); 2266 wd = mWallpaperMap.get(user.id); 2267 } 2268 if (wd != null && name.equals(wd.name)) { 2269 return true; 2270 } 2271 } 2272 } 2273 return false; 2274 } 2275 2276 /** 2277 * Sets the dimension hint for the wallpaper. These hints indicate the desired 2278 * minimum width and height for the wallpaper in a particular display. 2279 */ setDimensionHints(int width, int height, String callingPackage, int displayId)2280 public void setDimensionHints(int width, int height, String callingPackage, int displayId) 2281 throws RemoteException { 2282 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 2283 if (!isWallpaperSupported(callingPackage)) { 2284 return; 2285 } 2286 2287 // Make sure both width and height are not larger than max texture size. 2288 width = Math.min(width, GLHelper.getMaxTextureSize()); 2289 height = Math.min(height, GLHelper.getMaxTextureSize()); 2290 2291 synchronized (mLock) { 2292 int userId = UserHandle.getCallingUserId(); 2293 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); 2294 if (width <= 0 || height <= 0) { 2295 throw new IllegalArgumentException("width and height must be > 0"); 2296 } 2297 2298 if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) { 2299 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2300 } 2301 2302 final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId); 2303 if (width != wpdData.mWidth || height != wpdData.mHeight) { 2304 wpdData.mWidth = width; 2305 wpdData.mHeight = height; 2306 if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId); 2307 if (mCurrentUserId != userId) return; // Don't change the properties now 2308 if (wallpaper.connection != null) { 2309 final DisplayConnector connector = wallpaper.connection 2310 .getDisplayConnectorOrCreate(displayId); 2311 final IWallpaperEngine engine = connector != null ? connector.mEngine : null; 2312 if (engine != null) { 2313 try { 2314 engine.setDesiredSize(width, height); 2315 } catch (RemoteException e) { 2316 Slog.w(TAG, "Failed to set desired size", e); 2317 } 2318 notifyCallbacksLocked(wallpaper); 2319 } else if (wallpaper.connection.mService != null && connector != null) { 2320 // We've attached to the service but the engine hasn't attached back to us 2321 // yet. This means it will be created with the previous dimensions, so we 2322 // need to update it to the new dimensions once it attaches. 2323 connector.mDimensionsChanged = true; 2324 } 2325 } 2326 } 2327 } 2328 } 2329 2330 /** 2331 * Returns the desired minimum width for the wallpaper in a particular display. 2332 */ getWidthHint(int displayId)2333 public int getWidthHint(int displayId) throws RemoteException { 2334 synchronized (mLock) { 2335 if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) { 2336 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2337 } 2338 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); 2339 if (wallpaper != null) { 2340 final DisplayData wpdData = 2341 mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId); 2342 return wpdData.mWidth; 2343 } else { 2344 return 0; 2345 } 2346 } 2347 } 2348 2349 /** 2350 * Returns the desired minimum height for the wallpaper in a particular display. 2351 */ getHeightHint(int displayId)2352 public int getHeightHint(int displayId) throws RemoteException { 2353 synchronized (mLock) { 2354 if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) { 2355 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2356 } 2357 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); 2358 if (wallpaper != null) { 2359 final DisplayData wpdData = 2360 mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId); 2361 return wpdData.mHeight; 2362 } else { 2363 return 0; 2364 } 2365 } 2366 } 2367 2368 /** 2369 * Sets extra padding that we would like the wallpaper to have outside of the display. 2370 */ setDisplayPadding(Rect padding, String callingPackage, int displayId)2371 public void setDisplayPadding(Rect padding, String callingPackage, int displayId) { 2372 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 2373 if (!isWallpaperSupported(callingPackage)) { 2374 return; 2375 } 2376 synchronized (mLock) { 2377 if (!mWallpaperDisplayHelper.isValidDisplay(displayId)) { 2378 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2379 } 2380 int userId = UserHandle.getCallingUserId(); 2381 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); 2382 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) { 2383 throw new IllegalArgumentException("padding must be positive: " + padding); 2384 } 2385 2386 int maxSize = mWallpaperDisplayHelper.getMaximumSizeDimension(displayId); 2387 2388 final int paddingWidth = padding.left + padding.right; 2389 final int paddingHeight = padding.top + padding.bottom; 2390 if (paddingWidth > maxSize) { 2391 throw new IllegalArgumentException("padding width " + paddingWidth 2392 + " exceeds max width " + maxSize); 2393 } 2394 if (paddingHeight > maxSize) { 2395 throw new IllegalArgumentException("padding height " + paddingHeight 2396 + " exceeds max height " + maxSize); 2397 } 2398 2399 final DisplayData wpdData = mWallpaperDisplayHelper.getDisplayDataOrCreate(displayId); 2400 if (!padding.equals(wpdData.mPadding)) { 2401 wpdData.mPadding.set(padding); 2402 if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId); 2403 if (mCurrentUserId != userId) return; // Don't change the properties now 2404 if (wallpaper.connection != null) { 2405 final DisplayConnector connector = wallpaper.connection 2406 .getDisplayConnectorOrCreate(displayId); 2407 final IWallpaperEngine engine = connector != null ? connector.mEngine : null; 2408 if (engine != null) { 2409 try { 2410 engine.setDisplayPadding(padding); 2411 } catch (RemoteException e) { 2412 Slog.w(TAG, "Failed to set display padding", e); 2413 } 2414 notifyCallbacksLocked(wallpaper); 2415 } else if (wallpaper.connection.mService != null && connector != null) { 2416 // We've attached to the service but the engine hasn't attached back to us 2417 // yet. This means it will be created with the previous dimensions, so we 2418 // need to update it to the new dimensions once it attaches. 2419 connector.mPaddingChanged = true; 2420 } 2421 } 2422 } 2423 } 2424 } 2425 2426 @Deprecated 2427 @Override getWallpaper(String callingPkg, IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId)2428 public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb, 2429 final int which, Bundle outParams, int wallpaperUserId) { 2430 return getWallpaperWithFeature(callingPkg, null, cb, which, outParams, 2431 wallpaperUserId, /* getCropped= */ true); 2432 } 2433 2434 @Override getWallpaperWithFeature(String callingPkg, String callingFeatureId, IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId, boolean getCropped)2435 public ParcelFileDescriptor getWallpaperWithFeature(String callingPkg, String callingFeatureId, 2436 IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId, 2437 boolean getCropped) { 2438 final int callingPid = Binder.getCallingPid(); 2439 final int callingUid = Binder.getCallingUid(); 2440 final boolean hasPrivilege = hasPermission(READ_WALLPAPER_INTERNAL); 2441 if (!hasPrivilege) { 2442 boolean hasManageExternalStorage = hasPermission(MANAGE_EXTERNAL_STORAGE) 2443 || hasAppOpPermission(MANAGE_EXTERNAL_STORAGE, callingUid, callingPkg, 2444 callingFeatureId, "getWallpaperWithFeature from package: " + callingPkg); 2445 if (!hasManageExternalStorage) { 2446 mContext.getSystemService(StorageManager.class).checkPermissionReadImages(true, 2447 callingPid, callingUid, callingPkg, callingFeatureId); 2448 } 2449 } 2450 2451 wallpaperUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, 2452 wallpaperUserId, false, true, "getWallpaper", null); 2453 2454 if (which != FLAG_SYSTEM && which != FLAG_LOCK) { 2455 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read"); 2456 } 2457 2458 synchronized (mLock) { 2459 final SparseArray<WallpaperData> whichSet = 2460 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap; 2461 WallpaperData wallpaper = whichSet.get(wallpaperUserId); 2462 if (wallpaper == null) { 2463 // There is no established wallpaper imagery of this type (expected 2464 // only for lock wallpapers; a system WallpaperData is established at 2465 // user switch) 2466 return null; 2467 } 2468 // Only for default display. 2469 final DisplayData wpdData = 2470 mWallpaperDisplayHelper.getDisplayDataOrCreate(DEFAULT_DISPLAY); 2471 try { 2472 if (outParams != null) { 2473 outParams.putInt("width", wpdData.mWidth); 2474 outParams.putInt("height", wpdData.mHeight); 2475 } 2476 if (cb != null) { 2477 wallpaper.callbacks.register(cb); 2478 } 2479 2480 File result = getCropped ? wallpaper.getCropFile() : wallpaper.getWallpaperFile(); 2481 2482 if (!result.exists()) { 2483 return null; 2484 } 2485 2486 return ParcelFileDescriptor.open(result, MODE_READ_ONLY); 2487 } catch (FileNotFoundException e) { 2488 /* Shouldn't happen as we check to see if the file exists */ 2489 Slog.w(TAG, "Error getting wallpaper", e); 2490 } 2491 return null; 2492 } 2493 } 2494 2495 @Override getBitmapCrops(List<Point> displaySizes, @SetWallpaperFlags int which, boolean originalBitmap, int userId)2496 public List<Rect> getBitmapCrops(List<Point> displaySizes, @SetWallpaperFlags int which, 2497 boolean originalBitmap, int userId) { 2498 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2499 Binder.getCallingUid(), userId, false, true, "getBitmapCrop", null); 2500 synchronized (mLock) { 2501 checkPermission(READ_WALLPAPER_INTERNAL); 2502 WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId) 2503 : mWallpaperMap.get(userId); 2504 if (wallpaper == null || !mImageWallpaper.equals(wallpaper.getComponent())) { 2505 return null; 2506 } 2507 SparseArray<Rect> relativeSuggestedCrops = 2508 mWallpaperCropper.getRelativeCropHints(wallpaper); 2509 Point croppedBitmapSize = new Point( 2510 (int) Math.ceil(wallpaper.cropHint.width() / wallpaper.mSampleSize), 2511 (int) Math.ceil(wallpaper.cropHint.height() / wallpaper.mSampleSize)); 2512 if (croppedBitmapSize.equals(0, 0)) { 2513 // There is an ImageWallpaper, but there are no crop hints and the bitmap size is 2514 // unknown (e.g. the default wallpaper). Return a special "null" value that will be 2515 // handled by WallpaperManager, which will fetch the dimensions of the wallpaper. 2516 return null; 2517 } 2518 SparseArray<Rect> relativeDefaultCrops = 2519 mWallpaperCropper.getDefaultCrops(relativeSuggestedCrops, croppedBitmapSize); 2520 SparseArray<Rect> adjustedRelativeSuggestedCrops = new SparseArray<>(); 2521 for (int i = 0; i < relativeDefaultCrops.size(); i++) { 2522 int key = relativeDefaultCrops.keyAt(i); 2523 if (relativeSuggestedCrops.contains(key)) { 2524 adjustedRelativeSuggestedCrops.put(key, relativeDefaultCrops.get(key)); 2525 } 2526 } 2527 List<Rect> result = new ArrayList<>(); 2528 boolean rtl = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) 2529 == View.LAYOUT_DIRECTION_RTL; 2530 WallpaperDefaultDisplayInfo defaultDisplayInfo = 2531 mWallpaperDisplayHelper.getDefaultDisplayInfo(); 2532 for (Point displaySize : displaySizes) { 2533 result.add(WallpaperCropper.getCrop(displaySize, defaultDisplayInfo, 2534 croppedBitmapSize, adjustedRelativeSuggestedCrops, rtl)); 2535 } 2536 if (originalBitmap) result = WallpaperCropper.getOriginalCropHints(wallpaper, result); 2537 return result; 2538 } 2539 } 2540 2541 @Override getCurrentBitmapCrops(int which, int userId)2542 public Bundle getCurrentBitmapCrops(int which, int userId) { 2543 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2544 Binder.getCallingUid(), userId, false, true, "getBitmapCrop", null); 2545 synchronized (mLock) { 2546 checkPermission(READ_WALLPAPER_INTERNAL); 2547 WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId) 2548 : mWallpaperMap.get(userId); 2549 if (wallpaper == null || !mImageWallpaper.equals(wallpaper.getComponent())) { 2550 return null; 2551 } 2552 Bundle bundle = new Bundle(); 2553 for (int i = 0; i < wallpaper.mCropHints.size(); i++) { 2554 String key = String.valueOf(wallpaper.mCropHints.keyAt(i)); 2555 Rect rect = wallpaper.mCropHints.valueAt(i); 2556 bundle.putParcelable(key, rect); 2557 } 2558 return bundle; 2559 } 2560 } 2561 2562 @Override getFutureBitmapCrops(Point bitmapSize, List<Point> displaySizes, int[] screenOrientations, List<Rect> crops)2563 public List<Rect> getFutureBitmapCrops(Point bitmapSize, List<Point> displaySizes, 2564 int[] screenOrientations, List<Rect> crops) { 2565 SparseArray<Rect> cropMap = getCropMap(screenOrientations, crops); 2566 SparseArray<Rect> defaultCrops = mWallpaperCropper.getDefaultCrops(cropMap, bitmapSize); 2567 List<Rect> result = new ArrayList<>(); 2568 boolean rtl = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) 2569 == View.LAYOUT_DIRECTION_RTL; 2570 WallpaperDefaultDisplayInfo defaultDisplayInfo = 2571 mWallpaperDisplayHelper.getDefaultDisplayInfo(); 2572 for (Point displaySize : displaySizes) { 2573 result.add(WallpaperCropper.getCrop(displaySize, defaultDisplayInfo, bitmapSize, 2574 defaultCrops, rtl)); 2575 } 2576 return result; 2577 } 2578 2579 @Override getBitmapCrop(Point bitmapSize, int[] screenOrientations, List<Rect> crops)2580 public Rect getBitmapCrop(Point bitmapSize, int[] screenOrientations, List<Rect> crops) { 2581 if (!multiCrop()) { 2582 throw new UnsupportedOperationException( 2583 "This method should only be called with the multi crop flag enabled"); 2584 } 2585 SparseArray<Rect> cropMap = getCropMap(screenOrientations, crops); 2586 SparseArray<Rect> defaultCrops = mWallpaperCropper.getDefaultCrops(cropMap, bitmapSize); 2587 return WallpaperCropper.getTotalCrop(defaultCrops); 2588 } 2589 hasPermission(String permission)2590 private boolean hasPermission(String permission) { 2591 return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED; 2592 } 2593 hasPermission(WallpaperData data, String permission)2594 private boolean hasPermission(WallpaperData data, String permission) { 2595 try { 2596 return PackageManager.PERMISSION_GRANTED == mIPackageManager.checkPermission( 2597 permission, 2598 data.getComponent().getPackageName(), 2599 data.userId); 2600 } catch (RemoteException e) { 2601 Slog.e(TAG, "Failed to check wallpaper service permission", e); 2602 return false; 2603 } 2604 } 2605 hasAppOpPermission(String permission, int callingUid, String callingPackage, String attributionTag, String message)2606 private boolean hasAppOpPermission(String permission, int callingUid, String callingPackage, 2607 String attributionTag, String message) { 2608 final String op = AppOpsManager.permissionToOp(permission); 2609 final int opMode = mAppOpsManager.noteOpNoThrow(op, callingUid, callingPackage, 2610 attributionTag, message); 2611 switch (opMode) { 2612 case AppOpsManager.MODE_ALLOWED: 2613 case AppOpsManager.MODE_FOREGROUND: 2614 return true; 2615 case AppOpsManager.MODE_DEFAULT: 2616 return hasPermission(permission); 2617 default: 2618 return false; 2619 } 2620 } 2621 2622 @Override getWallpaperInfo(int userId)2623 public WallpaperInfo getWallpaperInfo(int userId) { 2624 return getWallpaperInfoWithFlags(FLAG_SYSTEM, userId); 2625 } 2626 2627 @Override getWallpaperInfoWithFlags(@etWallpaperFlags int which, int userId)2628 public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which, int userId) { 2629 if (liveWallpaperContentHandling()) { 2630 WallpaperInstance instance = getWallpaperInstance(which, userId, false); 2631 return (instance != null) ? instance.getInfo() : null; 2632 } 2633 2634 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2635 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null); 2636 synchronized (mLock) { 2637 WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId) 2638 : mWallpaperMap.get(userId); 2639 if (wallpaper == null 2640 || wallpaper.connection == null 2641 || wallpaper.connection.mInfo == null) return null; 2642 2643 WallpaperInfo info = wallpaper.connection.mInfo; 2644 if (hasPermission(READ_WALLPAPER_INTERNAL) 2645 || mPackageManagerInternal.canQueryPackage( 2646 Binder.getCallingUid(), info.getComponent().getPackageName())) { 2647 return info; 2648 } 2649 } 2650 return null; 2651 } 2652 2653 @Nullable 2654 @Override getWallpaperInstance(@etWallpaperFlags int which, int userId)2655 public WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which, int userId) { 2656 return getWallpaperInstance(which, userId, true); 2657 } 2658 getWallpaperInstance(@etWallpaperFlags int which, int userId, boolean requireReadWallpaper)2659 private WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which, int userId, 2660 boolean requireReadWallpaper) { 2661 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2662 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null); 2663 synchronized (mLock) { 2664 WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId) 2665 : mWallpaperMap.get(userId); 2666 if (wallpaper == null || wallpaper.connection == null) return null; 2667 2668 WallpaperInfo info = wallpaper.connection.mInfo; 2669 boolean canQueryPackage = (info == null) || mPackageManagerInternal.canQueryPackage( 2670 Binder.getCallingUid(), info.getComponent().getPackageName()); 2671 if (hasPermission(READ_WALLPAPER_INTERNAL) 2672 || (canQueryPackage && !requireReadWallpaper)) { 2673 // TODO(b/380245309) Remove this when crops are part of the description. 2674 WallpaperDescription description = 2675 wallpaper.getDescription().toBuilder().setCropHints( 2676 wallpaper.mCropHints).build(); 2677 return new WallpaperInstance(info, description); 2678 } else { 2679 return null; 2680 } 2681 } 2682 } 2683 2684 @Override getWallpaperInfoFile(int userId)2685 public ParcelFileDescriptor getWallpaperInfoFile(int userId) { 2686 synchronized (mLock) { 2687 try { 2688 File file = new File(getWallpaperDir(userId), WALLPAPER_INFO); 2689 2690 if (!file.exists()) { 2691 return null; 2692 } 2693 2694 return ParcelFileDescriptor.open(file, MODE_READ_ONLY); 2695 } catch (FileNotFoundException e) { 2696 /* Shouldn't happen as we check to see if the file exists */ 2697 Slog.w(TAG, "Error getting wallpaper info file", e); 2698 } 2699 return null; 2700 } 2701 } 2702 2703 @Override getWallpaperIdForUser(int which, int userId)2704 public int getWallpaperIdForUser(int which, int userId) { 2705 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2706 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null); 2707 2708 if (which != FLAG_SYSTEM && which != FLAG_LOCK) { 2709 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper"); 2710 } 2711 2712 final SparseArray<WallpaperData> map = 2713 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap; 2714 synchronized (mLock) { 2715 WallpaperData wallpaper = map.get(userId); 2716 if (wallpaper != null) { 2717 return wallpaper.wallpaperId; 2718 } 2719 } 2720 return -1; 2721 } 2722 2723 @Override registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId)2724 public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, 2725 int displayId) { 2726 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), 2727 userId, true, true, "registerWallpaperColorsCallback", null); 2728 synchronized (mLock) { 2729 SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> 2730 userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId); 2731 if (userDisplayColorsChangedListeners == null) { 2732 userDisplayColorsChangedListeners = new SparseArray<>(); 2733 mColorsChangedListeners.put(userId, userDisplayColorsChangedListeners); 2734 } 2735 RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners = 2736 userDisplayColorsChangedListeners.get(displayId); 2737 if (displayChangedListeners == null) { 2738 displayChangedListeners = new RemoteCallbackList<>(); 2739 userDisplayColorsChangedListeners.put(displayId, displayChangedListeners); 2740 } 2741 displayChangedListeners.register(cb); 2742 } 2743 } 2744 2745 @Override unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId)2746 public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, 2747 int displayId) { 2748 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), 2749 userId, true, true, "unregisterWallpaperColorsCallback", null); 2750 synchronized (mLock) { 2751 SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> 2752 userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId); 2753 if (userDisplayColorsChangedListeners != null) { 2754 RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners = 2755 userDisplayColorsChangedListeners.get(displayId); 2756 if (displayChangedListeners != null) { 2757 displayChangedListeners.unregister(cb); 2758 } 2759 } 2760 } 2761 } 2762 2763 /** 2764 * TODO(multi-display) Extends this method with specific display. 2765 * Propagate ambient state to wallpaper engine(s). 2766 * 2767 * @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise. 2768 * @param animationDuration Duration of the animation, or 0 when immediate. 2769 */ setInAmbientMode(boolean inAmbientMode, long animationDuration)2770 public void setInAmbientMode(boolean inAmbientMode, long animationDuration) { 2771 List<IWallpaperEngine> engines = new ArrayList<>(); 2772 synchronized (mLock) { 2773 mInAmbientMode = inAmbientMode; 2774 for (WallpaperData data : getActiveWallpapers()) { 2775 if (data.connection.mInfo == null 2776 || data.connection.mInfo.supportsAmbientMode()) { 2777 // TODO(multi-display) Extends this method with specific display. 2778 IWallpaperEngine engine = data.connection 2779 .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine; 2780 if (engine != null) engines.add(engine); 2781 } 2782 } 2783 } 2784 for (IWallpaperEngine engine : engines) { 2785 try { 2786 engine.setInAmbientMode(inAmbientMode, animationDuration); 2787 } catch (RemoteException e) { 2788 Slog.w(TAG, "Failed to set ambient mode", e); 2789 } 2790 } 2791 } 2792 pauseOrResumeRenderingImmediately(boolean pause)2793 private void pauseOrResumeRenderingImmediately(boolean pause) { 2794 synchronized (mLock) { 2795 for (WallpaperData data : getActiveWallpapers()) { 2796 if (data.connection.mInfo == null) { 2797 continue; 2798 } 2799 if (pause || LocalServices.getService(ActivityTaskManagerInternal.class) 2800 .isUidForeground(data.connection.mInfo.getServiceInfo() 2801 .applicationInfo.uid)) { 2802 if (data.connection.containsDisplay( 2803 mWindowManagerInternal.getTopFocusedDisplayId())) { 2804 data.connection.forEachDisplayConnector(displayConnector -> { 2805 if (displayConnector.mEngine != null) { 2806 try { 2807 displayConnector.mEngine.setVisibility(!pause); 2808 } catch (RemoteException e) { 2809 Slog.w(TAG, "Failed to set visibility", e); 2810 } 2811 } 2812 }); 2813 } 2814 } 2815 } 2816 } 2817 } 2818 2819 /** 2820 * Propagate a wake event to the wallpaper engine(s). 2821 */ notifyWakingUp(int x, int y, @NonNull Bundle extras)2822 public void notifyWakingUp(int x, int y, @NonNull Bundle extras) { 2823 checkCallerIsSystemOrSystemUi(); 2824 synchronized (mLock) { 2825 for (WallpaperData data : getActiveWallpapers()) { 2826 data.connection.forEachDisplayConnector(displayConnector -> { 2827 if (displayConnector.mEngine != null) { 2828 try { 2829 displayConnector.mEngine.dispatchWallpaperCommand( 2830 WallpaperManager.COMMAND_WAKING_UP, x, y, -1, extras); 2831 } catch (RemoteException e) { 2832 Slog.w(TAG, "Failed to dispatch COMMAND_WAKING_UP", e); 2833 } 2834 } 2835 }); 2836 } 2837 } 2838 } 2839 2840 /** 2841 * Propagate a sleep event to the wallpaper engine(s). 2842 */ notifyGoingToSleep(int x, int y, @NonNull Bundle extras)2843 public void notifyGoingToSleep(int x, int y, @NonNull Bundle extras) { 2844 checkCallerIsSystemOrSystemUi(); 2845 synchronized (mLock) { 2846 for (WallpaperData data : getActiveWallpapers()) { 2847 data.connection.forEachDisplayConnector(displayConnector -> { 2848 if (displayConnector.mEngine != null) { 2849 try { 2850 displayConnector.mEngine.dispatchWallpaperCommand( 2851 WallpaperManager.COMMAND_GOING_TO_SLEEP, x, y, -1, 2852 extras); 2853 } catch (RemoteException e) { 2854 Slog.w(TAG, "Failed to dispatch COMMAND_GOING_TO_SLEEP", e); 2855 } 2856 } 2857 }); 2858 } 2859 } 2860 } 2861 2862 /** 2863 * Propagates screen turned on event to wallpaper engine(s). 2864 */ notifyScreenTurnedOn(int displayId)2865 private void notifyScreenTurnedOn(int displayId) { 2866 synchronized (mLock) { 2867 for (WallpaperData data : getActiveWallpapers()) { 2868 if (data.connection.containsDisplay(displayId)) { 2869 final IWallpaperEngine engine = data.connection 2870 .getDisplayConnectorOrCreate(displayId).mEngine; 2871 if (engine != null) { 2872 try { 2873 engine.onScreenTurnedOn(); 2874 } catch (RemoteException e) { 2875 Slog.w(TAG, "Failed to notify that the screen turned on", e); 2876 } 2877 } 2878 } 2879 } 2880 } 2881 } 2882 2883 /** 2884 * Propagate screen turning on event to wallpaper engine(s). 2885 */ notifyScreenTurningOn(int displayId)2886 private void notifyScreenTurningOn(int displayId) { 2887 synchronized (mLock) { 2888 for (WallpaperData data : getActiveWallpapers()) { 2889 if (data.connection.containsDisplay(displayId)) { 2890 final IWallpaperEngine engine = data.connection 2891 .getDisplayConnectorOrCreate(displayId).mEngine; 2892 if (engine != null) { 2893 try { 2894 engine.onScreenTurningOn(); 2895 } catch (RemoteException e) { 2896 Slog.w(TAG, "Failed to notify that the screen is turning on", e); 2897 } 2898 } 2899 } 2900 } 2901 } 2902 } 2903 2904 /** 2905 * Propagate a keyguard going away event to the wallpaper engine. 2906 */ notifyKeyguardGoingAway()2907 private void notifyKeyguardGoingAway() { 2908 dispatchKeyguardCommand(WallpaperManager.COMMAND_KEYGUARD_GOING_AWAY); 2909 } 2910 2911 /** 2912 * Propagate a keyguard appearing event to the wallpaper engine. 2913 */ notifyKeyguardAppearing()2914 private void notifyKeyguardAppearing() { 2915 dispatchKeyguardCommand(WallpaperManager.COMMAND_KEYGUARD_APPEARING); 2916 } 2917 2918 /** 2919 * Propagate a keyguard-related event to the wallpaper engine. 2920 * 2921 * When the flag below is enabled, the event will only be dispatched in case the recipient 2922 * has {@link android.Manifest.pertmission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE} permission. 2923 */ dispatchKeyguardCommand(String command)2924 private void dispatchKeyguardCommand(String command) { 2925 synchronized (mLock) { 2926 for (WallpaperData data : getActiveWallpapers()) { 2927 if (notifyKeyguardEvents() && !hasPermission( 2928 data, android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)) { 2929 continue; 2930 } 2931 2932 data.connection.forEachDisplayConnector(displayConnector -> { 2933 if (displayConnector.mEngine != null) { 2934 try { 2935 displayConnector.mEngine.dispatchWallpaperCommand( 2936 command, -1, -1, -1, new Bundle()); 2937 } catch (RemoteException e) { 2938 Slog.w(TAG, "Failed to dispatch wallpaper command: " + command, e); 2939 } 2940 } 2941 }); 2942 } 2943 } 2944 } 2945 getActiveWallpapers()2946 private WallpaperData[] getActiveWallpapers() { 2947 WallpaperData systemWallpaper = mWallpaperMap.get(mCurrentUserId); 2948 WallpaperData lockWallpaper = mLockWallpaperMap.get(mCurrentUserId); 2949 boolean systemValid = systemWallpaper != null && systemWallpaper.connection != null; 2950 boolean lockValid = lockWallpaper != null && lockWallpaper.connection != null; 2951 return systemValid && lockValid ? new WallpaperData[]{systemWallpaper, lockWallpaper} 2952 : systemValid ? new WallpaperData[]{systemWallpaper} 2953 : lockValid ? new WallpaperData[]{lockWallpaper} 2954 : new WallpaperData[0]; 2955 } 2956 getWallpapers()2957 private WallpaperData[] getWallpapers() { 2958 WallpaperData systemWallpaper = mWallpaperMap.get(mCurrentUserId); 2959 WallpaperData lockWallpaper = mLockWallpaperMap.get(mCurrentUserId); 2960 boolean systemValid = systemWallpaper != null; 2961 boolean lockValid = lockWallpaper != null; 2962 return systemValid && lockValid ? new WallpaperData[]{systemWallpaper, lockWallpaper} 2963 : systemValid ? new WallpaperData[]{systemWallpaper} 2964 : lockValid ? new WallpaperData[]{lockWallpaper} 2965 : new WallpaperData[0]; 2966 } 2967 getEngine(int which, int userId, int displayId)2968 private IWallpaperEngine getEngine(int which, int userId, int displayId) { 2969 WallpaperData wallpaperData = findWallpaperAtDisplay(userId, displayId); 2970 if (wallpaperData == null) return null; 2971 WallpaperConnection connection = wallpaperData.connection; 2972 if (connection == null) return null; 2973 IWallpaperEngine engine = null; 2974 synchronized (mLock) { 2975 for (int i = 0; i < connection.mDisplayConnector.size(); i++) { 2976 int id = connection.mDisplayConnector.get(i).mDisplayId; 2977 int currentWhich = connection.mDisplayConnector.get(i).mDisplayId; 2978 if (id != displayId && currentWhich != which) continue; 2979 engine = connection.mDisplayConnector.get(i).mEngine; 2980 break; 2981 } 2982 } 2983 return engine; 2984 } 2985 2986 @Override addOnLocalColorsChangedListener(@onNull ILocalWallpaperColorConsumer callback, @NonNull List<RectF> regions, int which, int userId, int displayId)2987 public void addOnLocalColorsChangedListener(@NonNull ILocalWallpaperColorConsumer callback, 2988 @NonNull List<RectF> regions, int which, int userId, int displayId) 2989 throws RemoteException { 2990 if (which != FLAG_LOCK && which != FLAG_SYSTEM) { 2991 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM"); 2992 } 2993 IWallpaperEngine engine = getEngine(which, userId, displayId); 2994 if (engine == null) return; 2995 synchronized (mLock) { 2996 mLocalColorRepo.addAreas(callback, regions, displayId); 2997 } 2998 engine.addLocalColorsAreas(regions); 2999 } 3000 3001 @Override removeOnLocalColorsChangedListener( @onNull ILocalWallpaperColorConsumer callback, List<RectF> removeAreas, int which, int userId, int displayId)3002 public void removeOnLocalColorsChangedListener( 3003 @NonNull ILocalWallpaperColorConsumer callback, List<RectF> removeAreas, int which, 3004 int userId, int displayId) throws RemoteException { 3005 if (which != FLAG_LOCK && which != FLAG_SYSTEM) { 3006 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM"); 3007 } 3008 final UserHandle callingUser = Binder.getCallingUserHandle(); 3009 if (callingUser.getIdentifier() != userId) { 3010 throw new SecurityException("calling user id does not match"); 3011 } 3012 final long identity = Binder.clearCallingIdentity(); 3013 List<RectF> purgeAreas = null; 3014 try { 3015 synchronized (mLock) { 3016 purgeAreas = mLocalColorRepo.removeAreas(callback, removeAreas, displayId); 3017 } 3018 } catch (Exception e) { 3019 // ignore any exception 3020 } finally { 3021 Binder.restoreCallingIdentity(identity); 3022 } 3023 IWallpaperEngine engine = getEngine(which, userId, displayId); 3024 if (engine == null || purgeAreas == null) return; 3025 if (purgeAreas.size() > 0) engine.removeLocalColorsAreas(purgeAreas); 3026 } 3027 3028 /** 3029 * Returns true if the lock screen wallpaper exists (different wallpaper from the system) 3030 */ 3031 @Override lockScreenWallpaperExists()3032 public boolean lockScreenWallpaperExists() { 3033 synchronized (mLock) { 3034 return mLockWallpaperMap.get(mCurrentUserId) != null; 3035 } 3036 } 3037 3038 /** 3039 * Returns true if there is a static wallpaper on the specified screen. With which=FLAG_LOCK, 3040 * always return false if the lockscreen doesn't run its own wallpaper engine. 3041 */ 3042 @Override isStaticWallpaper(int which)3043 public boolean isStaticWallpaper(int which) { 3044 synchronized (mLock) { 3045 WallpaperData wallpaperData = (which == FLAG_LOCK ? mLockWallpaperMap : mWallpaperMap) 3046 .get(mCurrentUserId); 3047 if (wallpaperData == null) return false; 3048 return mImageWallpaper.equals(wallpaperData.getComponent()); 3049 } 3050 } 3051 3052 /** 3053 * Sets wallpaper dim amount for the calling UID. This applies to all destinations (home, lock) 3054 * with an active wallpaper engine. 3055 * 3056 * @param dimAmount Dim amount which would be blended with the system default dimming. 3057 */ 3058 @Override setWallpaperDimAmount(float dimAmount)3059 public void setWallpaperDimAmount(float dimAmount) throws RemoteException { 3060 setWallpaperDimAmountForUid(Binder.getCallingUid(), dimAmount); 3061 } 3062 3063 /** 3064 * Sets wallpaper dim amount for the calling UID. This applies to all destinations (home, lock) 3065 * with an active wallpaper engine. 3066 * 3067 * @param uid Caller UID that wants to set the wallpaper dim amount 3068 * @param dimAmount Dim amount where 0f reverts any dimming applied by the caller (fully bright) 3069 * and 1f is fully black 3070 * @throws RemoteException 3071 */ setWallpaperDimAmountForUid(int uid, float dimAmount)3072 public void setWallpaperDimAmountForUid(int uid, float dimAmount) { 3073 checkPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT); 3074 final long ident = Binder.clearCallingIdentity(); 3075 try { 3076 List<WallpaperData> pendingColorExtraction = new ArrayList<>(); 3077 synchronized (mLock) { 3078 // If called in boot before mCurrentUserId is set, sets the dim for USER_SYSTEM. 3079 int userId = mCurrentUserId != UserHandle.USER_NULL 3080 ? mCurrentUserId : UserHandle.USER_SYSTEM; 3081 WallpaperData wallpaper = mWallpaperMap.get(userId); 3082 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); 3083 3084 if (dimAmount == 0.0f) { 3085 wallpaper.mUidToDimAmount.remove(uid); 3086 } else { 3087 wallpaper.mUidToDimAmount.put(uid, dimAmount); 3088 } 3089 3090 float maxDimAmount = getHighestDimAmountFromMap(wallpaper.mUidToDimAmount); 3091 if (wallpaper.mWallpaperDimAmount == maxDimAmount) return; 3092 wallpaper.mWallpaperDimAmount = maxDimAmount; 3093 // Also set the dim amount to the lock screen wallpaper if the lock and home screen 3094 // do not share the same wallpaper 3095 if (lockWallpaper != null) { 3096 lockWallpaper.mWallpaperDimAmount = maxDimAmount; 3097 } 3098 3099 boolean changed = false; 3100 for (WallpaperData wp : getActiveWallpapers()) { 3101 if (wp != null && wp.connection != null) { 3102 wp.connection.forEachDisplayConnector(connector -> { 3103 if (connector.mEngine != null) { 3104 try { 3105 connector.mEngine.applyDimming(maxDimAmount); 3106 } catch (RemoteException e) { 3107 Slog.w(TAG, "Can't apply dimming on wallpaper display " 3108 + "connector", e); 3109 } 3110 } 3111 }); 3112 // Need to extract colors again to re-calculate dark hints after 3113 // applying dimming. 3114 if (!offloadColorExtraction()) { 3115 wp.mIsColorExtractedFromDim = true; 3116 pendingColorExtraction.add(wp); 3117 } 3118 changed = true; 3119 } 3120 } 3121 if (changed) { 3122 saveSettingsLocked(wallpaper.userId); 3123 } 3124 } 3125 for (WallpaperData wp: pendingColorExtraction) { 3126 if (!offloadColorExtraction()) notifyWallpaperColorsChanged(wp); 3127 } 3128 } finally { 3129 Binder.restoreCallingIdentity(ident); 3130 } 3131 } 3132 3133 @Override getWallpaperDimAmount()3134 public float getWallpaperDimAmount() { 3135 checkPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT); 3136 synchronized (mLock) { 3137 WallpaperData data = mWallpaperMap.get(mCurrentUserId); 3138 if (data == null) { 3139 data = mWallpaperMap.get(UserHandle.USER_SYSTEM); 3140 if (data == null) { 3141 Slog.e(TAG, "getWallpaperDimAmount: wallpaperData is null"); 3142 return 0.0f; 3143 } 3144 } 3145 return data.mWallpaperDimAmount; 3146 } 3147 } 3148 3149 /** 3150 * Gets the highest dim amount among all the calling UIDs that set the wallpaper dim amount. 3151 * Return 0f as default value to indicate no application has dimmed the wallpaper. 3152 * 3153 * @param uidToDimAmountMap Map of UIDs to dim amounts 3154 */ getHighestDimAmountFromMap(SparseArray<Float> uidToDimAmountMap)3155 private float getHighestDimAmountFromMap(SparseArray<Float> uidToDimAmountMap) { 3156 float maxDimAmount = 0.0f; 3157 for (int i = 0; i < uidToDimAmountMap.size(); i++) { 3158 maxDimAmount = Math.max(maxDimAmount, uidToDimAmountMap.valueAt(i)); 3159 } 3160 return maxDimAmount; 3161 } 3162 3163 @Override getWallpaperColors(int which, int userId, int displayId)3164 public WallpaperColors getWallpaperColors(int which, int userId, int displayId) 3165 throws RemoteException { 3166 if (which != FLAG_LOCK && which != FLAG_SYSTEM) { 3167 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM"); 3168 } 3169 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), 3170 userId, false, true, "getWallpaperColors", null); 3171 3172 WallpaperData wallpaperData = null; 3173 boolean shouldExtract; 3174 3175 synchronized (mLock) { 3176 if (which == FLAG_LOCK) { 3177 wallpaperData = mLockWallpaperMap.get(userId); 3178 } 3179 3180 // Try to get the system wallpaper anyway since it might 3181 // also be the lock screen wallpaper 3182 if (wallpaperData == null) { 3183 wallpaperData = findWallpaperAtDisplay(userId, displayId); 3184 } 3185 3186 if (wallpaperData == null) { 3187 return null; 3188 } 3189 shouldExtract = wallpaperData.primaryColors == null 3190 || wallpaperData.mIsColorExtractedFromDim; 3191 } 3192 3193 if (shouldExtract) { 3194 extractColors(wallpaperData); 3195 } 3196 3197 return getAdjustedWallpaperColorsOnDimming(wallpaperData); 3198 } 3199 3200 /** 3201 * Gets the adjusted {@link WallpaperColors} if the wallpaper colors were not extracted from 3202 * bitmap (i.e. it's a live wallpaper) and the dim amount is not 0. If these conditions apply, 3203 * default to using color hints that do not support dark theme and dark text. 3204 * 3205 * @param wallpaperData WallpaperData containing the WallpaperColors and mWallpaperDimAmount 3206 */ getAdjustedWallpaperColorsOnDimming(WallpaperData wallpaperData)3207 WallpaperColors getAdjustedWallpaperColorsOnDimming(WallpaperData wallpaperData) { 3208 synchronized (mLock) { 3209 WallpaperColors wallpaperColors = wallpaperData.primaryColors; 3210 3211 if (wallpaperColors != null 3212 && (wallpaperColors.getColorHints() & WallpaperColors.HINT_FROM_BITMAP) == 0 3213 && wallpaperData.mWallpaperDimAmount != 0f) { 3214 int adjustedColorHints = wallpaperColors.getColorHints() 3215 & ~WallpaperColors.HINT_SUPPORTS_DARK_TEXT 3216 & ~WallpaperColors.HINT_SUPPORTS_DARK_THEME; 3217 return new WallpaperColors( 3218 wallpaperColors.getPrimaryColor(), wallpaperColors.getSecondaryColor(), 3219 wallpaperColors.getTertiaryColor(), adjustedColorHints); 3220 } 3221 return wallpaperColors; 3222 } 3223 } 3224 findWallpaperAtDisplay(int userId, int displayId)3225 private WallpaperData findWallpaperAtDisplay(int userId, int displayId) { 3226 if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null 3227 && mFallbackWallpaper.connection.containsDisplay(displayId)) { 3228 return mFallbackWallpaper; 3229 } else { 3230 return mWallpaperMap.get(userId); 3231 } 3232 } 3233 3234 @Override setWallpaper(String name, String callingPackage, int[] screenOrientations, List<Rect> crops, boolean allowBackup, Bundle extras, int which, IWallpaperManagerCallback completion, int userId)3235 public ParcelFileDescriptor setWallpaper(String name, String callingPackage, 3236 int[] screenOrientations, List<Rect> crops, boolean allowBackup, 3237 Bundle extras, int which, IWallpaperManagerCallback completion, int userId) { 3238 3239 if (DEBUG) { 3240 Slog.d(TAG, "setWallpaper: name = " + name + ", callingPackage = " + callingPackage 3241 + ", screenOrientations = " 3242 + (screenOrientations == null ? null 3243 : Arrays.stream(screenOrientations).boxed().toList()) 3244 + ", crops = " + crops 3245 + ", allowBackup = " + allowBackup); 3246 } 3247 3248 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, 3249 false /* all */, true /* full */, "changing wallpaper", null /* pkg */); 3250 checkPermission(android.Manifest.permission.SET_WALLPAPER); 3251 3252 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) { 3253 final String msg = "Must specify a valid wallpaper category to set"; 3254 Slog.e(TAG, msg); 3255 throw new IllegalArgumentException(msg); 3256 } 3257 3258 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) { 3259 return null; 3260 } 3261 3262 SparseArray<Rect> cropMap = !multiCrop() ? null : getCropMap(screenOrientations, crops); 3263 Rect cropHint = multiCrop() || crops == null || crops.isEmpty() ? new Rect() : crops.get(0); 3264 final boolean fromForegroundApp = !multiCrop() ? false 3265 : isFromForegroundApp(callingPackage); 3266 3267 // "null" means the no-op crop, preserving the full input image 3268 if (cropHint == null && !multiCrop()) { 3269 cropHint = new Rect(0, 0, 0, 0); 3270 } else if (!multiCrop()) { 3271 if (cropHint.width() < 0 || cropHint.height() < 0 3272 || cropHint.left < 0 3273 || cropHint.top < 0) { 3274 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint); 3275 } 3276 } 3277 3278 synchronized (mLock) { 3279 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which)); 3280 WallpaperData wallpaper; 3281 final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId); 3282 final boolean systemIsStatic = 3283 originalSystemWallpaper != null && mImageWallpaper.equals( 3284 originalSystemWallpaper.getComponent()); 3285 final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null; 3286 3287 /* If we're setting system but not lock, and lock is currently sharing the system 3288 * wallpaper, we need to migrate that image over to being lock-only before 3289 * the caller here writes new bitmap data. 3290 */ 3291 if (which == FLAG_SYSTEM && systemIsStatic && systemIsBoth) { 3292 Slog.i(TAG, "Migrating current wallpaper to be lock-only before" 3293 + " updating system wallpaper"); 3294 migrateStaticSystemToLockWallpaperLocked(userId); 3295 } 3296 3297 wallpaper = getWallpaperSafeLocked(userId, which); 3298 if (mPendingMigrationViaStatic != null) { 3299 Slog.w(TAG, "Starting new static wp migration before previous migration finished"); 3300 } 3301 mPendingMigrationViaStatic = new WallpaperDestinationChangeHandler(wallpaper); 3302 final long ident = Binder.clearCallingIdentity(); 3303 try { 3304 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras); 3305 if (pfd != null) { 3306 wallpaper.imageWallpaperPending = true; 3307 wallpaper.mSystemWasBoth = systemIsBoth; 3308 wallpaper.mWhich = which; 3309 wallpaper.setComplete = completion; 3310 wallpaper.fromForegroundApp = multiCrop() ? fromForegroundApp 3311 : isFromForegroundApp(callingPackage); 3312 wallpaper.cropHint.set(cropHint); 3313 if (multiCrop()) { 3314 wallpaper.mCropHints = cropMap; 3315 wallpaper.mSampleSize = 1f; 3316 wallpaper.mOrientationWhenSet = 3317 mWallpaperDisplayHelper.getDefaultDisplayCurrentOrientation(); 3318 } 3319 wallpaper.allowBackup = allowBackup; 3320 wallpaper.mWallpaperDimAmount = getWallpaperDimAmount(); 3321 if (offloadColorExtraction()) wallpaper.primaryColors = null; 3322 } 3323 return pfd; 3324 } finally { 3325 Binder.restoreCallingIdentity(ident); 3326 } 3327 } 3328 } 3329 getCropMap(int[] screenOrientations, List<Rect> crops)3330 private SparseArray<Rect> getCropMap(int[] screenOrientations, List<Rect> crops) { 3331 if ((crops == null ^ screenOrientations == null) 3332 || (crops != null && crops.size() != screenOrientations.length)) { 3333 throw new IllegalArgumentException( 3334 "Illegal crops/orientations lists: must both be null, or both the same size"); 3335 } 3336 SparseArray<Rect> cropMap = new SparseArray<>(); 3337 if (crops != null && !crops.isEmpty()) { 3338 for (int i = 0; i < crops.size(); i++) { 3339 Rect crop = crops.get(i); 3340 int width = crop.width(), height = crop.height(); 3341 if (width < 0 || height < 0 || crop.left < 0 || crop.top < 0) { 3342 throw new IllegalArgumentException("Invalid crop rect supplied: " + crop); 3343 } 3344 int orientation = screenOrientations[i]; 3345 if (orientation == ORIENTATION_UNKNOWN && crops.size() > 1) { 3346 throw new IllegalArgumentException("Invalid crops supplied: the UNKNOWN" 3347 + "screen orientation should only be used in a singleton map"); 3348 } 3349 cropMap.put(orientation, crop); 3350 } 3351 } 3352 return cropMap; 3353 } 3354 migrateStaticSystemToLockWallpaperLocked(int userId)3355 private void migrateStaticSystemToLockWallpaperLocked(int userId) { 3356 WallpaperData sysWP = mWallpaperMap.get(userId); 3357 if (sysWP == null) { 3358 if (DEBUG) { 3359 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only"); 3360 } 3361 return; 3362 } 3363 3364 // We know a-priori that there is no lock-only wallpaper currently 3365 WallpaperData lockWP = new WallpaperData(userId, FLAG_LOCK); 3366 lockWP.wallpaperId = sysWP.wallpaperId; 3367 lockWP.cropHint.set(sysWP.cropHint); 3368 if (sysWP.mCropHints != null) { 3369 lockWP.mCropHints = sysWP.mCropHints.clone(); 3370 } 3371 lockWP.allowBackup = sysWP.allowBackup; 3372 lockWP.primaryColors = sysWP.primaryColors; 3373 lockWP.mWallpaperDimAmount = sysWP.mWallpaperDimAmount; 3374 lockWP.mWhich = FLAG_LOCK; 3375 3376 // Migrate the bitmap files outright; no need to copy 3377 try { 3378 if (sysWP.getWallpaperFile().exists()) { 3379 Os.rename(sysWP.getWallpaperFile().getAbsolutePath(), 3380 lockWP.getWallpaperFile().getAbsolutePath()); 3381 } 3382 if (sysWP.getCropFile().exists()) { 3383 Os.rename(sysWP.getCropFile().getAbsolutePath(), 3384 lockWP.getCropFile().getAbsolutePath()); 3385 } 3386 mLockWallpaperMap.put(userId, lockWP); 3387 SELinux.restorecon(lockWP.getWallpaperFile()); 3388 mLastLockWallpaper = lockWP; 3389 } catch (ErrnoException e) { 3390 // can happen when migrating default wallpaper (which is not stored in wallpaperFile) 3391 Slog.w(TAG, "Couldn't migrate system wallpaper: " + e.getMessage()); 3392 clearWallpaperBitmaps(lockWP); 3393 } 3394 } 3395 updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, Bundle extras)3396 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, 3397 Bundle extras) { 3398 if (name == null) name = ""; 3399 try { 3400 File dir = getWallpaperDir(wallpaper.userId); 3401 if (!dir.exists()) { 3402 dir.mkdir(); 3403 FileUtils.setPermissions( 3404 dir.getPath(), 3405 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, 3406 -1, -1); 3407 } 3408 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.getWallpaperFile(), 3409 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE); 3410 if (!SELinux.restorecon(wallpaper.getWallpaperFile())) { 3411 Slog.w(TAG, "restorecon failed for wallpaper file: " + 3412 wallpaper.getWallpaperFile().getPath()); 3413 return null; 3414 } 3415 wallpaper.name = name; 3416 wallpaper.wallpaperId = makeWallpaperIdLocked(); 3417 if (extras != null) { 3418 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId); 3419 } 3420 // Nullify field to require new computation 3421 wallpaper.primaryColors = null; 3422 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId 3423 + " name=" + name + " file=" + wallpaper.getWallpaperFile().getName()); 3424 return fd; 3425 } catch (FileNotFoundException e) { 3426 Slog.w(TAG, "Error setting wallpaper", e); 3427 } 3428 return null; 3429 } 3430 3431 @Override setWallpaperComponentChecked(WallpaperDescription description, String callingPackage, @SetWallpaperFlags int which, int userId)3432 public void setWallpaperComponentChecked(WallpaperDescription description, 3433 String callingPackage, @SetWallpaperFlags int which, int userId) { 3434 3435 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) { 3436 setWallpaperDescription(description, callingPackage, which, userId); 3437 } 3438 } 3439 3440 // ToDo: Remove this version of the function 3441 @Override setWallpaperComponent(ComponentName name)3442 public void setWallpaperComponent(ComponentName name) { 3443 setWallpaperComponent(name, "", UserHandle.getCallingUserId(), FLAG_SYSTEM); 3444 } 3445 3446 @VisibleForTesting setWallpaperComponent(ComponentName name, String callingPackage, @SetWallpaperFlags int which, int userId)3447 boolean setWallpaperComponent(ComponentName name, String callingPackage, 3448 @SetWallpaperFlags int which, int userId) { 3449 return setWallpaperDescription( 3450 new WallpaperDescription.Builder().setComponent(name).build(), callingPackage, 3451 which, userId); 3452 } 3453 3454 @VisibleForTesting setWallpaperDescription(WallpaperDescription description, String callingPackage, @SetWallpaperFlags int which, int userId)3455 boolean setWallpaperDescription(WallpaperDescription description, String callingPackage, 3456 @SetWallpaperFlags int which, int userId) { 3457 boolean fromForeground = isFromForegroundApp(callingPackage); 3458 return setWallpaperDescriptionInternal(description, which, userId, false, fromForeground, 3459 null); 3460 } 3461 setWallpaperDescriptionInternal(@onNull WallpaperDescription description, @SetWallpaperFlags int which, int userIdIn, boolean force, boolean fromForeground, IRemoteCallback reply)3462 private boolean setWallpaperDescriptionInternal(@NonNull WallpaperDescription description, 3463 @SetWallpaperFlags int which, int userIdIn, boolean force, boolean fromForeground, 3464 IRemoteCallback reply) { 3465 ComponentName name = description.getComponent(); 3466 if (DEBUG) { 3467 Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name); 3468 } 3469 final int userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), 3470 userIdIn, false /* all */, true /* full */, "changing live wallpaper", 3471 null /* pkg */); 3472 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); 3473 3474 boolean shouldNotifyColors = false; 3475 final boolean bindSuccess; 3476 3477 // If the lockscreen wallpaper is set to the same as the home screen, notify that the 3478 // lockscreen wallpaper colors changed, even if we don't bind a new wallpaper engine. 3479 boolean shouldNotifyLockscreenColors = false; 3480 final WallpaperData newWallpaper; 3481 3482 synchronized (mLock) { 3483 Slog.v(TAG, "setWallpaperComponent name=" + name + ", which = " + which); 3484 final WallpaperData originalSystemWallpaper = mWallpaperMap.get(userId); 3485 if (originalSystemWallpaper == null) { 3486 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); 3487 } 3488 final boolean systemIsStatic = mImageWallpaper.equals( 3489 originalSystemWallpaper.getComponent()); 3490 final boolean systemIsBoth = mLockWallpaperMap.get(userId) == null; 3491 3492 if (which == FLAG_SYSTEM && systemIsBoth && systemIsStatic) { 3493 // Migrate current static system+lock wp to lock only before proceeding. 3494 Slog.i(TAG, "Migrating current wallpaper to be lock-only before" 3495 + "updating system wallpaper"); 3496 migrateStaticSystemToLockWallpaperLocked(userId); 3497 } 3498 3499 newWallpaper = getWallpaperSafeLocked(userId, which); 3500 final long ident = Binder.clearCallingIdentity(); 3501 3502 try { 3503 newWallpaper.imageWallpaperPending = false; 3504 newWallpaper.mWhich = which; 3505 newWallpaper.mSystemWasBoth = systemIsBoth; 3506 newWallpaper.fromForegroundApp = fromForeground; 3507 final WallpaperDestinationChangeHandler 3508 liveSync = new WallpaperDestinationChangeHandler( 3509 newWallpaper); 3510 boolean same; 3511 if (liveWallpaperContentHandling()) { 3512 same = changingToSame(description, newWallpaper.connection, 3513 newWallpaper.getDescription()); 3514 } else { 3515 same = changingToSame(name, newWallpaper.connection, 3516 newWallpaper.getComponent()); 3517 } 3518 3519 /* 3520 * If we have a shared system+lock wallpaper, and we reapply the same wallpaper 3521 * to system only, force rebind: the current wallpaper will be migrated to lock 3522 * and a new engine with the same wallpaper will be applied to system. 3523 */ 3524 boolean forceRebind = force || (same && systemIsBoth && which == FLAG_SYSTEM); 3525 3526 newWallpaper.mBindSource = 3527 (name == null) ? BindSource.SET_LIVE_TO_CLEAR : BindSource.SET_LIVE; 3528 if (liveWallpaperContentHandling()) { 3529 bindSuccess = bindWallpaperDescriptionLocked(description, forceRebind, 3530 /* fromUser */ true, newWallpaper, reply); 3531 } else { 3532 bindSuccess = bindWallpaperComponentLocked(name, forceRebind, 3533 /* fromUser */ true, newWallpaper, reply); 3534 } 3535 if (bindSuccess) { 3536 if (!same || (offloadColorExtraction() && forceRebind)) { 3537 newWallpaper.primaryColors = null; 3538 } else { 3539 if (newWallpaper.connection != null) { 3540 newWallpaper.connection.forEachDisplayConnector(displayConnector -> { 3541 try { 3542 if (displayConnector.mEngine != null) { 3543 displayConnector.mEngine.dispatchWallpaperCommand( 3544 COMMAND_REAPPLY, 0, 0, 0, null); 3545 } 3546 } catch (RemoteException e) { 3547 Slog.w(TAG, "Error sending apply message to wallpaper", e); 3548 } 3549 }); 3550 } 3551 } 3552 boolean lockBitmapCleared = false; 3553 if (!mImageWallpaper.equals(newWallpaper.getComponent())) { 3554 clearWallpaperBitmaps(newWallpaper); 3555 lockBitmapCleared = newWallpaper.mWhich == FLAG_LOCK; 3556 } 3557 newWallpaper.wallpaperId = makeWallpaperIdLocked(); 3558 notifyCallbacksLocked(newWallpaper); 3559 if (fixWallpaperChanged()) { 3560 notifyWallpaperChanged(newWallpaper); 3561 } 3562 shouldNotifyColors = true; 3563 if (offloadColorExtraction()) { 3564 shouldNotifyColors = false; 3565 shouldNotifyLockscreenColors = !force && same && !systemIsBoth 3566 && which == (FLAG_SYSTEM | FLAG_LOCK); 3567 } 3568 3569 if (which == (FLAG_SYSTEM | FLAG_LOCK)) { 3570 if (DEBUG) { 3571 Slog.v(TAG, "Lock screen wallpaper changed to same as home"); 3572 } 3573 final WallpaperData lockedWallpaper = mLockWallpaperMap.get( 3574 newWallpaper.userId); 3575 if (lockedWallpaper != null) { 3576 detachWallpaperLocked(lockedWallpaper); 3577 if (same) { 3578 updateEngineFlags(newWallpaper); 3579 } 3580 } 3581 if (!lockBitmapCleared) { 3582 clearWallpaperBitmaps(newWallpaper.userId, FLAG_LOCK); 3583 } 3584 mLockWallpaperMap.remove(newWallpaper.userId); 3585 } 3586 if (liveSync != null) liveSync.complete(); 3587 } 3588 } finally { 3589 Binder.restoreCallingIdentity(ident); 3590 } 3591 } 3592 3593 if (shouldNotifyColors) { 3594 notifyWallpaperColorsChanged(newWallpaper); 3595 } 3596 if (shouldNotifyLockscreenColors) { 3597 notifyWallpaperColorsChanged(newWallpaper, FLAG_LOCK); 3598 } 3599 3600 return bindSuccess; 3601 } 3602 3603 /** 3604 * Determines if the given component name is the default component. Note: a null name can be 3605 * used to represent the default component. 3606 * @param name The component name to check. 3607 * @return True if the component name matches the default wallpaper component. 3608 */ isDefaultComponent(ComponentName name)3609 private boolean isDefaultComponent(ComponentName name) { 3610 return name == null || name.equals(mDefaultWallpaperComponent); 3611 } 3612 changingToSame(ComponentName newComponentName, WallpaperConnection currentConnection, ComponentName currentComponentName)3613 private boolean changingToSame(ComponentName newComponentName, 3614 WallpaperConnection currentConnection, ComponentName currentComponentName) { 3615 if (currentConnection != null) { 3616 if (isDefaultComponent(newComponentName) && isDefaultComponent(currentComponentName)) { 3617 if (DEBUG) Slog.v(TAG, "changingToSame: still using default"); 3618 // Still using default wallpaper. 3619 return true; 3620 } else if (currentComponentName != null && currentComponentName.equals( 3621 newComponentName)) { 3622 // Changing to same wallpaper. 3623 if (DEBUG) Slog.v(TAG, "same wallpaper"); 3624 return true; 3625 } 3626 } 3627 return false; 3628 } 3629 changingToSame(WallpaperDescription newDescription, WallpaperConnection currentConnection, WallpaperDescription currentDescription)3630 private boolean changingToSame(WallpaperDescription newDescription, 3631 WallpaperConnection currentConnection, WallpaperDescription currentDescription) { 3632 if (currentConnection == null) { 3633 return false; 3634 } 3635 if (isDefaultComponent(newDescription.getComponent()) && isDefaultComponent( 3636 currentDescription.getComponent())) { 3637 if (DEBUG) Slog.v(TAG, "changingToSame: still using default"); 3638 // Still using default wallpaper. 3639 return true; 3640 } else if (newDescription.equals(currentDescription)) { 3641 // Changing to same wallpaper. 3642 if (DEBUG) Slog.v(TAG, "same wallpaper"); 3643 return true; 3644 } 3645 return false; 3646 } 3647 3648 /* 3649 * Attempt to bind the wallpaper given by `componentName`, returning true on success otherwise 3650 * false. 3651 * 3652 * When called, `wallpaper` is in a deliberately inconsistent state. Most fields have been 3653 * updated to describe the desired wallpaper, but the ComponentName is not updated until 3654 * binding is successful. This is required for maybeDetachWallpapers() to work correctly. 3655 * 3656 * The late update of the component field should cause multi-threading headaches with 3657 * WallpaperConnection#onServiceConnected, but doesn't because onServiceConnected required 3658 * `mLock` and `bindWallpaperComponentLocked` is always called with that lock, which prevents a 3659 * race condition. 3660 * 3661 * This is a major motivation for making WallpaperData immutable per b/267170056. 3662 */ bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply)3663 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, 3664 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { 3665 return bindWallpaperDescriptionLocked( 3666 new WallpaperDescription.Builder().setComponent(componentName).build(), force, 3667 fromUser, wallpaper, reply); 3668 } 3669 3670 // When `liveWallpaperContentHandling()` is false this acts exactly like the version which takes 3671 // a ComponentName argument did: it uses the ComponentName from `description`, it binds the 3672 // service given by that component, and updates WallpaperData with that component on success. bindWallpaperDescriptionLocked(WallpaperDescription description, boolean force, boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply)3673 boolean bindWallpaperDescriptionLocked(WallpaperDescription description, boolean force, 3674 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { 3675 ComponentName componentName = description.getComponent(); 3676 if (DEBUG_LIVE) { 3677 Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); 3678 } 3679 boolean skipBinding; 3680 if (liveWallpaperContentHandling()) { 3681 skipBinding = !force && changingToSame(description, wallpaper.connection, 3682 wallpaper.getDescription()); 3683 } else { 3684 skipBinding = !force && changingToSame(componentName, wallpaper.connection, 3685 wallpaper.getComponent()); 3686 } 3687 if (skipBinding) { 3688 try { 3689 if (DEBUG_LIVE) { 3690 Slog.v(TAG, "Changing to the same component, ignoring"); 3691 } 3692 if (reply != null) reply.sendResult(null); 3693 } catch (RemoteException e) { 3694 Slog.e(TAG, "Failed to send callback", e); 3695 } 3696 return true; 3697 } 3698 3699 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 3700 t.traceBegin("WPMS.bindWallpaperComponentLocked-" + componentName); 3701 try { 3702 if (componentName == null) { 3703 componentName = mDefaultWallpaperComponent; 3704 if (liveWallpaperContentHandling()) { 3705 description = description.toBuilder().setComponent(componentName).build(); 3706 } 3707 } 3708 int serviceUserId = wallpaper.userId; 3709 ServiceInfo si = mIPackageManager.getServiceInfo(componentName, 3710 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId); 3711 if (si == null) { 3712 // The wallpaper component we're trying to use doesn't exist 3713 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable"); 3714 return false; 3715 } 3716 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) { 3717 String msg = "Selected service does not have " 3718 + android.Manifest.permission.BIND_WALLPAPER 3719 + ": " + componentName; 3720 if (fromUser) { 3721 throw new SecurityException(msg); 3722 } 3723 Slog.w(TAG, msg); 3724 return false; 3725 } 3726 3727 // This will only get set for non-static wallpapers. 3728 WallpaperInfo wi = null; 3729 3730 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); 3731 if (componentName != null && !componentName.equals(mImageWallpaper)) { 3732 // The requested component is not the static wallpaper service, so make sure it's 3733 // actually a wallpaper service. 3734 if (mFallbackWallpaperComponent != null 3735 && componentName.equals(mFallbackWallpaperComponent)) { 3736 // The fallback wallpaper does not declare WallpaperService.SERVICE_INTERFACE 3737 // action in its intent filter to prevent it from being listed in the wallpaper 3738 // picker. And thus, use explicit intent to query the metadata. 3739 intent = new Intent().setComponent(mFallbackWallpaperComponent); 3740 } 3741 List<ResolveInfo> ris = 3742 mIPackageManager.queryIntentServices(intent, 3743 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 3744 PackageManager.GET_META_DATA, serviceUserId).getList(); 3745 for (int i=0; i<ris.size(); i++) { 3746 ServiceInfo rsi = ris.get(i).serviceInfo; 3747 if (rsi.name.equals(si.name) && 3748 rsi.packageName.equals(si.packageName)) { 3749 try { 3750 wi = new WallpaperInfo(mContext, ris.get(i)); 3751 } catch (XmlPullParserException e) { 3752 if (fromUser) { 3753 throw new IllegalArgumentException(e); 3754 } 3755 Slog.w(TAG, e); 3756 return false; 3757 } catch (IOException e) { 3758 if (fromUser) { 3759 throw new IllegalArgumentException(e); 3760 } 3761 Slog.w(TAG, e); 3762 return false; 3763 } 3764 break; 3765 } 3766 } 3767 if (wi == null) { 3768 String msg = "Selected service is not a wallpaper: " 3769 + componentName; 3770 if (fromUser) { 3771 throw new SecurityException(msg); 3772 } 3773 Slog.w(TAG, msg); 3774 return false; 3775 } 3776 } 3777 3778 if (wi != null && wi.supportsAmbientMode()) { 3779 final int hasPrivilege = mIPackageManager.checkPermission( 3780 android.Manifest.permission.AMBIENT_WALLPAPER, wi.getPackageName(), 3781 serviceUserId); 3782 // All watch wallpapers support ambient mode by default. 3783 if (hasPrivilege != PERMISSION_GRANTED 3784 && !mIPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) { 3785 String msg = "Selected service does not have " 3786 + android.Manifest.permission.AMBIENT_WALLPAPER 3787 + ": " + componentName; 3788 if (fromUser) { 3789 throw new SecurityException(msg); 3790 } 3791 Slog.w(TAG, msg); 3792 return false; 3793 } 3794 } 3795 3796 final ActivityOptions clientOptions = ActivityOptions.makeBasic() 3797 .setPendingIntentCreatorBackgroundActivityStartMode( 3798 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED); 3799 PendingIntent clientIntent = PendingIntent.getActivityAsUser( 3800 mContext, 0, Intent.createChooser( 3801 new Intent(Intent.ACTION_SET_WALLPAPER), 3802 mContext.getText(com.android.internal.R.string.chooser_wallpaper)), 3803 PendingIntent.FLAG_IMMUTABLE, clientOptions.toBundle(), 3804 UserHandle.of(serviceUserId)); 3805 3806 // Bind the service! 3807 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName); 3808 final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(), 3809 MATCH_DIRECT_BOOT_AUTO, wallpaper.userId); 3810 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid); 3811 intent.setComponent(componentName); 3812 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, 3813 com.android.internal.R.string.wallpaper_binding_label); 3814 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, clientIntent); 3815 int bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI 3816 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE 3817 | Context.BIND_INCLUDE_CAPABILITIES; 3818 3819 if (mContext.getResources().getBoolean( 3820 com.android.internal.R.bool.config_wallpaperTopApp)) { 3821 bindFlags |= Context.BIND_SCHEDULE_LIKE_TOP_APP; 3822 } 3823 boolean bindSuccess = mContext.bindServiceAsUser(intent, newConn, bindFlags, 3824 getHandlerForBindingWallpaperLocked(), new UserHandle(serviceUserId)); 3825 if (!bindSuccess) { 3826 String msg = "Unable to bind service: " + componentName; 3827 if (fromUser) { 3828 throw new IllegalArgumentException(msg); 3829 } 3830 Slog.w(TAG, msg); 3831 return false; 3832 } 3833 maybeDetachLastWallpapers(wallpaper); 3834 if (liveWallpaperContentHandling()) { 3835 wallpaper.setDescription(description); 3836 } else { 3837 wallpaper.setComponent(componentName); 3838 } 3839 wallpaper.connection = newConn; 3840 newConn.mReply = reply; 3841 updateCurrentWallpapers(wallpaper); 3842 updateFallbackConnection(componentUid); 3843 } catch (RemoteException e) { 3844 String msg = "Remote exception for " + componentName + "\n" + e; 3845 if (fromUser) { 3846 throw new IllegalArgumentException(msg); 3847 } 3848 Slog.w(TAG, msg); 3849 return false; 3850 } finally { 3851 t.traceEnd(); 3852 } 3853 return true; 3854 } 3855 getHandlerForBindingWallpaperLocked()3856 private Handler getHandlerForBindingWallpaperLocked() { 3857 if (!Flags.bindWallpaperServiceOnItsOwnThreadDuringAUserSwitch()) { 3858 return mContext.getMainThreadHandler(); 3859 } 3860 if (mInitialUserSwitch) { 3861 return mContext.getMainThreadHandler(); 3862 } 3863 if (mHandlerThread == null) { 3864 mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_FOREGROUND, true /*allowIo*/); 3865 mHandlerThread.start(); 3866 } 3867 return mHandlerThread.getThreadHandler(); 3868 } 3869 3870 // Updates tracking of the currently bound wallpapers. updateCurrentWallpapers(WallpaperData newWallpaper)3871 private void updateCurrentWallpapers(WallpaperData newWallpaper) { 3872 if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) { 3873 return; 3874 } 3875 if (newWallpaper.mWhich == (FLAG_SYSTEM | FLAG_LOCK)) { 3876 mLastWallpaper = newWallpaper; 3877 mLastLockWallpaper = null; 3878 } else if (newWallpaper.mWhich == FLAG_SYSTEM) { 3879 mLastWallpaper = newWallpaper; 3880 } else if (newWallpaper.mWhich == FLAG_LOCK) { 3881 mLastLockWallpaper = newWallpaper; 3882 } 3883 } 3884 3885 // Detaches previously bound wallpapers if no longer in use. maybeDetachLastWallpapers(WallpaperData newWallpaper)3886 private void maybeDetachLastWallpapers(WallpaperData newWallpaper) { 3887 if (newWallpaper.userId != mCurrentUserId || newWallpaper.equals(mFallbackWallpaper)) { 3888 return; 3889 } 3890 boolean homeUpdated = (newWallpaper.mWhich & FLAG_SYSTEM) != 0; 3891 boolean lockUpdated = (newWallpaper.mWhich & FLAG_LOCK) != 0; 3892 boolean systemWillBecomeLock = newWallpaper.mSystemWasBoth && !lockUpdated; 3893 if (homeUpdated && !systemWillBecomeLock) { 3894 detachWallpaperLocked(mLastWallpaper); 3895 } 3896 if (lockUpdated) { 3897 detachWallpaperLocked(mLastLockWallpaper); 3898 } 3899 } 3900 3901 // Frees up all rendering resources used by the given wallpaper so that the WallpaperData object 3902 // can be reused: detaches Engine, unbinds WallpaperService, etc. detachWallpaperLocked(WallpaperData wallpaper)3903 private void detachWallpaperLocked(WallpaperData wallpaper) { 3904 if (wallpaper != null && wallpaper.connection != null) { 3905 if (DEBUG) { 3906 Slog.v(TAG, "Detaching wallpaper: " + wallpaper); 3907 } 3908 if (wallpaper.connection.mReply != null) { 3909 try { 3910 wallpaper.connection.mReply.sendResult(null); 3911 } catch (RemoteException e) { 3912 Slog.w(TAG, "Error sending reply to wallpaper before disconnect", e); 3913 } 3914 wallpaper.connection.mReply = null; 3915 } 3916 wallpaper.connection.forEachDisplayConnector( 3917 connector -> connector.disconnectLocked(wallpaper.connection)); 3918 wallpaper.connection.mService = null; 3919 wallpaper.connection.mDisplayConnector.clear(); 3920 3921 FgThread.getHandler().removeCallbacks(wallpaper.connection.mResetRunnable); 3922 mContext.getMainThreadHandler().removeCallbacks( 3923 wallpaper.connection.mDisconnectRunnable); 3924 mContext.getMainThreadHandler().removeCallbacks( 3925 wallpaper.connection.mTryToRebindRunnable); 3926 3927 try { 3928 mContext.unbindService(wallpaper.connection); 3929 } catch (IllegalArgumentException e) { 3930 Slog.w(TAG, "Error unbinding wallpaper when detaching", e); 3931 } 3932 wallpaper.connection = null; 3933 if (wallpaper == mLastWallpaper) { 3934 mLastWallpaper = null; 3935 } 3936 if (wallpaper == mLastLockWallpaper) { 3937 mLastLockWallpaper = null; 3938 } 3939 } 3940 } 3941 3942 // Updates the given wallpaper's Engine so that its destination flags are the same as those of 3943 // the wallpaper, e.g., after a wallpaper has been changed from displaying on home+lock to home 3944 // or lock only. updateEngineFlags(WallpaperData wallpaper)3945 private void updateEngineFlags(WallpaperData wallpaper) { 3946 if (wallpaper.connection == null) { 3947 return; 3948 } 3949 wallpaper.connection.forEachDisplayConnector( 3950 connector -> { 3951 try { 3952 connector.mWhich = wallpaper.mWhich; 3953 if (connector.mEngine != null) { 3954 connector.mEngine.setWallpaperFlags(wallpaper.mWhich); 3955 mWindowManagerInternal.setWallpaperShowWhenLocked( 3956 connector.mToken, (wallpaper.mWhich & FLAG_LOCK) != 0); 3957 } 3958 } catch (RemoteException e) { 3959 Slog.e(TAG, "Failed to update wallpaper engine flags", e); 3960 } 3961 }); 3962 } 3963 attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper)3964 private void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) { 3965 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 3966 t.traceBegin("WPMS.attachServiceLocked"); 3967 conn.forEachDisplayConnector(connector-> connector.connectLocked(conn, wallpaper)); 3968 t.traceEnd(); 3969 } 3970 notifyCallbacksLocked(WallpaperData wallpaper)3971 private void notifyCallbacksLocked(WallpaperData wallpaper) { 3972 final int n = wallpaper.callbacks.beginBroadcast(); 3973 for (int i = 0; i < n; i++) { 3974 try { 3975 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged(); 3976 } catch (RemoteException e) { 3977 3978 // The RemoteCallbackList will take care of removing 3979 // the dead object for us. 3980 Slog.w(TAG, "Failed to notify callbacks about wallpaper changes", e); 3981 } 3982 } 3983 wallpaper.callbacks.finishBroadcast(); 3984 3985 if (!fixWallpaperChanged()) { 3986 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 3987 intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, 3988 wallpaper.fromForegroundApp); 3989 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId)); 3990 } 3991 } 3992 notifyWallpaperChanged(WallpaperData wallpaper)3993 private void notifyWallpaperChanged(WallpaperData wallpaper) { 3994 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 3995 intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, wallpaper.fromForegroundApp); 3996 intent.putExtra(WallpaperManager.EXTRA_WHICH_WALLPAPER_CHANGED, wallpaper.mWhich); 3997 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId)); 3998 } 3999 checkPermission(String permission)4000 private void checkPermission(String permission) { 4001 if (!hasPermission(permission)) { 4002 throw new SecurityException("Access denied to process: " + Binder.getCallingPid() 4003 + ", must have permission " + permission); 4004 } 4005 } 4006 packageBelongsToUid(String packageName, int uid)4007 private boolean packageBelongsToUid(String packageName, int uid) { 4008 int userId = UserHandle.getUserId(uid); 4009 int packageUid; 4010 try { 4011 packageUid = mContext.getPackageManager().getPackageUidAsUser( 4012 packageName, userId); 4013 } catch (PackageManager.NameNotFoundException e) { 4014 return false; 4015 } 4016 return packageUid == uid; 4017 } 4018 enforcePackageBelongsToUid(String packageName, int uid)4019 private void enforcePackageBelongsToUid(String packageName, int uid) { 4020 if (!packageBelongsToUid(packageName, uid)) { 4021 throw new IllegalArgumentException( 4022 "Invalid package or package does not belong to uid:" 4023 + uid); 4024 } 4025 } 4026 isFromForegroundApp(String callingPackage)4027 private boolean isFromForegroundApp(String callingPackage) { 4028 return Binder.withCleanCallingIdentity(() -> 4029 mActivityManager.getPackageImportance(callingPackage) == IMPORTANCE_FOREGROUND); 4030 } 4031 4032 /** Check that the caller is either system_server or systemui */ checkCallerIsSystemOrSystemUi()4033 private void checkCallerIsSystemOrSystemUi() { 4034 if (Binder.getCallingUid() != Process.myUid() && mContext.checkCallingPermission( 4035 android.Manifest.permission.STATUS_BAR_SERVICE) != PERMISSION_GRANTED) { 4036 throw new SecurityException("Access denied: only system processes can call this"); 4037 } 4038 } 4039 4040 /** 4041 * Certain user types do not support wallpapers (e.g. managed profiles). The check is 4042 * implemented through through the OP_WRITE_WALLPAPER AppOp. 4043 */ isWallpaperSupported(String callingPackage)4044 public boolean isWallpaperSupported(String callingPackage) { 4045 final int callingUid = Binder.getCallingUid(); 4046 enforcePackageBelongsToUid(callingPackage, callingUid); 4047 4048 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, callingUid, 4049 callingPackage) == AppOpsManager.MODE_ALLOWED; 4050 } 4051 4052 @Override isSetWallpaperAllowed(String callingPackage)4053 public boolean isSetWallpaperAllowed(String callingPackage) { 4054 final PackageManager pm = mContext.getPackageManager(); 4055 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid()); 4056 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage); 4057 if (!uidMatchPackage) { 4058 return false; // callingPackage was faked. 4059 } 4060 final DevicePolicyManagerInternal dpmi = 4061 LocalServices.getService(DevicePolicyManagerInternal.class); 4062 if (dpmi != null && dpmi.isDeviceOrProfileOwnerInCallingUser(callingPackage)) { 4063 return true; 4064 } 4065 final int callingUserId = UserHandle.getCallingUserId(); 4066 final long ident = Binder.clearCallingIdentity(); 4067 try { 4068 UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 4069 return !umi.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER, callingUserId); 4070 } finally { 4071 Binder.restoreCallingIdentity(ident); 4072 } 4073 } 4074 4075 @Override isWallpaperBackupEligible(int which, int userId)4076 public boolean isWallpaperBackupEligible(int which, int userId) { 4077 WallpaperData wallpaper = (which == FLAG_LOCK) 4078 ? mLockWallpaperMap.get(userId) 4079 : mWallpaperMap.get(userId); 4080 return (wallpaper != null) ? wallpaper.allowBackup : false; 4081 } 4082 onDisplayAddSystemDecorationsInternal(int displayId)4083 private void onDisplayAddSystemDecorationsInternal(int displayId) { 4084 synchronized (mLock) { 4085 if (mLastWallpaper == null) { 4086 return; 4087 } 4088 int useFallbackWallpaperWhich = 0; 4089 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { 4090 List<WallpaperData> wallpapers = new ArrayList<>(); 4091 wallpapers.add(mLastWallpaper); 4092 // If the system and the lock wallpapers are not the same, we should also 4093 // establish a display connector to the lock wallpaper for this display. 4094 if (mLastLockWallpaper != null && mLastWallpaper != mLastLockWallpaper) { 4095 wallpapers.add(mLastLockWallpaper); 4096 } 4097 4098 for (int i = 0; i < wallpapers.size(); i++) { 4099 WallpaperData wallpaper = wallpapers.get(i); 4100 if (isWallpaperCompatibleForDisplay(displayId, wallpaper.connection)) { 4101 final DisplayConnector connector = 4102 wallpaper.connection.getDisplayConnectorOrCreate(displayId); 4103 if (connector != null) { 4104 connector.connectLocked(wallpaper.connection, wallpaper); 4105 } else { 4106 Slog.w(TAG, "Fail to connect to wallpaper for display id " + displayId 4107 + " due to null connector. Use fallback wallpaper."); 4108 useFallbackWallpaperWhich |= wallpaper.mWhich; 4109 } 4110 } else { 4111 useFallbackWallpaperWhich |= wallpaper.mWhich; 4112 } 4113 } 4114 4115 if (useFallbackWallpaperWhich == 0 4116 || mFallbackWallpaper == null 4117 || mFallbackWallpaper.connection == null) { 4118 return; 4119 } 4120 } else { 4121 if (isWallpaperCompatibleForDisplay(displayId, mLastWallpaper.connection)) { 4122 final DisplayConnector connector = 4123 mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId); 4124 if (connector == null) return; 4125 connector.connectLocked(mLastWallpaper.connection, mLastWallpaper); 4126 return; 4127 } 4128 } 4129 4130 // System wallpaper does not support multiple displays, attach this display to 4131 // the fallback wallpaper. 4132 if (mFallbackWallpaper != null && mFallbackWallpaper 4133 .connection != null) { 4134 final DisplayConnector connector = mFallbackWallpaper 4135 .connection.getDisplayConnectorOrCreate(displayId); 4136 if (connector == null) return; 4137 connector.mWhich = useFallbackWallpaperWhich; 4138 connector.connectLocked(mFallbackWallpaper.connection, mFallbackWallpaper); 4139 } else { 4140 Slog.w(TAG, "No wallpaper can be added to the new display"); 4141 } 4142 } 4143 } 4144 4145 // This method may be called even if the display is not being removed from the system. 4146 // This can be called when the display is removed, or when the display system decorations are 4147 // removed to start mirroring. onDisplayRemovedInternal(int displayId)4148 private void onDisplayRemovedInternal(int displayId) { 4149 synchronized (mLock) { 4150 if (isDeviceEligibleForDesktopExperienceWallpaper(mContext)) { 4151 // There could be at most 2 wallpaper connections per display: 4152 // 1. system & lock are the same: mLastWallpaper 4153 // 2. system, lock are different: mLastWallpaper, mLastLockWallpaper 4154 // 3. fallback used as both system & lock wallpaper: mFallbackWallpaper 4155 // 4. fallback used as lock only wallpaper: mFallbackWallpaper, 4156 // mLastWallpaper 4157 // 5. fallback used as system only wallpaper: mFallbackWallpaper, 4158 // mLastLockWallpaper 4159 List<WallpaperData> pendingDisconnectWallpapers = new ArrayList<>(); 4160 if (mLastWallpaper != null && mLastWallpaper.connection != null 4161 && mLastWallpaper.connection.containsDisplay(displayId)) { 4162 pendingDisconnectWallpapers.add(mLastWallpaper); 4163 } 4164 if (mLastLockWallpaper != null && mLastLockWallpaper.connection != null 4165 && mLastLockWallpaper.connection.containsDisplay(displayId)) { 4166 pendingDisconnectWallpapers.add(mLastLockWallpaper); 4167 } 4168 if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null 4169 && mFallbackWallpaper.connection.containsDisplay(displayId)) { 4170 pendingDisconnectWallpapers.add(mFallbackWallpaper); 4171 } 4172 for (int i = 0; i < pendingDisconnectWallpapers.size(); i++) { 4173 WallpaperData wallpaper = pendingDisconnectWallpapers.get(i); 4174 DisplayConnector displayConnector = 4175 wallpaper.connection.getDisplayConnectorOrCreate(displayId); 4176 if (displayConnector == null) { 4177 Slog.w(TAG, 4178 "Fail to disconnect wallpaper upon display removes system " 4179 + "decorations"); 4180 return; 4181 } 4182 displayConnector.disconnectLocked(wallpaper.connection); 4183 wallpaper.connection.removeDisplayConnector(displayId); 4184 } 4185 } else { 4186 if (mLastWallpaper != null) { 4187 WallpaperData targetWallpaper = null; 4188 if (mLastWallpaper.connection != null 4189 && mLastWallpaper.connection.containsDisplay(displayId)) { 4190 targetWallpaper = mLastWallpaper; 4191 } else if (mFallbackWallpaper != null 4192 && mFallbackWallpaper.connection != null 4193 && mFallbackWallpaper.connection.containsDisplay( 4194 displayId)) { 4195 targetWallpaper = mFallbackWallpaper; 4196 } 4197 if (targetWallpaper == null) return; 4198 DisplayConnector connector = 4199 targetWallpaper.connection.getDisplayConnectorOrCreate( 4200 displayId); 4201 if (connector == null) return; 4202 connector.disconnectLocked(targetWallpaper.connection); 4203 targetWallpaper.connection.removeDisplayConnector(displayId); 4204 } 4205 } 4206 4207 mWallpaperDisplayHelper.removeDisplayData(displayId); 4208 4209 for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) { 4210 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks = 4211 mColorsChangedListeners.valueAt(i); 4212 callbacks.delete(displayId); 4213 } 4214 } 4215 } 4216 saveSettingsLocked(int userId)4217 void saveSettingsLocked(int userId) { 4218 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 4219 t.traceBegin("WPMS.saveSettingsLocked-" + userId); 4220 mWallpaperDataParser.saveSettingsLocked( 4221 userId, mWallpaperMap.get(userId), mLockWallpaperMap.get(userId)); 4222 t.traceEnd(); 4223 } 4224 4225 /** 4226 * Determines and returns the current wallpaper for the given user and destination, creating 4227 * a valid entry if it does not already exist and adding it to the appropriate wallpaper map. 4228 * 4229 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could 4230 * happen during user switch. The async user switch observer may not have received 4231 * the event yet. We use this safe method when we don't care about this ordering and just 4232 * want to update the data. The data is going to be applied when the user switch observer 4233 * is eventually executed. 4234 * 4235 * Important: this method loads settings to initialize the given user's wallpaper data if 4236 * there is no current in-memory state. 4237 */ getWallpaperSafeLocked(int userId, int which)4238 WallpaperData getWallpaperSafeLocked(int userId, int which) { 4239 // We're setting either just system (work with the system wallpaper), 4240 // both (also work with the system wallpaper), or just the lock 4241 // wallpaper (update against the existing lock wallpaper if any). 4242 // Combined or just-system operations use the 'system' WallpaperData 4243 // for this use; lock-only operations use the dedicated one. 4244 final SparseArray<WallpaperData> whichSet = 4245 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap; 4246 WallpaperData wallpaper = whichSet.get(userId); 4247 if (wallpaper == null) { 4248 // common case, this is the first lookup post-boot of the system or 4249 // unified lock, so we bring up the saved state lazily now and recheck. 4250 // if we're loading the system wallpaper for the first time, also load the lock 4251 // wallpaper to determine if the system wallpaper is system+lock or system only. 4252 int whichLoad = (which == FLAG_LOCK) ? FLAG_LOCK : FLAG_SYSTEM | FLAG_LOCK; 4253 loadSettingsLocked(userId, false, whichLoad); 4254 wallpaper = whichSet.get(userId); 4255 if (wallpaper == null) { 4256 // if it's still null here, this is likely a lock-only operation and there is not 4257 // currently a lock-only wallpaper set for this user, so we need to establish 4258 // it now. 4259 if (which == FLAG_LOCK) { 4260 wallpaper = new WallpaperData(userId, FLAG_LOCK); 4261 mLockWallpaperMap.put(userId, wallpaper); 4262 } else { 4263 // rationality fallback: we're in bad shape, but establishing a known 4264 // valid system+lock WallpaperData will keep us from dying. 4265 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!"); 4266 wallpaper = new WallpaperData(userId, FLAG_SYSTEM); 4267 mWallpaperMap.put(userId, wallpaper); 4268 } 4269 } 4270 } 4271 return wallpaper; 4272 } 4273 loadSettingsLocked(int userId, boolean keepDimensionHints, int which)4274 private void loadSettingsLocked(int userId, boolean keepDimensionHints, int which) { 4275 initializeFallbackWallpaper(); 4276 boolean restoreFromOld = !mWallpaperMap.contains(userId); 4277 WallpaperDataParser.WallpaperLoadingResult result = mWallpaperDataParser.loadSettingsLocked( 4278 userId, keepDimensionHints, restoreFromOld, which); 4279 4280 boolean updateSystem = (which & FLAG_SYSTEM) != 0; 4281 boolean updateLock = (which & FLAG_LOCK) != 0; 4282 4283 if (updateSystem) mWallpaperMap.put(userId, result.getSystemWallpaperData()); 4284 if (updateLock) { 4285 if (result.success()) { 4286 mLockWallpaperMap.put(userId, result.getLockWallpaperData()); 4287 } else { 4288 mLockWallpaperMap.remove(userId); 4289 } 4290 } 4291 } 4292 initializeFallbackWallpaper()4293 private void initializeFallbackWallpaper() { 4294 if (mFallbackWallpaper == null) { 4295 if (DEBUG) Slog.d(TAG, "Initialize fallback wallpaper"); 4296 final int systemUserId = UserHandle.USER_SYSTEM; 4297 mFallbackWallpaper = new WallpaperData(systemUserId, FLAG_SYSTEM); 4298 mFallbackWallpaper.allowBackup = false; 4299 mFallbackWallpaper.wallpaperId = makeWallpaperIdLocked(); 4300 mFallbackWallpaper.mBindSource = BindSource.INITIALIZE_FALLBACK; 4301 if (mFallbackWallpaperComponent == null) { 4302 bindWallpaperComponentLocked(mDefaultWallpaperComponent, true, false, 4303 mFallbackWallpaper, null); 4304 } else { 4305 mFallbackWallpaper.mWhich = FLAG_SYSTEM | FLAG_LOCK; 4306 bindWallpaperComponentLocked(mFallbackWallpaperComponent, true, false, 4307 mFallbackWallpaper, null); 4308 } 4309 } 4310 } 4311 4312 // Called by SystemBackupAgent after files are restored to disk. 4313 // TODO(b/373875373) Remove this method settingsRestored()4314 public void settingsRestored() { 4315 // Verify caller is the system 4316 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 4317 throw new RuntimeException("settingsRestored() can only be called from the system process"); 4318 } 4319 // TODO: If necessary, make it work for secondary users as well. This currently assumes 4320 // restores only to the primary user 4321 if (DEBUG) Slog.v(TAG, "settingsRestored"); 4322 WallpaperData wallpaper = null; 4323 boolean success = false; 4324 synchronized (mLock) { 4325 loadSettingsLocked(UserHandle.USER_SYSTEM, false, FLAG_SYSTEM | FLAG_LOCK); 4326 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM); 4327 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore 4328 wallpaper.allowBackup = true; // by definition if it was restored 4329 ComponentName componentName = 4330 removeNextWallpaperComponent() ? wallpaper.getComponent() 4331 : wallpaper.nextWallpaperComponent; 4332 4333 if (liveWallpaperContentHandling()) { 4334 // Per b/373875373 this method should be removed, so we just set wallpapers to 4335 // default. 4336 bindWallpaperDescriptionLocked(new WallpaperDescription.Builder().build(), false, 4337 false, wallpaper, null); 4338 return; 4339 } 4340 if (componentName != null && !componentName.equals(mImageWallpaper)) { 4341 wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_LIVE_SUCCESS; 4342 if (!bindWallpaperComponentLocked(componentName, false, false, 4343 wallpaper, null)) { 4344 // No such live wallpaper or other failure; fall back to the default 4345 // live wallpaper (since the profile being restored indicated that the 4346 // user had selected a live rather than static one). 4347 wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_LIVE_FAILURE; 4348 bindWallpaperComponentLocked(null, false, false, wallpaper, null); 4349 } 4350 success = true; 4351 } else { 4352 // If there's a wallpaper name, we use that. If that can't be loaded, then we 4353 // use the default. 4354 if ("".equals(wallpaper.name)) { 4355 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty"); 4356 success = true; 4357 } else { 4358 if (DEBUG) { 4359 Slog.v(TAG, "settingsRestored: attempting to restore named resource"); 4360 } 4361 success = mWallpaperDataParser.restoreNamedResourceLocked(wallpaper); 4362 } 4363 if (DEBUG) { 4364 Slog.v(TAG, "settingsRestored: success=" + success + " id=" 4365 + wallpaper.wallpaperId); 4366 } 4367 if (success) { 4368 mWallpaperCropper.generateCrop( 4369 wallpaper); // based on the new image + metadata 4370 wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_STATIC; 4371 bindWallpaperComponentLocked(null, true, false, wallpaper, null); 4372 } 4373 } 4374 } 4375 4376 if (!success) { 4377 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'"); 4378 wallpaper.name = ""; 4379 getWallpaperDir(UserHandle.USER_SYSTEM).delete(); 4380 } 4381 4382 synchronized (mLock) { 4383 saveSettingsLocked(UserHandle.USER_SYSTEM); 4384 } 4385 } 4386 4387 @Override // Binder call onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)4388 public void onShellCommand(FileDescriptor in, FileDescriptor out, 4389 FileDescriptor err, String[] args, ShellCallback callback, 4390 ResultReceiver resultReceiver) { 4391 new WallpaperManagerShellCommand(WallpaperManagerService.this).exec(this, in, out, err, 4392 args, callback, resultReceiver); 4393 } 4394 dumpWallpaper(WallpaperData wallpaper, PrintWriter pw)4395 private void dumpWallpaper(WallpaperData wallpaper, PrintWriter pw) { 4396 if (wallpaper == null) { 4397 pw.println(" (null entry)"); 4398 return; 4399 } 4400 pw.print(" User "); pw.print(wallpaper.userId); 4401 pw.print(": id="); pw.print(wallpaper.wallpaperId); 4402 pw.print(": mWhich="); pw.print(wallpaper.mWhich); 4403 pw.print(": mSystemWasBoth="); pw.print(wallpaper.mSystemWasBoth); 4404 pw.print(": mBindSource="); pw.println(wallpaper.mBindSource.name()); 4405 pw.println(" Display state:"); 4406 mWallpaperDisplayHelper.forEachDisplayData(wpSize -> { 4407 pw.print(" displayId="); 4408 pw.println(wpSize.mDisplayId); 4409 pw.print(" mWidth="); 4410 pw.print(wpSize.mWidth); 4411 pw.print(" mHeight="); 4412 pw.println(wpSize.mHeight); 4413 pw.print(" mPadding="); pw.println(wpSize.mPadding); 4414 }); 4415 pw.print(" mCropHint="); pw.println(wallpaper.cropHint); 4416 if (multiCrop()) pw.print(" mCropHints="); pw.println(wallpaper.mCropHints); 4417 pw.print(" mName="); pw.println(wallpaper.name); 4418 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup); 4419 pw.print(" mWallpaperComponent="); pw.println(wallpaper.getComponent()); 4420 pw.print(" mWallpaperDimAmount="); pw.println(wallpaper.mWallpaperDimAmount); 4421 pw.print(" isColorExtracted="); pw.println(wallpaper.mIsColorExtractedFromDim); 4422 pw.println(" mUidToDimAmount:"); 4423 for (int j = 0; j < wallpaper.mUidToDimAmount.size(); j++) { 4424 pw.print(" UID="); pw.print(wallpaper.mUidToDimAmount.keyAt(j)); 4425 pw.print(" dimAmount="); pw.println(wallpaper.mUidToDimAmount.valueAt(j)); 4426 } 4427 if (wallpaper.connection != null) { 4428 WallpaperConnection conn = wallpaper.connection; 4429 pw.print(" Wallpaper connection "); 4430 pw.print(conn); 4431 pw.println(":"); 4432 if (conn.mInfo != null) { 4433 pw.print(" mInfo.component="); 4434 pw.println(conn.mInfo.getComponent()); 4435 } 4436 conn.forEachDisplayConnector(connector -> { 4437 pw.print(" mDisplayId="); 4438 pw.println(connector.mDisplayId); 4439 pw.print(" mToken="); 4440 pw.println(connector.mToken); 4441 pw.print(" mEngine="); 4442 pw.println(connector.mEngine); 4443 }); 4444 pw.print(" mService="); 4445 pw.println(conn.mService); 4446 pw.print(" mLastDiedTime="); 4447 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis()); 4448 } 4449 } 4450 4451 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)4452 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4453 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 4454 4455 pw.print("mDefaultWallpaperComponent="); pw.println(mDefaultWallpaperComponent); 4456 pw.print("mImageWallpaper="); pw.println(mImageWallpaper); 4457 4458 synchronized (mLock) { 4459 pw.println("System wallpaper state:"); 4460 for (int i = 0; i < mWallpaperMap.size(); i++) { 4461 dumpWallpaper(mWallpaperMap.valueAt(i), pw); 4462 } 4463 pw.println("Lock wallpaper state:"); 4464 for (int i = 0; i < mLockWallpaperMap.size(); i++) { 4465 dumpWallpaper(mLockWallpaperMap.valueAt(i), pw); 4466 } 4467 pw.println("Fallback wallpaper state:"); 4468 if (mFallbackWallpaper != null) { 4469 dumpWallpaper(mFallbackWallpaper, pw); 4470 } 4471 } 4472 } 4473 } 4474