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