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.app.WallpaperManager.COMMAND_REAPPLY; 20 import static android.app.WallpaperManager.FLAG_LOCK; 21 import static android.app.WallpaperManager.FLAG_SYSTEM; 22 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; 23 import static android.os.ParcelFileDescriptor.MODE_CREATE; 24 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; 25 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; 26 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; 27 import static android.view.Display.DEFAULT_DISPLAY; 28 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 29 30 import android.annotation.NonNull; 31 import android.app.ActivityManager; 32 import android.app.AppGlobals; 33 import android.app.AppOpsManager; 34 import android.app.IWallpaperManager; 35 import android.app.IWallpaperManagerCallback; 36 import android.app.PendingIntent; 37 import android.app.UserSwitchObserver; 38 import android.app.WallpaperColors; 39 import android.app.WallpaperInfo; 40 import android.app.WallpaperManager; 41 import android.app.WallpaperManager.SetWallpaperFlags; 42 import android.app.admin.DevicePolicyManagerInternal; 43 import android.app.backup.WallpaperBackupHelper; 44 import android.content.BroadcastReceiver; 45 import android.content.ComponentName; 46 import android.content.Context; 47 import android.content.Intent; 48 import android.content.IntentFilter; 49 import android.content.ServiceConnection; 50 import android.content.pm.IPackageManager; 51 import android.content.pm.PackageManager; 52 import android.content.pm.PackageManager.NameNotFoundException; 53 import android.content.pm.ResolveInfo; 54 import android.content.pm.ServiceInfo; 55 import android.content.pm.UserInfo; 56 import android.content.res.Resources; 57 import android.graphics.Bitmap; 58 import android.graphics.BitmapFactory; 59 import android.graphics.BitmapRegionDecoder; 60 import android.graphics.Color; 61 import android.graphics.Rect; 62 import android.hardware.display.DisplayManager; 63 import android.os.Binder; 64 import android.os.Bundle; 65 import android.os.Debug; 66 import android.os.Environment; 67 import android.os.FileObserver; 68 import android.os.FileUtils; 69 import android.os.Handler; 70 import android.os.IBinder; 71 import android.os.IInterface; 72 import android.os.IRemoteCallback; 73 import android.os.ParcelFileDescriptor; 74 import android.os.Process; 75 import android.os.RemoteCallbackList; 76 import android.os.RemoteException; 77 import android.os.SELinux; 78 import android.os.SystemClock; 79 import android.os.UserHandle; 80 import android.os.UserManager; 81 import android.os.UserManagerInternal; 82 import android.os.storage.StorageManager; 83 import android.service.wallpaper.IWallpaperConnection; 84 import android.service.wallpaper.IWallpaperEngine; 85 import android.service.wallpaper.IWallpaperService; 86 import android.service.wallpaper.WallpaperService; 87 import android.system.ErrnoException; 88 import android.system.Os; 89 import android.util.EventLog; 90 import android.util.Slog; 91 import android.util.SparseArray; 92 import android.util.SparseBooleanArray; 93 import android.util.Xml; 94 import android.view.Display; 95 import android.view.DisplayInfo; 96 97 import com.android.internal.R; 98 import com.android.internal.annotations.VisibleForTesting; 99 import com.android.internal.content.PackageMonitor; 100 import com.android.internal.os.BackgroundThread; 101 import com.android.internal.util.DumpUtils; 102 import com.android.internal.util.FastXmlSerializer; 103 import com.android.internal.util.JournaledFile; 104 import com.android.server.EventLogTags; 105 import com.android.server.FgThread; 106 import com.android.server.LocalServices; 107 import com.android.server.SystemService; 108 import com.android.server.utils.TimingsTraceAndSlog; 109 import com.android.server.wm.WindowManagerInternal; 110 111 import libcore.io.IoUtils; 112 113 import org.xmlpull.v1.XmlPullParser; 114 import org.xmlpull.v1.XmlPullParserException; 115 import org.xmlpull.v1.XmlSerializer; 116 117 import java.io.BufferedOutputStream; 118 import java.io.File; 119 import java.io.FileDescriptor; 120 import java.io.FileInputStream; 121 import java.io.FileNotFoundException; 122 import java.io.FileOutputStream; 123 import java.io.IOException; 124 import java.io.InputStream; 125 import java.io.PrintWriter; 126 import java.nio.charset.StandardCharsets; 127 import java.util.ArrayList; 128 import java.util.Arrays; 129 import java.util.List; 130 import java.util.Objects; 131 import java.util.function.Consumer; 132 import java.util.function.Predicate; 133 134 public class WallpaperManagerService extends IWallpaperManager.Stub 135 implements IWallpaperManagerService { 136 private static final String TAG = "WallpaperManagerService"; 137 private static final boolean DEBUG = false; 138 private static final boolean DEBUG_LIVE = true; 139 140 // This 100MB limitation is defined in RecordingCanvas. 141 private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; 142 143 public static class Lifecycle extends SystemService { 144 private IWallpaperManagerService mService; 145 Lifecycle(Context context)146 public Lifecycle(Context context) { 147 super(context); 148 } 149 150 @Override onStart()151 public void onStart() { 152 try { 153 final Class<? extends IWallpaperManagerService> klass = 154 (Class<? extends IWallpaperManagerService>)Class.forName( 155 getContext().getResources().getString( 156 R.string.config_wallpaperManagerServiceName)); 157 mService = klass.getConstructor(Context.class).newInstance(getContext()); 158 publishBinderService(Context.WALLPAPER_SERVICE, mService); 159 } catch (Exception exp) { 160 Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp); 161 } 162 } 163 164 @Override onBootPhase(int phase)165 public void onBootPhase(int phase) { 166 if (mService != null) { 167 mService.onBootPhase(phase); 168 } 169 } 170 171 @Override onUnlockUser(int userHandle)172 public void onUnlockUser(int userHandle) { 173 if (mService != null) { 174 mService.onUnlockUser(userHandle); 175 } 176 } 177 } 178 179 private final Object mLock = new Object(); 180 181 /** 182 * Minimum time between crashes of a wallpaper service for us to consider 183 * restarting it vs. just reverting to the static wallpaper. 184 */ 185 private static final long MIN_WALLPAPER_CRASH_TIME = 10000; 186 private static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128; 187 static final String WALLPAPER = "wallpaper_orig"; 188 static final String WALLPAPER_CROP = "wallpaper"; 189 static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig"; 190 static final String WALLPAPER_LOCK_CROP = "wallpaper_lock"; 191 static final String WALLPAPER_INFO = "wallpaper_info.xml"; 192 193 // All the various per-user state files we need to be aware of 194 private static final String[] sPerUserFiles = new String[] { 195 WALLPAPER, WALLPAPER_CROP, 196 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP, 197 WALLPAPER_INFO 198 }; 199 200 /** 201 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks 202 * that the wallpaper has changed. The CREATE is triggered when there is no 203 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered 204 * every time the wallpaper is changed. 205 */ 206 private class WallpaperObserver extends FileObserver { 207 208 final int mUserId; 209 final WallpaperData mWallpaper; 210 final File mWallpaperDir; 211 final File mWallpaperFile; 212 final File mWallpaperLockFile; 213 WallpaperObserver(WallpaperData wallpaper)214 public WallpaperObserver(WallpaperData wallpaper) { 215 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(), 216 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF); 217 mUserId = wallpaper.userId; 218 mWallpaperDir = getWallpaperDir(wallpaper.userId); 219 mWallpaper = wallpaper; 220 mWallpaperFile = new File(mWallpaperDir, WALLPAPER); 221 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG); 222 } 223 dataForEvent(boolean sysChanged, boolean lockChanged)224 private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) { 225 WallpaperData wallpaper = null; 226 synchronized (mLock) { 227 if (lockChanged) { 228 wallpaper = mLockWallpaperMap.get(mUserId); 229 } 230 if (wallpaper == null) { 231 // no lock-specific wallpaper exists, or sys case, handled together 232 wallpaper = mWallpaperMap.get(mUserId); 233 } 234 } 235 return (wallpaper != null) ? wallpaper : mWallpaper; 236 } 237 238 @Override onEvent(int event, String path)239 public void onEvent(int event, String path) { 240 if (path == null) { 241 return; 242 } 243 final boolean moved = (event == MOVED_TO); 244 final boolean written = (event == CLOSE_WRITE || moved); 245 final File changedFile = new File(mWallpaperDir, path); 246 247 // System and system+lock changes happen on the system wallpaper input file; 248 // lock-only changes happen on the dedicated lock wallpaper input file 249 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile)); 250 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile)); 251 int notifyColorsWhich = 0; 252 WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged); 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 + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending) 261 + " written=" + written); 262 } 263 264 if (moved && lockWallpaperChanged) { 265 // We just migrated sys -> lock to preserve imagery for an impending 266 // new system-only wallpaper. Tell keyguard about it and make sure it 267 // has the right SELinux label. 268 if (DEBUG) { 269 Slog.i(TAG, "Sys -> lock MOVED_TO"); 270 } 271 SELinux.restorecon(changedFile); 272 notifyLockWallpaperChanged(); 273 notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK); 274 return; 275 } 276 277 synchronized (mLock) { 278 if (sysWallpaperChanged || lockWallpaperChanged) { 279 notifyCallbacksLocked(wallpaper); 280 if (wallpaper.wallpaperComponent == null 281 || event != CLOSE_WRITE // includes the MOVED_TO case 282 || wallpaper.imageWallpaperPending) { 283 if (written) { 284 // The image source has finished writing the source image, 285 // so we now produce the crop rect (in the background), and 286 // only publish the new displayable (sub)image as a result 287 // of that work. 288 if (DEBUG) { 289 Slog.v(TAG, "Wallpaper written; generating crop"); 290 } 291 SELinux.restorecon(changedFile); 292 if (moved) { 293 // This is a restore, so generate the crop using any just-restored new 294 // crop guidelines, making sure to preserve our local dimension hints. 295 // We also make sure to reapply the correct SELinux label. 296 if (DEBUG) { 297 Slog.v(TAG, "moved-to, therefore restore; reloading metadata"); 298 } 299 loadSettingsLocked(wallpaper.userId, true); 300 } 301 generateCrop(wallpaper); 302 if (DEBUG) { 303 Slog.v(TAG, "Crop done; invoking completion callback"); 304 } 305 wallpaper.imageWallpaperPending = false; 306 if (sysWallpaperChanged) { 307 // If this was the system wallpaper, rebind... 308 bindWallpaperComponentLocked(mImageWallpaper, true, 309 false, wallpaper, null); 310 notifyColorsWhich |= FLAG_SYSTEM; 311 } 312 if (lockWallpaperChanged 313 || (wallpaper.whichPending & FLAG_LOCK) != 0) { 314 if (DEBUG) { 315 Slog.i(TAG, "Lock-relevant wallpaper changed"); 316 } 317 // either a lock-only wallpaper commit or a system+lock event. 318 // if it's system-plus-lock we need to wipe the lock bookkeeping; 319 // we're falling back to displaying the system wallpaper there. 320 if (!lockWallpaperChanged) { 321 mLockWallpaperMap.remove(wallpaper.userId); 322 } 323 // and in any case, tell keyguard about it 324 notifyLockWallpaperChanged(); 325 notifyColorsWhich |= FLAG_LOCK; 326 } 327 328 saveSettingsLocked(wallpaper.userId); 329 330 // Publish completion *after* we've persisted the changes 331 if (wallpaper.setComplete != null) { 332 try { 333 wallpaper.setComplete.onWallpaperChanged(); 334 } catch (RemoteException e) { 335 // if this fails we don't really care; the setting app may just 336 // have crashed and that sort of thing is a fact of life. 337 } 338 } 339 } 340 } 341 } 342 } 343 344 // Outside of the lock since it will synchronize itself 345 if (notifyColorsWhich != 0) { 346 notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich); 347 } 348 } 349 } 350 notifyLockWallpaperChanged()351 private void notifyLockWallpaperChanged() { 352 final IWallpaperManagerCallback cb = mKeyguardListener; 353 if (cb != null) { 354 try { 355 cb.onWallpaperChanged(); 356 } catch (RemoteException e) { 357 // Oh well it went away; no big deal 358 } 359 } 360 } 361 notifyWallpaperColorsChanged(@onNull WallpaperData wallpaper, int which)362 private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) { 363 if (wallpaper.connection != null) { 364 wallpaper.connection.forEachDisplayConnector(connector -> { 365 notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId); 366 }); 367 } else { // Lock wallpaper does not have WallpaperConnection. 368 notifyWallpaperColorsChangedOnDisplay(wallpaper, which, DEFAULT_DISPLAY); 369 } 370 } 371 getWallpaperCallbacks(int userId, int displayId)372 private RemoteCallbackList<IWallpaperManagerCallback> getWallpaperCallbacks(int userId, 373 int displayId) { 374 RemoteCallbackList<IWallpaperManagerCallback> listeners = null; 375 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> displayListeners = 376 mColorsChangedListeners.get(userId); 377 if (displayListeners != null) { 378 listeners = displayListeners.get(displayId); 379 } 380 return listeners; 381 } 382 notifyWallpaperColorsChangedOnDisplay(@onNull WallpaperData wallpaper, int which, int displayId)383 private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, int which, 384 int displayId) { 385 boolean needsExtraction; 386 synchronized (mLock) { 387 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners = 388 getWallpaperCallbacks(wallpaper.userId, displayId); 389 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners = 390 getWallpaperCallbacks(UserHandle.USER_ALL, displayId); 391 // No-op until someone is listening to it. 392 if (emptyCallbackList(currentUserColorListeners) && 393 emptyCallbackList(userAllColorListeners)) { 394 return; 395 } 396 397 if (DEBUG) { 398 Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + which); 399 } 400 401 needsExtraction = wallpaper.primaryColors == null; 402 } 403 404 // Let's notify the current values, it's fine if it's null, it just means 405 // that we don't know yet. 406 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId); 407 408 if (needsExtraction) { 409 extractColors(wallpaper); 410 synchronized (mLock) { 411 // Don't need to notify if nothing changed. 412 if (wallpaper.primaryColors == null) { 413 return; 414 } 415 } 416 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId); 417 } 418 } 419 emptyCallbackList(RemoteCallbackList<T> list)420 private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) { 421 return (list == null || list.getRegisteredCallbackCount() == 0); 422 } 423 notifyColorListeners(@onNull WallpaperColors wallpaperColors, int which, int userId, int displayId)424 private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which, 425 int userId, int displayId) { 426 final IWallpaperManagerCallback keyguardListener; 427 final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>(); 428 synchronized (mLock) { 429 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners = 430 getWallpaperCallbacks(userId, displayId); 431 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners = 432 getWallpaperCallbacks(UserHandle.USER_ALL, displayId); 433 keyguardListener = mKeyguardListener; 434 435 if (currentUserColorListeners != null) { 436 final int count = currentUserColorListeners.beginBroadcast(); 437 for (int i = 0; i < count; i++) { 438 colorListeners.add(currentUserColorListeners.getBroadcastItem(i)); 439 } 440 currentUserColorListeners.finishBroadcast(); 441 } 442 443 if (userAllColorListeners != null) { 444 final int count = userAllColorListeners.beginBroadcast(); 445 for (int i = 0; i < count; i++) { 446 colorListeners.add(userAllColorListeners.getBroadcastItem(i)); 447 } 448 userAllColorListeners.finishBroadcast(); 449 } 450 } 451 452 final int count = colorListeners.size(); 453 for (int i = 0; i < count; i++) { 454 try { 455 colorListeners.get(i).onWallpaperColorsChanged(wallpaperColors, which, userId); 456 } catch (RemoteException e) { 457 // Callback is gone, it's not necessary to unregister it since 458 // RemoteCallbackList#getBroadcastItem will take care of it. 459 } 460 } 461 462 // Only shows Keyguard on default display 463 if (keyguardListener != null && displayId == DEFAULT_DISPLAY) { 464 try { 465 keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId); 466 } catch (RemoteException e) { 467 // Oh well it went away; no big deal 468 } 469 } 470 } 471 472 /** 473 * We can easily extract colors from an ImageWallpaper since it's only a bitmap. 474 * In this case, using the crop is more than enough. Live wallpapers are just ignored. 475 * 476 * @param wallpaper a wallpaper representation 477 */ extractColors(WallpaperData wallpaper)478 private void extractColors(WallpaperData wallpaper) { 479 String cropFile = null; 480 boolean defaultImageWallpaper = false; 481 int wallpaperId; 482 483 if (wallpaper.equals(mFallbackWallpaper)) { 484 synchronized (mLock) { 485 if (mFallbackWallpaper.primaryColors != null) return; 486 } 487 final WallpaperColors colors = extractDefaultImageWallpaperColors(); 488 synchronized (mLock) { 489 mFallbackWallpaper.primaryColors = colors; 490 } 491 return; 492 } 493 494 synchronized (mLock) { 495 // Not having a wallpaperComponent means it's a lock screen wallpaper. 496 final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent) 497 || wallpaper.wallpaperComponent == null; 498 if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) { 499 cropFile = wallpaper.cropFile.getAbsolutePath(); 500 } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) { 501 defaultImageWallpaper = true; 502 } 503 wallpaperId = wallpaper.wallpaperId; 504 } 505 506 WallpaperColors colors = null; 507 if (cropFile != null) { 508 Bitmap bitmap = BitmapFactory.decodeFile(cropFile); 509 if (bitmap != null) { 510 colors = WallpaperColors.fromBitmap(bitmap); 511 bitmap.recycle(); 512 } 513 } else if (defaultImageWallpaper) { 514 // There is no crop and source file because this is default image wallpaper. 515 colors = extractDefaultImageWallpaperColors(); 516 } 517 518 if (colors == null) { 519 Slog.w(TAG, "Cannot extract colors because wallpaper could not be read."); 520 return; 521 } 522 523 synchronized (mLock) { 524 if (wallpaper.wallpaperId == wallpaperId) { 525 wallpaper.primaryColors = colors; 526 // Now that we have the colors, let's save them into the xml 527 // to avoid having to run this again. 528 saveSettingsLocked(wallpaper.userId); 529 } else { 530 Slog.w(TAG, "Not setting primary colors since wallpaper changed"); 531 } 532 } 533 } 534 extractDefaultImageWallpaperColors()535 private WallpaperColors extractDefaultImageWallpaperColors() { 536 if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors"); 537 538 synchronized (mLock) { 539 if (mCacheDefaultImageWallpaperColors != null) return mCacheDefaultImageWallpaperColors; 540 } 541 542 WallpaperColors colors = null; 543 try (InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) { 544 if (is == null) { 545 Slog.w(TAG, "Can't open default wallpaper stream"); 546 return null; 547 } 548 549 final BitmapFactory.Options options = new BitmapFactory.Options(); 550 final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); 551 if (bitmap != null) { 552 colors = WallpaperColors.fromBitmap(bitmap); 553 bitmap.recycle(); 554 } 555 } catch (OutOfMemoryError e) { 556 Slog.w(TAG, "Can't decode default wallpaper stream", e); 557 } catch (IOException e) { 558 Slog.w(TAG, "Can't close default wallpaper stream", e); 559 } 560 561 if (colors == null) { 562 Slog.e(TAG, "Extract default image wallpaper colors failed"); 563 } else { 564 synchronized (mLock) { 565 mCacheDefaultImageWallpaperColors = colors; 566 } 567 } 568 569 return colors; 570 } 571 572 /** 573 * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped 574 * for display. 575 */ generateCrop(WallpaperData wallpaper)576 private void generateCrop(WallpaperData wallpaper) { 577 boolean success = false; 578 579 // Only generate crop for default display. 580 final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY); 581 final Rect cropHint = new Rect(wallpaper.cropHint); 582 final DisplayInfo displayInfo = new DisplayInfo(); 583 mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); 584 585 if (DEBUG) { 586 Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" 587 + Integer.toHexString(wallpaper.whichPending) 588 + " to " + wallpaper.cropFile.getName() 589 + " crop=(" + cropHint.width() + 'x' + cropHint.height() 590 + ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')'); 591 } 592 593 // Analyse the source; needed in multiple cases 594 BitmapFactory.Options options = new BitmapFactory.Options(); 595 options.inJustDecodeBounds = true; 596 BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options); 597 if (options.outWidth <= 0 || options.outHeight <= 0) { 598 Slog.w(TAG, "Invalid wallpaper data"); 599 success = false; 600 } else { 601 boolean needCrop = false; 602 boolean needScale = false; 603 604 // Empty crop means use the full image 605 if (cropHint.isEmpty()) { 606 cropHint.left = cropHint.top = 0; 607 cropHint.right = options.outWidth; 608 cropHint.bottom = options.outHeight; 609 } else { 610 // force the crop rect to lie within the measured bounds 611 cropHint.offset( 612 (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0), 613 (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0)); 614 615 // If the crop hint was larger than the image we just overshot. Patch things up. 616 if (cropHint.left < 0) { 617 cropHint.left = 0; 618 } 619 if (cropHint.top < 0) { 620 cropHint.top = 0; 621 } 622 623 // Don't bother cropping if what we're left with is identity 624 needCrop = (options.outHeight > cropHint.height() 625 || options.outWidth > cropHint.width()); 626 } 627 628 // scale if the crop height winds up not matching the recommended metrics 629 needScale = wpData.mHeight != cropHint.height() 630 || cropHint.height() > GLHelper.getMaxTextureSize() 631 || cropHint.width() > GLHelper.getMaxTextureSize(); 632 633 //make sure screen aspect ratio is preserved if width is scaled under screen size 634 if (needScale) { 635 final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); 636 final int newWidth = (int) (cropHint.width() * scaleByHeight); 637 if (newWidth < displayInfo.logicalWidth) { 638 final float screenAspectRatio = 639 (float) displayInfo.logicalHeight / (float) displayInfo.logicalWidth; 640 cropHint.bottom = (int) (cropHint.width() * screenAspectRatio); 641 needCrop = true; 642 } 643 } 644 645 if (DEBUG) { 646 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); 647 Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); 648 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight); 649 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale); 650 } 651 652 if (!needCrop && !needScale) { 653 // Simple case: the nominal crop fits what we want, so we take 654 // the whole thing and just copy the image file directly. 655 656 // TODO: It is not accurate to estimate bitmap size without decoding it, 657 // may be we can try to remove this optimized way in the future, 658 // that means, we will always go into the 'else' block. 659 660 // This is just a quick estimation, may be smaller than it is. 661 long estimateSize = options.outWidth * options.outHeight * 4; 662 663 // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. 664 // Please see: RecordingCanvas#throwIfCannotDraw. 665 if (estimateSize < MAX_BITMAP_SIZE) { 666 success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); 667 } 668 669 if (!success) { 670 wallpaper.cropFile.delete(); 671 // TODO: fall back to default wallpaper in this case 672 } 673 674 if (DEBUG) { 675 Slog.v(TAG, "Null crop of new wallpaper, estimate size=" 676 + estimateSize + ", success=" + success); 677 } 678 } else { 679 // Fancy case: crop and scale. First, we decode and scale down if appropriate. 680 FileOutputStream f = null; 681 BufferedOutputStream bos = null; 682 try { 683 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance( 684 wallpaper.wallpaperFile.getAbsolutePath(), false); 685 686 // This actually downsamples only by powers of two, but that's okay; we do 687 // a proper scaling blit later. This is to minimize transient RAM use. 688 // We calculate the largest power-of-two under the actual ratio rather than 689 // just let the decode take care of it because we also want to remap where the 690 // cropHint rectangle lies in the decoded [super]rect. 691 final int actualScale = cropHint.height() / wpData.mHeight; 692 int scale = 1; 693 while (2 * scale <= actualScale) { 694 scale *= 2; 695 } 696 options.inSampleSize = scale; 697 options.inJustDecodeBounds = false; 698 699 final Rect estimateCrop = new Rect(cropHint); 700 estimateCrop.scale(1f / options.inSampleSize); 701 final float hRatio = (float) wpData.mHeight / estimateCrop.height(); 702 final int destHeight = (int) (estimateCrop.height() * hRatio); 703 final int destWidth = (int) (estimateCrop.width() * hRatio); 704 705 // We estimated an invalid crop, try to adjust the cropHint to get a valid one. 706 if (destWidth > GLHelper.getMaxTextureSize()) { 707 int newHeight = (int) (wpData.mHeight / hRatio); 708 int newWidth = (int) (wpData.mWidth / hRatio); 709 710 if (DEBUG) { 711 Slog.v(TAG, "Invalid crop dimensions, trying to adjust."); 712 } 713 714 estimateCrop.set(cropHint); 715 estimateCrop.left += (cropHint.width() - newWidth) / 2; 716 estimateCrop.top += (cropHint.height() - newHeight) / 2; 717 estimateCrop.right = estimateCrop.left + newWidth; 718 estimateCrop.bottom = estimateCrop.top + newHeight; 719 cropHint.set(estimateCrop); 720 estimateCrop.scale(1f / options.inSampleSize); 721 } 722 723 // We've got the safe cropHint; now we want to scale it properly to 724 // the desired rectangle. 725 // That's a height-biased operation: make it fit the hinted height. 726 final int safeHeight = (int) (estimateCrop.height() * hRatio); 727 final int safeWidth = (int) (estimateCrop.width() * hRatio); 728 729 if (DEBUG) { 730 Slog.v(TAG, "Decode parameters:"); 731 Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); 732 Slog.v(TAG, " down sampling=" + options.inSampleSize 733 + ", hRatio=" + hRatio); 734 Slog.v(TAG, " dest=" + destWidth + "x" + destHeight); 735 Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight); 736 Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize()); 737 } 738 739 Bitmap cropped = decoder.decodeRegion(cropHint, options); 740 decoder.recycle(); 741 742 if (cropped == null) { 743 Slog.e(TAG, "Could not decode new wallpaper"); 744 } else { 745 // We are safe to create final crop with safe dimensions now. 746 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, 747 safeWidth, safeHeight, true); 748 if (DEBUG) { 749 Slog.v(TAG, "Final extract:"); 750 Slog.v(TAG, " dims: w=" + wpData.mWidth 751 + " h=" + wpData.mHeight); 752 Slog.v(TAG, " out: w=" + finalCrop.getWidth() 753 + " h=" + finalCrop.getHeight()); 754 } 755 756 // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. 757 // Please see: RecordingCanvas#throwIfCannotDraw. 758 if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) { 759 throw new RuntimeException( 760 "Too large bitmap, limit=" + MAX_BITMAP_SIZE); 761 } 762 763 f = new FileOutputStream(wallpaper.cropFile); 764 bos = new BufferedOutputStream(f, 32*1024); 765 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos); 766 bos.flush(); // don't rely on the implicit flush-at-close when noting success 767 success = true; 768 } 769 } catch (Exception e) { 770 if (DEBUG) { 771 Slog.e(TAG, "Error decoding crop", e); 772 } 773 } finally { 774 IoUtils.closeQuietly(bos); 775 IoUtils.closeQuietly(f); 776 } 777 } 778 } 779 780 if (!success) { 781 Slog.e(TAG, "Unable to apply new wallpaper"); 782 wallpaper.cropFile.delete(); 783 } 784 785 if (wallpaper.cropFile.exists()) { 786 boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile()); 787 if (DEBUG) { 788 Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon); 789 } 790 } 791 } 792 793 private final Context mContext; 794 private final WindowManagerInternal mWindowManagerInternal; 795 private final IPackageManager mIPackageManager; 796 private final MyPackageMonitor mMonitor; 797 private final AppOpsManager mAppOpsManager; 798 799 private final DisplayManager mDisplayManager; 800 private final DisplayManager.DisplayListener mDisplayListener = 801 new DisplayManager.DisplayListener() { 802 803 @Override 804 public void onDisplayAdded(int displayId) { 805 } 806 807 @Override 808 public void onDisplayRemoved(int displayId) { 809 synchronized (mLock) { 810 if (mLastWallpaper != null) { 811 WallpaperData targetWallpaper = null; 812 if (mLastWallpaper.connection.containsDisplay(displayId)) { 813 targetWallpaper = mLastWallpaper; 814 } else if (mFallbackWallpaper.connection.containsDisplay(displayId)) { 815 targetWallpaper = mFallbackWallpaper; 816 } 817 if (targetWallpaper == null) return; 818 WallpaperConnection.DisplayConnector connector = 819 targetWallpaper.connection.getDisplayConnectorOrCreate(displayId); 820 if (connector == null) return; 821 connector.disconnectLocked(); 822 targetWallpaper.connection.removeDisplayConnector(displayId); 823 removeDisplayData(displayId); 824 } 825 for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) { 826 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks = 827 mColorsChangedListeners.valueAt(i); 828 callbacks.delete(displayId); 829 } 830 } 831 } 832 833 @Override 834 public void onDisplayChanged(int displayId) { 835 } 836 }; 837 838 /** 839 * Map of color listeners per user id. 840 * The first key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners. 841 * The secondary key will be the display id, which means which display the listener is 842 * interested in. 843 */ 844 private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>> 845 mColorsChangedListeners; 846 protected WallpaperData mLastWallpaper; 847 private IWallpaperManagerCallback mKeyguardListener; 848 private boolean mWaitingForUnlock; 849 private boolean mShuttingDown; 850 851 /** 852 * ID of the current wallpaper, changed every time anything sets a wallpaper. 853 * This is used for external detection of wallpaper update activity. 854 */ 855 private int mWallpaperId; 856 857 /** 858 * Name of the component used to display bitmap wallpapers from either the gallery or 859 * built-in wallpapers. 860 */ 861 private final ComponentName mImageWallpaper; 862 863 /** 864 * Default image wallpaper shall never changed after system service started, caching it when we 865 * first read the image file. 866 */ 867 private WallpaperColors mCacheDefaultImageWallpaperColors; 868 869 /** 870 * Name of the default wallpaper component; might be different from mImageWallpaper 871 */ 872 private final ComponentName mDefaultWallpaperComponent; 873 874 private final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>(); 875 private final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>(); 876 877 private SparseArray<DisplayData> mDisplayDatas = new SparseArray<>(); 878 879 protected WallpaperData mFallbackWallpaper; 880 881 private final SparseBooleanArray mUserRestorecon = new SparseBooleanArray(); 882 private int mCurrentUserId = UserHandle.USER_NULL; 883 private boolean mInAmbientMode; 884 885 static class WallpaperData { 886 887 int userId; 888 889 final File wallpaperFile; // source image 890 final File cropFile; // eventual destination 891 892 /** 893 * True while the client is writing a new wallpaper 894 */ 895 boolean imageWallpaperPending; 896 897 /** 898 * Which new wallpapers are being written; mirrors the 'which' 899 * selector bit field to setWallpaper(). 900 */ 901 int whichPending; 902 903 /** 904 * Callback once the set + crop is finished 905 */ 906 IWallpaperManagerCallback setComplete; 907 908 /** 909 * Is the OS allowed to back up this wallpaper imagery? 910 */ 911 boolean allowBackup; 912 913 /** 914 * Resource name if using a picture from the wallpaper gallery 915 */ 916 String name = ""; 917 918 /** 919 * The component name of the currently set live wallpaper. 920 */ 921 ComponentName wallpaperComponent; 922 923 /** 924 * The component name of the wallpaper that should be set next. 925 */ 926 ComponentName nextWallpaperComponent; 927 928 /** 929 * The ID of this wallpaper 930 */ 931 int wallpaperId; 932 933 /** 934 * Primary colors histogram 935 */ 936 WallpaperColors primaryColors; 937 938 WallpaperConnection connection; 939 long lastDiedTime; 940 boolean wallpaperUpdating; 941 WallpaperObserver wallpaperObserver; 942 943 /** 944 * List of callbacks registered they should each be notified when the wallpaper is changed. 945 */ 946 private RemoteCallbackList<IWallpaperManagerCallback> callbacks 947 = new RemoteCallbackList<IWallpaperManagerCallback>(); 948 949 /** 950 * The crop hint supplied for displaying a subset of the source image 951 */ 952 final Rect cropHint = new Rect(0, 0, 0, 0); 953 WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName)954 WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName) { 955 this.userId = userId; 956 wallpaperFile = new File(wallpaperDir, inputFileName); 957 cropFile = new File(wallpaperDir, cropFileName); 958 } 959 960 // Called during initialization of a given user's wallpaper bookkeeping cropExists()961 boolean cropExists() { 962 return cropFile.exists(); 963 } 964 sourceExists()965 boolean sourceExists() { 966 return wallpaperFile.exists(); 967 } 968 } 969 970 @VisibleForTesting 971 static final class DisplayData { 972 int mWidth = -1; 973 int mHeight = -1; 974 final Rect mPadding = new Rect(0, 0, 0, 0); 975 final int mDisplayId; 976 DisplayData(int displayId)977 DisplayData(int displayId) { 978 mDisplayId = displayId; 979 } 980 } 981 removeDisplayData(int displayId)982 private void removeDisplayData(int displayId) { 983 mDisplayDatas.remove(displayId); 984 } 985 getDisplayDataOrCreate(int displayId)986 private DisplayData getDisplayDataOrCreate(int displayId) { 987 DisplayData wpdData = mDisplayDatas.get(displayId); 988 if (wpdData == null) { 989 wpdData = new DisplayData(displayId); 990 ensureSaneWallpaperDisplaySize(wpdData, displayId); 991 mDisplayDatas.append(displayId, wpdData); 992 } 993 return wpdData; 994 } 995 ensureSaneWallpaperDisplaySize(DisplayData wpdData, int displayId)996 private void ensureSaneWallpaperDisplaySize(DisplayData wpdData, int displayId) { 997 // We always want to have some reasonable width hint. 998 final int baseSize = getMaximumSizeDimension(displayId); 999 if (wpdData.mWidth < baseSize) { 1000 wpdData.mWidth = baseSize; 1001 } 1002 if (wpdData.mHeight < baseSize) { 1003 wpdData.mHeight = baseSize; 1004 } 1005 } 1006 getMaximumSizeDimension(int displayId)1007 private int getMaximumSizeDimension(int displayId) { 1008 Display display = mDisplayManager.getDisplay(displayId); 1009 if (display == null) { 1010 Slog.w(TAG, "Invalid displayId=" + displayId + " " + Debug.getCallers(4)); 1011 display = mDisplayManager.getDisplay(DEFAULT_DISPLAY); 1012 } 1013 return display.getMaximumSizeDimension(); 1014 } 1015 forEachDisplayData(Consumer<DisplayData> action)1016 void forEachDisplayData(Consumer<DisplayData> action) { 1017 for (int i = mDisplayDatas.size() - 1; i >= 0; i--) { 1018 final DisplayData wpdData = mDisplayDatas.valueAt(i); 1019 action.accept(wpdData); 1020 } 1021 } 1022 makeWallpaperIdLocked()1023 int makeWallpaperIdLocked() { 1024 do { 1025 ++mWallpaperId; 1026 } while (mWallpaperId == 0); 1027 return mWallpaperId; 1028 } 1029 supportsMultiDisplay(WallpaperConnection connection)1030 private boolean supportsMultiDisplay(WallpaperConnection connection) { 1031 if (connection != null) { 1032 return connection.mInfo == null // This is image wallpaper 1033 || connection.mInfo.supportsMultipleDisplays(); 1034 } 1035 return false; 1036 } 1037 updateFallbackConnection()1038 private void updateFallbackConnection() { 1039 if (mLastWallpaper == null || mFallbackWallpaper == null) return; 1040 final WallpaperConnection systemConnection = mLastWallpaper.connection; 1041 final WallpaperConnection fallbackConnection = mFallbackWallpaper.connection; 1042 if (fallbackConnection == null) { 1043 Slog.w(TAG, "Fallback wallpaper connection has not been created yet!!"); 1044 return; 1045 } 1046 if (supportsMultiDisplay(systemConnection)) { 1047 if (fallbackConnection.mDisplayConnector.size() != 0) { 1048 fallbackConnection.forEachDisplayConnector(connector -> { 1049 if (connector.mEngine != null) { 1050 connector.disconnectLocked(); 1051 } 1052 }); 1053 fallbackConnection.mDisplayConnector.clear(); 1054 } 1055 } else { 1056 fallbackConnection.appendConnectorWithCondition(display -> 1057 fallbackConnection.isUsableDisplay(display) 1058 && display.getDisplayId() != DEFAULT_DISPLAY 1059 && !fallbackConnection.containsDisplay(display.getDisplayId())); 1060 fallbackConnection.forEachDisplayConnector(connector -> { 1061 if (connector.mEngine == null) { 1062 connector.connectLocked(fallbackConnection, mFallbackWallpaper); 1063 } 1064 }); 1065 } 1066 } 1067 1068 class WallpaperConnection extends IWallpaperConnection.Stub 1069 implements ServiceConnection { 1070 1071 /** 1072 * Collect needed info for a display. 1073 */ 1074 @VisibleForTesting 1075 final class DisplayConnector { 1076 final int mDisplayId; 1077 final Binder mToken = new Binder(); 1078 IWallpaperEngine mEngine; 1079 boolean mDimensionsChanged; 1080 boolean mPaddingChanged; 1081 DisplayConnector(int displayId)1082 DisplayConnector(int displayId) { 1083 mDisplayId = displayId; 1084 } 1085 ensureStatusHandled()1086 void ensureStatusHandled() { 1087 final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId); 1088 if (mDimensionsChanged) { 1089 try { 1090 mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight); 1091 } catch (RemoteException e) { 1092 Slog.w(TAG, "Failed to set wallpaper dimensions", e); 1093 } 1094 mDimensionsChanged = false; 1095 } 1096 if (mPaddingChanged) { 1097 try { 1098 mEngine.setDisplayPadding(wpdData.mPadding); 1099 } catch (RemoteException e) { 1100 Slog.w(TAG, "Failed to set wallpaper padding", e); 1101 } 1102 mPaddingChanged = false; 1103 } 1104 } 1105 connectLocked(WallpaperConnection connection, WallpaperData wallpaper)1106 void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) { 1107 if (connection.mService == null) { 1108 Slog.w(TAG, "WallpaperService is not connected yet"); 1109 return; 1110 } 1111 if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken); 1112 mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId); 1113 final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId); 1114 try { 1115 connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false, 1116 wpdData.mWidth, wpdData.mHeight, 1117 wpdData.mPadding, mDisplayId); 1118 } catch (RemoteException e) { 1119 Slog.w(TAG, "Failed attaching wallpaper on display", e); 1120 if (wallpaper != null && !wallpaper.wallpaperUpdating 1121 && connection.getConnectedEngineSize() == 0) { 1122 bindWallpaperComponentLocked(null /* componentName */, false /* force */, 1123 false /* fromUser */, wallpaper, null /* reply */); 1124 } 1125 } 1126 } 1127 disconnectLocked()1128 void disconnectLocked() { 1129 if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken); 1130 mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */, 1131 mDisplayId); 1132 try { 1133 if (mEngine != null) { 1134 mEngine.destroy(); 1135 } 1136 } catch (RemoteException e) { 1137 } 1138 mEngine = null; 1139 } 1140 } 1141 1142 /** 1143 * A map for each display. 1144 * Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable. 1145 */ 1146 private SparseArray<DisplayConnector> mDisplayConnector = new SparseArray<>(); 1147 1148 /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the 1149 * middle of an update). If exceeded, the wallpaper gets reset to the system default. */ 1150 private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000; 1151 1152 final WallpaperInfo mInfo; 1153 IWallpaperService mService; 1154 WallpaperData mWallpaper; 1155 final int mClientUid; 1156 IRemoteCallback mReply; 1157 1158 private Runnable mResetRunnable = () -> { 1159 synchronized (mLock) { 1160 if (mShuttingDown) { 1161 // Don't expect wallpaper services to relaunch during shutdown 1162 if (DEBUG_LIVE) { 1163 Slog.i(TAG, "Ignoring relaunch timeout during shutdown"); 1164 } 1165 return; 1166 } 1167 1168 if (!mWallpaper.wallpaperUpdating 1169 && mWallpaper.userId == mCurrentUserId) { 1170 Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent 1171 + ", reverting to built-in wallpaper!"); 1172 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, 1173 null); 1174 } 1175 } 1176 }; 1177 1178 private Runnable mTryToRebindRunnable = this::tryToRebind; 1179 WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid)1180 WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) { 1181 mInfo = info; 1182 mWallpaper = wallpaper; 1183 mClientUid = clientUid; 1184 initDisplayState(); 1185 } 1186 initDisplayState()1187 private void initDisplayState() { 1188 // Do not initialize fallback wallpaper 1189 if (!mWallpaper.equals(mFallbackWallpaper)) { 1190 if (supportsMultiDisplay(this)) { 1191 // The system wallpaper is image wallpaper or it can supports multiple displays. 1192 appendConnectorWithCondition(this::isUsableDisplay); 1193 } else { 1194 // The system wallpaper does not support multiple displays, so just attach it on 1195 // default display. 1196 mDisplayConnector.append(DEFAULT_DISPLAY, 1197 new DisplayConnector(DEFAULT_DISPLAY)); 1198 } 1199 } 1200 } 1201 appendConnectorWithCondition(Predicate<Display> tester)1202 private void appendConnectorWithCondition(Predicate<Display> tester) { 1203 final Display[] displays = mDisplayManager.getDisplays(); 1204 for (Display display : displays) { 1205 if (tester.test(display)) { 1206 final int displayId = display.getDisplayId(); 1207 final DisplayConnector connector = mDisplayConnector.get(displayId); 1208 if (connector == null) { 1209 mDisplayConnector.append(displayId, 1210 new DisplayConnector(displayId)); 1211 } 1212 } 1213 } 1214 } 1215 1216 @VisibleForTesting isUsableDisplay(Display display)1217 boolean isUsableDisplay(Display display) { 1218 if (display == null || !display.hasAccess(mClientUid)) { 1219 return false; 1220 } 1221 final int displayId = display.getDisplayId(); 1222 if (displayId == DEFAULT_DISPLAY) { 1223 return true; 1224 } 1225 1226 final long ident = Binder.clearCallingIdentity(); 1227 try { 1228 return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId); 1229 } finally { 1230 Binder.restoreCallingIdentity(ident); 1231 } 1232 } 1233 forEachDisplayConnector(Consumer<DisplayConnector> action)1234 void forEachDisplayConnector(Consumer<DisplayConnector> action) { 1235 for (int i = mDisplayConnector.size() - 1; i >= 0; i--) { 1236 final DisplayConnector connector = mDisplayConnector.valueAt(i); 1237 action.accept(connector); 1238 } 1239 } 1240 getConnectedEngineSize()1241 int getConnectedEngineSize() { 1242 int engineSize = 0; 1243 for (int i = mDisplayConnector.size() - 1; i >= 0; i--) { 1244 final DisplayConnector connector = mDisplayConnector.valueAt(i); 1245 if (connector.mEngine != null) engineSize++; 1246 } 1247 return engineSize; 1248 } 1249 getDisplayConnectorOrCreate(int displayId)1250 DisplayConnector getDisplayConnectorOrCreate(int displayId) { 1251 DisplayConnector connector = mDisplayConnector.get(displayId); 1252 if (connector == null) { 1253 final Display display = mDisplayManager.getDisplay(displayId); 1254 if (isUsableDisplay(display)) { 1255 connector = new DisplayConnector(displayId); 1256 mDisplayConnector.append(displayId, connector); 1257 } 1258 } 1259 return connector; 1260 } 1261 containsDisplay(int displayId)1262 boolean containsDisplay(int displayId) { 1263 return mDisplayConnector.get(displayId) != null; 1264 } 1265 removeDisplayConnector(int displayId)1266 void removeDisplayConnector(int displayId) { 1267 final DisplayConnector connector = mDisplayConnector.get(displayId); 1268 if (connector != null) { 1269 mDisplayConnector.remove(displayId); 1270 } 1271 } 1272 1273 @Override onServiceConnected(ComponentName name, IBinder service)1274 public void onServiceConnected(ComponentName name, IBinder service) { 1275 synchronized (mLock) { 1276 if (mWallpaper.connection == this) { 1277 mService = IWallpaperService.Stub.asInterface(service); 1278 attachServiceLocked(this, mWallpaper); 1279 // XXX should probably do saveSettingsLocked() later 1280 // when we have an engine, but I'm not sure about 1281 // locking there and anyway we always need to be able to 1282 // recover if there is something wrong. 1283 if (!mWallpaper.equals(mFallbackWallpaper)) { 1284 saveSettingsLocked(mWallpaper.userId); 1285 } 1286 FgThread.getHandler().removeCallbacks(mResetRunnable); 1287 mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable); 1288 } 1289 } 1290 } 1291 1292 @Override onServiceDisconnected(ComponentName name)1293 public void onServiceDisconnected(ComponentName name) { 1294 synchronized (mLock) { 1295 Slog.w(TAG, "Wallpaper service gone: " + name); 1296 if (!Objects.equals(name, mWallpaper.wallpaperComponent)) { 1297 Slog.e(TAG, "Does not match expected wallpaper component " 1298 + mWallpaper.wallpaperComponent); 1299 } 1300 mService = null; 1301 forEachDisplayConnector(connector -> connector.mEngine = null); 1302 if (mWallpaper.connection == this) { 1303 // There is an inherent ordering race between this callback and the 1304 // package monitor that receives notice that a package is being updated, 1305 // so we cannot quite trust at this moment that we know for sure that 1306 // this is not an update. If we think this is a genuine non-update 1307 // wallpaper outage, we do our "wait for reset" work as a continuation, 1308 // a short time in the future, specifically to allow any pending package 1309 // update message on this same looper thread to be processed. 1310 if (!mWallpaper.wallpaperUpdating) { 1311 mContext.getMainThreadHandler().postDelayed(mDisconnectRunnable, 1312 1000); 1313 } 1314 } 1315 } 1316 } 1317 scheduleTimeoutLocked()1318 private void scheduleTimeoutLocked() { 1319 // If we didn't reset it right away, do so after we couldn't connect to 1320 // it for an extended amount of time to avoid having a black wallpaper. 1321 final Handler fgHandler = FgThread.getHandler(); 1322 fgHandler.removeCallbacks(mResetRunnable); 1323 fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS); 1324 if (DEBUG_LIVE) { 1325 Slog.i(TAG, 1326 "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent); 1327 } 1328 } 1329 tryToRebind()1330 private void tryToRebind() { 1331 synchronized (mLock) { 1332 if (mWallpaper.wallpaperUpdating) { 1333 return; 1334 } 1335 final ComponentName wpService = mWallpaper.wallpaperComponent; 1336 // The broadcast of package update could be delayed after service disconnected. Try 1337 // to re-bind the service for 10 seconds. 1338 if (bindWallpaperComponentLocked( 1339 wpService, true, false, mWallpaper, null)) { 1340 mWallpaper.connection.scheduleTimeoutLocked(); 1341 } else if (SystemClock.uptimeMillis() - mWallpaper.lastDiedTime 1342 < WALLPAPER_RECONNECT_TIMEOUT_MS) { 1343 // Bind fail without timeout, schedule rebind 1344 Slog.w(TAG, "Rebind fail! Try again later"); 1345 mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1000); 1346 } else { 1347 // Timeout 1348 Slog.w(TAG, "Reverting to built-in wallpaper!"); 1349 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null); 1350 final String flattened = wpService.flattenToString(); 1351 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED, 1352 flattened.substring(0, Math.min(flattened.length(), 1353 MAX_WALLPAPER_COMPONENT_LOG_LENGTH))); 1354 } 1355 } 1356 } 1357 1358 private Runnable mDisconnectRunnable = () -> { 1359 synchronized (mLock) { 1360 // The wallpaper disappeared. If this isn't a system-default one, track 1361 // crashes and fall back to default if it continues to misbehave. 1362 if (this == mWallpaper.connection) { 1363 final ComponentName wpService = mWallpaper.wallpaperComponent; 1364 if (!mWallpaper.wallpaperUpdating 1365 && mWallpaper.userId == mCurrentUserId 1366 && !Objects.equals(mDefaultWallpaperComponent, wpService) 1367 && !Objects.equals(mImageWallpaper, wpService)) { 1368 // There is a race condition which causes 1369 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is 1370 // currently updating since the broadcast notifying us is async. 1371 // This race is overcome by the general rule that we only reset the 1372 // wallpaper if its service was shut down twice 1373 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis. 1374 if (mWallpaper.lastDiedTime != 0 1375 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME 1376 > SystemClock.uptimeMillis()) { 1377 Slog.w(TAG, "Reverting to built-in wallpaper!"); 1378 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null); 1379 } else { 1380 mWallpaper.lastDiedTime = SystemClock.uptimeMillis(); 1381 tryToRebind(); 1382 } 1383 } 1384 } else { 1385 if (DEBUG_LIVE) { 1386 Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring"); 1387 } 1388 } 1389 } 1390 }; 1391 1392 /** 1393 * Called by a live wallpaper if its colors have changed. 1394 * @param primaryColors representation of wallpaper primary colors 1395 * @param displayId for which display 1396 */ 1397 @Override onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId)1398 public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) { 1399 int which; 1400 synchronized (mLock) { 1401 // Do not broadcast changes on ImageWallpaper since it's handled 1402 // internally by this class. 1403 if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) { 1404 return; 1405 } 1406 1407 mWallpaper.primaryColors = primaryColors; 1408 1409 // Live wallpapers always are system wallpapers. 1410 which = FLAG_SYSTEM; 1411 // It's also the lock screen wallpaper when we don't have a bitmap in there. 1412 if (displayId == DEFAULT_DISPLAY) { 1413 final WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId); 1414 if (lockedWallpaper == null) { 1415 which |= FLAG_LOCK; 1416 } 1417 } 1418 } 1419 if (which != 0) { 1420 notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId); 1421 } 1422 } 1423 1424 @Override attachEngine(IWallpaperEngine engine, int displayId)1425 public void attachEngine(IWallpaperEngine engine, int displayId) { 1426 synchronized (mLock) { 1427 final DisplayConnector connector = getDisplayConnectorOrCreate(displayId); 1428 if (connector == null) { 1429 try { 1430 engine.destroy(); 1431 } catch (RemoteException e) { 1432 Slog.w(TAG, "Failed to destroy engine", e); 1433 } 1434 return; 1435 } 1436 connector.mEngine = engine; 1437 connector.ensureStatusHandled(); 1438 1439 // TODO(multi-display) TBD. 1440 if (mInfo != null && mInfo.supportsAmbientMode() && displayId == DEFAULT_DISPLAY) { 1441 try { 1442 connector.mEngine.setInAmbientMode(mInAmbientMode, 0L /* duration */); 1443 } catch (RemoteException e) { 1444 Slog.w(TAG, "Failed to set ambient mode state", e); 1445 } 1446 } 1447 try { 1448 // This will trigger onComputeColors in the wallpaper engine. 1449 // It's fine to be locked in here since the binder is oneway. 1450 connector.mEngine.requestWallpaperColors(); 1451 } catch (RemoteException e) { 1452 Slog.w(TAG, "Failed to request wallpaper colors", e); 1453 } 1454 } 1455 } 1456 1457 @Override engineShown(IWallpaperEngine engine)1458 public void engineShown(IWallpaperEngine engine) { 1459 synchronized (mLock) { 1460 if (mReply != null) { 1461 long ident = Binder.clearCallingIdentity(); 1462 try { 1463 mReply.sendResult(null); 1464 } catch (RemoteException e) { 1465 Binder.restoreCallingIdentity(ident); 1466 } 1467 mReply = null; 1468 } 1469 } 1470 } 1471 1472 @Override setWallpaper(String name)1473 public ParcelFileDescriptor setWallpaper(String name) { 1474 synchronized (mLock) { 1475 if (mWallpaper.connection == this) { 1476 return updateWallpaperBitmapLocked(name, mWallpaper, null); 1477 } 1478 return null; 1479 } 1480 } 1481 } 1482 1483 class MyPackageMonitor extends PackageMonitor { 1484 @Override onPackageUpdateFinished(String packageName, int uid)1485 public void onPackageUpdateFinished(String packageName, int uid) { 1486 synchronized (mLock) { 1487 if (mCurrentUserId != getChangingUserId()) { 1488 return; 1489 } 1490 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 1491 if (wallpaper != null) { 1492 final ComponentName wpService = wallpaper.wallpaperComponent; 1493 if (wpService != null && wpService.getPackageName().equals(packageName)) { 1494 if (DEBUG_LIVE) { 1495 Slog.i(TAG, "Wallpaper " + wpService + " update has finished"); 1496 } 1497 wallpaper.wallpaperUpdating = false; 1498 clearWallpaperComponentLocked(wallpaper); 1499 if (!bindWallpaperComponentLocked(wpService, false, false, 1500 wallpaper, null)) { 1501 Slog.w(TAG, "Wallpaper " + wpService 1502 + " no longer available; reverting to default"); 1503 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null); 1504 } 1505 } 1506 } 1507 } 1508 } 1509 1510 @Override onPackageModified(String packageName)1511 public void onPackageModified(String packageName) { 1512 synchronized (mLock) { 1513 if (mCurrentUserId != getChangingUserId()) { 1514 return; 1515 } 1516 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 1517 if (wallpaper != null) { 1518 if (wallpaper.wallpaperComponent == null 1519 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { 1520 return; 1521 } 1522 doPackagesChangedLocked(true, wallpaper); 1523 } 1524 } 1525 } 1526 1527 @Override onPackageUpdateStarted(String packageName, int uid)1528 public void onPackageUpdateStarted(String packageName, int uid) { 1529 synchronized (mLock) { 1530 if (mCurrentUserId != getChangingUserId()) { 1531 return; 1532 } 1533 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 1534 if (wallpaper != null) { 1535 if (wallpaper.wallpaperComponent != null 1536 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { 1537 if (DEBUG_LIVE) { 1538 Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent 1539 + " is updating"); 1540 } 1541 wallpaper.wallpaperUpdating = true; 1542 if (wallpaper.connection != null) { 1543 FgThread.getHandler().removeCallbacks( 1544 wallpaper.connection.mResetRunnable); 1545 } 1546 } 1547 } 1548 } 1549 } 1550 1551 @Override onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)1552 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 1553 synchronized (mLock) { 1554 boolean changed = false; 1555 if (mCurrentUserId != getChangingUserId()) { 1556 return false; 1557 } 1558 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 1559 if (wallpaper != null) { 1560 boolean res = doPackagesChangedLocked(doit, wallpaper); 1561 changed |= res; 1562 } 1563 return changed; 1564 } 1565 } 1566 1567 @Override onSomePackagesChanged()1568 public void onSomePackagesChanged() { 1569 synchronized (mLock) { 1570 if (mCurrentUserId != getChangingUserId()) { 1571 return; 1572 } 1573 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 1574 if (wallpaper != null) { 1575 doPackagesChangedLocked(true, wallpaper); 1576 } 1577 } 1578 } 1579 doPackagesChangedLocked(boolean doit, WallpaperData wallpaper)1580 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) { 1581 boolean changed = false; 1582 if (wallpaper.wallpaperComponent != null) { 1583 int change = isPackageDisappearing(wallpaper.wallpaperComponent 1584 .getPackageName()); 1585 if (change == PACKAGE_PERMANENT_CHANGE 1586 || change == PACKAGE_TEMPORARY_CHANGE) { 1587 changed = true; 1588 if (doit) { 1589 Slog.w(TAG, "Wallpaper uninstalled, removing: " 1590 + wallpaper.wallpaperComponent); 1591 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null); 1592 } 1593 } 1594 } 1595 if (wallpaper.nextWallpaperComponent != null) { 1596 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent 1597 .getPackageName()); 1598 if (change == PACKAGE_PERMANENT_CHANGE 1599 || change == PACKAGE_TEMPORARY_CHANGE) { 1600 wallpaper.nextWallpaperComponent = null; 1601 } 1602 } 1603 if (wallpaper.wallpaperComponent != null 1604 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) { 1605 try { 1606 mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent, 1607 PackageManager.MATCH_DIRECT_BOOT_AWARE 1608 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 1609 } catch (NameNotFoundException e) { 1610 Slog.w(TAG, "Wallpaper component gone, removing: " 1611 + wallpaper.wallpaperComponent); 1612 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null); 1613 } 1614 } 1615 if (wallpaper.nextWallpaperComponent != null 1616 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) { 1617 try { 1618 mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent, 1619 PackageManager.MATCH_DIRECT_BOOT_AWARE 1620 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); 1621 } catch (NameNotFoundException e) { 1622 wallpaper.nextWallpaperComponent = null; 1623 } 1624 } 1625 return changed; 1626 } 1627 } 1628 1629 @VisibleForTesting getCurrentWallpaperData(@etWallpaperFlags int which, int userId)1630 WallpaperData getCurrentWallpaperData(@SetWallpaperFlags int which, int userId) { 1631 synchronized (mLock) { 1632 final SparseArray<WallpaperData> wallpaperDataMap = 1633 which == FLAG_SYSTEM ? mWallpaperMap : mLockWallpaperMap; 1634 return wallpaperDataMap.get(userId); 1635 } 1636 } 1637 WallpaperManagerService(Context context)1638 public WallpaperManagerService(Context context) { 1639 if (DEBUG) Slog.v(TAG, "WallpaperService startup"); 1640 mContext = context; 1641 mShuttingDown = false; 1642 mImageWallpaper = ComponentName.unflattenFromString( 1643 context.getResources().getString(R.string.image_wallpaper_component)); 1644 mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context); 1645 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); 1646 mIPackageManager = AppGlobals.getPackageManager(); 1647 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 1648 mDisplayManager = mContext.getSystemService(DisplayManager.class); 1649 mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */); 1650 mMonitor = new MyPackageMonitor(); 1651 mColorsChangedListeners = new SparseArray<>(); 1652 1653 LocalServices.addService(WallpaperManagerInternal.class, new LocalService()); 1654 } 1655 1656 private final class LocalService extends WallpaperManagerInternal { 1657 @Override onDisplayReady(int displayId)1658 public void onDisplayReady(int displayId) { 1659 onDisplayReadyInternal(displayId); 1660 } 1661 } 1662 initialize()1663 void initialize() { 1664 mMonitor.register(mContext, null, UserHandle.ALL, true); 1665 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs(); 1666 1667 // Initialize state from the persistent store, then guarantee that the 1668 // WallpaperData for the system imagery is instantiated & active, creating 1669 // it from defaults if necessary. 1670 loadSettingsLocked(UserHandle.USER_SYSTEM, false); 1671 getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM); 1672 } 1673 getWallpaperDir(int userId)1674 File getWallpaperDir(int userId) { 1675 return Environment.getUserSystemDirectory(userId); 1676 } 1677 1678 @Override finalize()1679 protected void finalize() throws Throwable { 1680 super.finalize(); 1681 for (int i = 0; i < mWallpaperMap.size(); i++) { 1682 WallpaperData wallpaper = mWallpaperMap.valueAt(i); 1683 wallpaper.wallpaperObserver.stopWatching(); 1684 } 1685 } 1686 systemReady()1687 void systemReady() { 1688 if (DEBUG) Slog.v(TAG, "systemReady"); 1689 initialize(); 1690 1691 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM); 1692 // If we think we're going to be using the system image wallpaper imagery, make 1693 // sure we have something to render 1694 if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) { 1695 // No crop file? Make sure we've finished the processing sequence if necessary 1696 if (!wallpaper.cropExists()) { 1697 if (DEBUG) { 1698 Slog.i(TAG, "No crop; regenerating from source"); 1699 } 1700 generateCrop(wallpaper); 1701 } 1702 // Still nothing? Fall back to default. 1703 if (!wallpaper.cropExists()) { 1704 if (DEBUG) { 1705 Slog.i(TAG, "Unable to regenerate crop; resetting"); 1706 } 1707 clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null); 1708 } 1709 } else { 1710 if (DEBUG) { 1711 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring"); 1712 } 1713 } 1714 1715 IntentFilter userFilter = new IntentFilter(); 1716 userFilter.addAction(Intent.ACTION_USER_REMOVED); 1717 mContext.registerReceiver(new BroadcastReceiver() { 1718 @Override 1719 public void onReceive(Context context, Intent intent) { 1720 final String action = intent.getAction(); 1721 if (Intent.ACTION_USER_REMOVED.equals(action)) { 1722 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 1723 UserHandle.USER_NULL)); 1724 } 1725 } 1726 }, userFilter); 1727 1728 final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); 1729 mContext.registerReceiver(new BroadcastReceiver() { 1730 @Override 1731 public void onReceive(Context context, Intent intent) { 1732 if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { 1733 if (DEBUG) { 1734 Slog.i(TAG, "Shutting down"); 1735 } 1736 synchronized (mLock) { 1737 mShuttingDown = true; 1738 } 1739 } 1740 } 1741 }, shutdownFilter); 1742 1743 try { 1744 ActivityManager.getService().registerUserSwitchObserver( 1745 new UserSwitchObserver() { 1746 @Override 1747 public void onUserSwitching(int newUserId, IRemoteCallback reply) { 1748 switchUser(newUserId, reply); 1749 } 1750 }, TAG); 1751 } catch (RemoteException e) { 1752 e.rethrowAsRuntimeException(); 1753 } 1754 } 1755 1756 /** Called by SystemBackupAgent */ getName()1757 public String getName() { 1758 // Verify caller is the system 1759 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 1760 throw new RuntimeException("getName() can only be called from the system process"); 1761 } 1762 synchronized (mLock) { 1763 return mWallpaperMap.get(0).name; 1764 } 1765 } 1766 stopObserver(WallpaperData wallpaper)1767 void stopObserver(WallpaperData wallpaper) { 1768 if (wallpaper != null) { 1769 if (wallpaper.wallpaperObserver != null) { 1770 wallpaper.wallpaperObserver.stopWatching(); 1771 wallpaper.wallpaperObserver = null; 1772 } 1773 } 1774 } 1775 stopObserversLocked(int userId)1776 void stopObserversLocked(int userId) { 1777 stopObserver(mWallpaperMap.get(userId)); 1778 stopObserver(mLockWallpaperMap.get(userId)); 1779 mWallpaperMap.remove(userId); 1780 mLockWallpaperMap.remove(userId); 1781 } 1782 1783 @Override onBootPhase(int phase)1784 public void onBootPhase(int phase) { 1785 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 1786 systemReady(); 1787 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 1788 switchUser(UserHandle.USER_SYSTEM, null); 1789 } 1790 } 1791 1792 @Override onUnlockUser(final int userId)1793 public void onUnlockUser(final int userId) { 1794 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 1795 t.traceBegin("on-unlock-user-" + userId); 1796 try { 1797 synchronized (mLock) { 1798 if (mCurrentUserId == userId) { 1799 if (mWaitingForUnlock) { 1800 // the desired wallpaper is not direct-boot aware, load it now 1801 final WallpaperData systemWallpaper = 1802 getWallpaperSafeLocked(userId, FLAG_SYSTEM); 1803 switchWallpaper(systemWallpaper, null); 1804 notifyCallbacksLocked(systemWallpaper); 1805 } 1806 1807 // Make sure that the SELinux labeling of all the relevant files is correct. 1808 // This corrects for mislabeling bugs that might have arisen from move-to 1809 // operations involving the wallpaper files. This isn't timing-critical, 1810 // so we do it in the background to avoid holding up the user unlock operation. 1811 if (!mUserRestorecon.get(userId)) { 1812 mUserRestorecon.put(userId, true); 1813 Runnable relabeler = () -> { 1814 final File wallpaperDir = getWallpaperDir(userId); 1815 for (String filename : sPerUserFiles) { 1816 File f = new File(wallpaperDir, filename); 1817 if (f.exists()) { 1818 SELinux.restorecon(f); 1819 } 1820 } 1821 }; 1822 BackgroundThread.getHandler().post(relabeler); 1823 } 1824 } 1825 } 1826 } finally { 1827 t.traceEnd(); 1828 } 1829 } 1830 onRemoveUser(int userId)1831 void onRemoveUser(int userId) { 1832 if (userId < 1) return; 1833 1834 final File wallpaperDir = getWallpaperDir(userId); 1835 synchronized (mLock) { 1836 stopObserversLocked(userId); 1837 for (String filename : sPerUserFiles) { 1838 new File(wallpaperDir, filename).delete(); 1839 } 1840 mUserRestorecon.delete(userId); 1841 } 1842 } 1843 switchUser(int userId, IRemoteCallback reply)1844 void switchUser(int userId, IRemoteCallback reply) { 1845 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG); 1846 t.traceBegin("switch-user-" + userId); 1847 try { 1848 final WallpaperData systemWallpaper; 1849 final WallpaperData lockWallpaper; 1850 synchronized (mLock) { 1851 if (mCurrentUserId == userId) { 1852 return; 1853 } 1854 mCurrentUserId = userId; 1855 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); 1856 final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId); 1857 lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper; 1858 // Not started watching yet, in case wallpaper data was loaded for other reasons. 1859 if (systemWallpaper.wallpaperObserver == null) { 1860 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper); 1861 systemWallpaper.wallpaperObserver.startWatching(); 1862 } 1863 switchWallpaper(systemWallpaper, reply); 1864 } 1865 1866 // Offload color extraction to another thread since switchUser will be called 1867 // from the main thread. 1868 FgThread.getHandler().post(() -> { 1869 notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM); 1870 notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK); 1871 notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); 1872 }); 1873 } finally { 1874 t.traceEnd(); 1875 } 1876 } 1877 switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply)1878 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) { 1879 synchronized (mLock) { 1880 mWaitingForUnlock = false; 1881 final ComponentName cname = wallpaper.wallpaperComponent != null ? 1882 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent; 1883 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) { 1884 // We failed to bind the desired wallpaper, but that might 1885 // happen if the wallpaper isn't direct-boot aware 1886 ServiceInfo si = null; 1887 try { 1888 si = mIPackageManager.getServiceInfo(cname, 1889 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId); 1890 } catch (RemoteException ignored) { 1891 } 1892 1893 if (si == null) { 1894 Slog.w(TAG, "Failure starting previous wallpaper; clearing"); 1895 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply); 1896 } else { 1897 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked"); 1898 // We might end up persisting the current wallpaper data 1899 // while locked, so pretend like the component was actually 1900 // bound into place 1901 wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent; 1902 final WallpaperData fallback = 1903 new WallpaperData(wallpaper.userId, getWallpaperDir(wallpaper.userId), 1904 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); 1905 ensureSaneWallpaperData(fallback); 1906 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply); 1907 mWaitingForUnlock = true; 1908 } 1909 } 1910 } 1911 } 1912 1913 @Override clearWallpaper(String callingPackage, int which, int userId)1914 public void clearWallpaper(String callingPackage, int which, int userId) { 1915 if (DEBUG) Slog.v(TAG, "clearWallpaper"); 1916 checkPermission(android.Manifest.permission.SET_WALLPAPER); 1917 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) { 1918 return; 1919 } 1920 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 1921 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null); 1922 1923 WallpaperData data = null; 1924 synchronized (mLock) { 1925 clearWallpaperLocked(false, which, userId, null); 1926 1927 if (which == FLAG_LOCK) { 1928 data = mLockWallpaperMap.get(userId); 1929 } 1930 if (which == FLAG_SYSTEM || data == null) { 1931 data = mWallpaperMap.get(userId); 1932 } 1933 } 1934 1935 // When clearing a wallpaper, broadcast new valid colors 1936 if (data != null) { 1937 notifyWallpaperColorsChanged(data, which); 1938 notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); 1939 } 1940 } 1941 clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply)1942 void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) { 1943 if (which != FLAG_SYSTEM && which != FLAG_LOCK) { 1944 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear"); 1945 } 1946 1947 WallpaperData wallpaper = null; 1948 if (which == FLAG_LOCK) { 1949 wallpaper = mLockWallpaperMap.get(userId); 1950 if (wallpaper == null) { 1951 // It's already gone; we're done. 1952 if (DEBUG) { 1953 Slog.i(TAG, "Lock wallpaper already cleared"); 1954 } 1955 return; 1956 } 1957 } else { 1958 wallpaper = mWallpaperMap.get(userId); 1959 if (wallpaper == null) { 1960 // Might need to bring it in the first time to establish our rewrite 1961 loadSettingsLocked(userId, false); 1962 wallpaper = mWallpaperMap.get(userId); 1963 } 1964 } 1965 if (wallpaper == null) { 1966 return; 1967 } 1968 1969 final long ident = Binder.clearCallingIdentity(); 1970 try { 1971 if (wallpaper.wallpaperFile.exists()) { 1972 wallpaper.wallpaperFile.delete(); 1973 wallpaper.cropFile.delete(); 1974 if (which == FLAG_LOCK) { 1975 mLockWallpaperMap.remove(userId); 1976 final IWallpaperManagerCallback cb = mKeyguardListener; 1977 if (cb != null) { 1978 if (DEBUG) { 1979 Slog.i(TAG, "Notifying keyguard of lock wallpaper clear"); 1980 } 1981 try { 1982 cb.onWallpaperChanged(); 1983 } catch (RemoteException e) { 1984 // Oh well it went away; no big deal 1985 } 1986 } 1987 saveSettingsLocked(userId); 1988 return; 1989 } 1990 } 1991 1992 RuntimeException e = null; 1993 try { 1994 wallpaper.primaryColors = null; 1995 wallpaper.imageWallpaperPending = false; 1996 if (userId != mCurrentUserId) return; 1997 if (bindWallpaperComponentLocked(defaultFailed 1998 ? mImageWallpaper 1999 : null, true, false, wallpaper, reply)) { 2000 return; 2001 } 2002 } catch (IllegalArgumentException e1) { 2003 e = e1; 2004 } 2005 2006 // This can happen if the default wallpaper component doesn't 2007 // exist. This should be a system configuration problem, but 2008 // let's not let it crash the system and just live with no 2009 // wallpaper. 2010 Slog.e(TAG, "Default wallpaper component not found!", e); 2011 clearWallpaperComponentLocked(wallpaper); 2012 if (reply != null) { 2013 try { 2014 reply.sendResult(null); 2015 } catch (RemoteException e1) { 2016 } 2017 } 2018 } finally { 2019 Binder.restoreCallingIdentity(ident); 2020 } 2021 } 2022 hasNamedWallpaper(String name)2023 public boolean hasNamedWallpaper(String name) { 2024 synchronized (mLock) { 2025 List<UserInfo> users; 2026 long ident = Binder.clearCallingIdentity(); 2027 try { 2028 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers(); 2029 } finally { 2030 Binder.restoreCallingIdentity(ident); 2031 } 2032 for (UserInfo user: users) { 2033 // ignore managed profiles 2034 if (user.isManagedProfile()) { 2035 continue; 2036 } 2037 WallpaperData wd = mWallpaperMap.get(user.id); 2038 if (wd == null) { 2039 // User hasn't started yet, so load her settings to peek at the wallpaper 2040 loadSettingsLocked(user.id, false); 2041 wd = mWallpaperMap.get(user.id); 2042 } 2043 if (wd != null && name.equals(wd.name)) { 2044 return true; 2045 } 2046 } 2047 } 2048 return false; 2049 } 2050 isValidDisplay(int displayId)2051 private boolean isValidDisplay(int displayId) { 2052 return mDisplayManager.getDisplay(displayId) != null; 2053 } 2054 2055 /** 2056 * Sets the dimension hint for the wallpaper. These hints indicate the desired 2057 * minimum width and height for the wallpaper in a particular display. 2058 */ setDimensionHints(int width, int height, String callingPackage, int displayId)2059 public void setDimensionHints(int width, int height, String callingPackage, int displayId) 2060 throws RemoteException { 2061 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 2062 if (!isWallpaperSupported(callingPackage)) { 2063 return; 2064 } 2065 2066 // Make sure both width and height are not larger than max texture size. 2067 width = Math.min(width, GLHelper.getMaxTextureSize()); 2068 height = Math.min(height, GLHelper.getMaxTextureSize()); 2069 2070 synchronized (mLock) { 2071 int userId = UserHandle.getCallingUserId(); 2072 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); 2073 if (width <= 0 || height <= 0) { 2074 throw new IllegalArgumentException("width and height must be > 0"); 2075 } 2076 2077 if (!isValidDisplay(displayId)) { 2078 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2079 } 2080 2081 final DisplayData wpdData = getDisplayDataOrCreate(displayId); 2082 if (width != wpdData.mWidth || height != wpdData.mHeight) { 2083 wpdData.mWidth = width; 2084 wpdData.mHeight = height; 2085 if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId); 2086 if (mCurrentUserId != userId) return; // Don't change the properties now 2087 if (wallpaper.connection != null) { 2088 final WallpaperConnection.DisplayConnector connector = wallpaper.connection 2089 .getDisplayConnectorOrCreate(displayId); 2090 final IWallpaperEngine engine = connector != null ? connector.mEngine : null; 2091 if (engine != null) { 2092 try { 2093 engine.setDesiredSize(width, height); 2094 } catch (RemoteException e) { 2095 } 2096 notifyCallbacksLocked(wallpaper); 2097 } else if (wallpaper.connection.mService != null && connector != null) { 2098 // We've attached to the service but the engine hasn't attached back to us 2099 // yet. This means it will be created with the previous dimensions, so we 2100 // need to update it to the new dimensions once it attaches. 2101 connector.mDimensionsChanged = true; 2102 } 2103 } 2104 } 2105 } 2106 } 2107 2108 /** 2109 * Returns the desired minimum width for the wallpaper in a particular display. 2110 */ getWidthHint(int displayId)2111 public int getWidthHint(int displayId) throws RemoteException { 2112 synchronized (mLock) { 2113 if (!isValidDisplay(displayId)) { 2114 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2115 } 2116 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); 2117 if (wallpaper != null) { 2118 final DisplayData wpdData = getDisplayDataOrCreate(displayId); 2119 return wpdData.mWidth; 2120 } else { 2121 return 0; 2122 } 2123 } 2124 } 2125 2126 /** 2127 * Returns the desired minimum height for the wallpaper in a particular display. 2128 */ getHeightHint(int displayId)2129 public int getHeightHint(int displayId) throws RemoteException { 2130 synchronized (mLock) { 2131 if (!isValidDisplay(displayId)) { 2132 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2133 } 2134 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); 2135 if (wallpaper != null) { 2136 final DisplayData wpdData = getDisplayDataOrCreate(displayId); 2137 return wpdData.mHeight; 2138 } else { 2139 return 0; 2140 } 2141 } 2142 } 2143 2144 /** 2145 * Sets extra padding that we would like the wallpaper to have outside of the display. 2146 */ setDisplayPadding(Rect padding, String callingPackage, int displayId)2147 public void setDisplayPadding(Rect padding, String callingPackage, int displayId) { 2148 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 2149 if (!isWallpaperSupported(callingPackage)) { 2150 return; 2151 } 2152 synchronized (mLock) { 2153 if (!isValidDisplay(displayId)) { 2154 throw new IllegalArgumentException("Cannot find display with id=" + displayId); 2155 } 2156 int userId = UserHandle.getCallingUserId(); 2157 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); 2158 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) { 2159 throw new IllegalArgumentException("padding must be positive: " + padding); 2160 } 2161 2162 final DisplayData wpdData = getDisplayDataOrCreate(displayId); 2163 if (!padding.equals(wpdData.mPadding)) { 2164 wpdData.mPadding.set(padding); 2165 if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId); 2166 if (mCurrentUserId != userId) return; // Don't change the properties now 2167 if (wallpaper.connection != null) { 2168 final WallpaperConnection.DisplayConnector connector = wallpaper.connection 2169 .getDisplayConnectorOrCreate(displayId); 2170 final IWallpaperEngine engine = connector != null ? connector.mEngine : null; 2171 if (engine != null) { 2172 try { 2173 engine.setDisplayPadding(padding); 2174 } catch (RemoteException e) { 2175 } 2176 notifyCallbacksLocked(wallpaper); 2177 } else if (wallpaper.connection.mService != null && connector != null) { 2178 // We've attached to the service but the engine hasn't attached back to us 2179 // yet. This means it will be created with the previous dimensions, so we 2180 // need to update it to the new dimensions once it attaches. 2181 connector.mPaddingChanged = true; 2182 } 2183 } 2184 } 2185 } 2186 } 2187 2188 @Deprecated 2189 @Override getWallpaper(String callingPkg, IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId)2190 public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb, 2191 final int which, Bundle outParams, int wallpaperUserId) { 2192 return getWallpaperWithFeature(callingPkg, null, cb, which, outParams, wallpaperUserId); 2193 } 2194 2195 @Override getWallpaperWithFeature(String callingPkg, String callingFeatureId, IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId)2196 public ParcelFileDescriptor getWallpaperWithFeature(String callingPkg, String callingFeatureId, 2197 IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId) { 2198 final int hasPrivilege = mContext.checkCallingOrSelfPermission( 2199 android.Manifest.permission.READ_WALLPAPER_INTERNAL); 2200 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) { 2201 mContext.getSystemService(StorageManager.class).checkPermissionReadImages(true, 2202 Binder.getCallingPid(), Binder.getCallingUid(), callingPkg, callingFeatureId); 2203 } 2204 2205 wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2206 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null); 2207 2208 if (which != FLAG_SYSTEM && which != FLAG_LOCK) { 2209 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read"); 2210 } 2211 2212 synchronized (mLock) { 2213 final SparseArray<WallpaperData> whichSet = 2214 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap; 2215 WallpaperData wallpaper = whichSet.get(wallpaperUserId); 2216 if (wallpaper == null) { 2217 // There is no established wallpaper imagery of this type (expected 2218 // only for lock wallpapers; a system WallpaperData is established at 2219 // user switch) 2220 return null; 2221 } 2222 // Only for default display. 2223 final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY); 2224 try { 2225 if (outParams != null) { 2226 outParams.putInt("width", wpdData.mWidth); 2227 outParams.putInt("height", wpdData.mHeight); 2228 } 2229 if (cb != null) { 2230 wallpaper.callbacks.register(cb); 2231 } 2232 if (!wallpaper.cropFile.exists()) { 2233 return null; 2234 } 2235 return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY); 2236 } catch (FileNotFoundException e) { 2237 /* Shouldn't happen as we check to see if the file exists */ 2238 Slog.w(TAG, "Error getting wallpaper", e); 2239 } 2240 return null; 2241 } 2242 } 2243 2244 @Override getWallpaperInfo(int userId)2245 public WallpaperInfo getWallpaperInfo(int userId) { 2246 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2247 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null); 2248 synchronized (mLock) { 2249 WallpaperData wallpaper = mWallpaperMap.get(userId); 2250 if (wallpaper != null && wallpaper.connection != null) { 2251 return wallpaper.connection.mInfo; 2252 } 2253 return null; 2254 } 2255 } 2256 2257 @Override getWallpaperIdForUser(int which, int userId)2258 public int getWallpaperIdForUser(int which, int userId) { 2259 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 2260 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null); 2261 2262 if (which != FLAG_SYSTEM && which != FLAG_LOCK) { 2263 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper"); 2264 } 2265 2266 final SparseArray<WallpaperData> map = 2267 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap; 2268 synchronized (mLock) { 2269 WallpaperData wallpaper = map.get(userId); 2270 if (wallpaper != null) { 2271 return wallpaper.wallpaperId; 2272 } 2273 } 2274 return -1; 2275 } 2276 2277 @Override registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId)2278 public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, 2279 int displayId) { 2280 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), 2281 userId, true, true, "registerWallpaperColorsCallback", null); 2282 synchronized (mLock) { 2283 SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> 2284 userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId); 2285 if (userDisplayColorsChangedListeners == null) { 2286 userDisplayColorsChangedListeners = new SparseArray<>(); 2287 mColorsChangedListeners.put(userId, userDisplayColorsChangedListeners); 2288 } 2289 RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners = 2290 userDisplayColorsChangedListeners.get(displayId); 2291 if (displayChangedListeners == null) { 2292 displayChangedListeners = new RemoteCallbackList<>(); 2293 userDisplayColorsChangedListeners.put(displayId, displayChangedListeners); 2294 } 2295 displayChangedListeners.register(cb); 2296 } 2297 } 2298 2299 @Override unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, int displayId)2300 public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId, 2301 int displayId) { 2302 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), 2303 userId, true, true, "unregisterWallpaperColorsCallback", null); 2304 synchronized (mLock) { 2305 SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> 2306 userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId); 2307 if (userDisplayColorsChangedListeners != null) { 2308 RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners = 2309 userDisplayColorsChangedListeners.get(displayId); 2310 if (displayChangedListeners != null) { 2311 displayChangedListeners.unregister(cb); 2312 } 2313 } 2314 } 2315 } 2316 2317 /** 2318 * TODO(multi-display) Extends this method with specific display. 2319 * Propagate ambient state to wallpaper engine. 2320 * 2321 * @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise. 2322 * @param animationDuration Duration of the animation, or 0 when immediate. 2323 */ setInAmbientMode(boolean inAmbientMode, long animationDuration)2324 public void setInAmbientMode(boolean inAmbientMode, long animationDuration) { 2325 final IWallpaperEngine engine; 2326 synchronized (mLock) { 2327 mInAmbientMode = inAmbientMode; 2328 final WallpaperData data = mWallpaperMap.get(mCurrentUserId); 2329 // The wallpaper info is null for image wallpaper, also use the engine in this case. 2330 if (data != null && data.connection != null && (data.connection.mInfo == null 2331 || data.connection.mInfo.supportsAmbientMode())) { 2332 // TODO(multi-display) Extends this method with specific display. 2333 engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine; 2334 } else { 2335 engine = null; 2336 } 2337 } 2338 2339 if (engine != null) { 2340 try { 2341 engine.setInAmbientMode(inAmbientMode, animationDuration); 2342 } catch (RemoteException e) { 2343 // Cannot talk to wallpaper engine. 2344 } 2345 } 2346 } 2347 2348 @Override setLockWallpaperCallback(IWallpaperManagerCallback cb)2349 public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) { 2350 checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW); 2351 synchronized (mLock) { 2352 mKeyguardListener = cb; 2353 } 2354 return true; 2355 } 2356 2357 @Override getWallpaperColors(int which, int userId, int displayId)2358 public WallpaperColors getWallpaperColors(int which, int userId, int displayId) 2359 throws RemoteException { 2360 if (which != FLAG_LOCK && which != FLAG_SYSTEM) { 2361 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM"); 2362 } 2363 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), 2364 userId, false, true, "getWallpaperColors", null); 2365 2366 WallpaperData wallpaperData = null; 2367 boolean shouldExtract; 2368 2369 synchronized (mLock) { 2370 if (which == FLAG_LOCK) { 2371 wallpaperData = mLockWallpaperMap.get(userId); 2372 } 2373 2374 // Try to get the system wallpaper anyway since it might 2375 // also be the lock screen wallpaper 2376 if (wallpaperData == null) { 2377 wallpaperData = findWallpaperAtDisplay(userId, displayId); 2378 } 2379 2380 if (wallpaperData == null) { 2381 return null; 2382 } 2383 shouldExtract = wallpaperData.primaryColors == null; 2384 } 2385 2386 if (shouldExtract) { 2387 extractColors(wallpaperData); 2388 } 2389 2390 synchronized (mLock) { 2391 return wallpaperData.primaryColors; 2392 } 2393 } 2394 findWallpaperAtDisplay(int userId, int displayId)2395 private WallpaperData findWallpaperAtDisplay(int userId, int displayId) { 2396 if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null 2397 && mFallbackWallpaper.connection.containsDisplay(displayId)) { 2398 return mFallbackWallpaper; 2399 } else { 2400 return mWallpaperMap.get(userId); 2401 } 2402 } 2403 2404 @Override setWallpaper(String name, String callingPackage, Rect cropHint, boolean allowBackup, Bundle extras, int which, IWallpaperManagerCallback completion, int userId)2405 public ParcelFileDescriptor setWallpaper(String name, String callingPackage, 2406 Rect cropHint, boolean allowBackup, Bundle extras, int which, 2407 IWallpaperManagerCallback completion, int userId) { 2408 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, 2409 false /* all */, true /* full */, "changing wallpaper", null /* pkg */); 2410 checkPermission(android.Manifest.permission.SET_WALLPAPER); 2411 2412 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) { 2413 final String msg = "Must specify a valid wallpaper category to set"; 2414 Slog.e(TAG, msg); 2415 throw new IllegalArgumentException(msg); 2416 } 2417 2418 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) { 2419 return null; 2420 } 2421 2422 // "null" means the no-op crop, preserving the full input image 2423 if (cropHint == null) { 2424 cropHint = new Rect(0, 0, 0, 0); 2425 } else { 2426 if (cropHint.width() < 0 || cropHint.height() < 0 2427 || cropHint.left < 0 2428 || cropHint.top < 0) { 2429 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint); 2430 } 2431 } 2432 2433 synchronized (mLock) { 2434 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which)); 2435 WallpaperData wallpaper; 2436 2437 /* If we're setting system but not lock, and lock is currently sharing the system 2438 * wallpaper, we need to migrate that image over to being lock-only before 2439 * the caller here writes new bitmap data. 2440 */ 2441 if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) { 2442 Slog.i(TAG, "Migrating current wallpaper to be lock-only before" 2443 + "updating system wallpaper"); 2444 migrateSystemToLockWallpaperLocked(userId); 2445 } 2446 2447 wallpaper = getWallpaperSafeLocked(userId, which); 2448 final long ident = Binder.clearCallingIdentity(); 2449 try { 2450 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras); 2451 if (pfd != null) { 2452 wallpaper.imageWallpaperPending = true; 2453 wallpaper.whichPending = which; 2454 wallpaper.setComplete = completion; 2455 wallpaper.cropHint.set(cropHint); 2456 wallpaper.allowBackup = allowBackup; 2457 } 2458 return pfd; 2459 } finally { 2460 Binder.restoreCallingIdentity(ident); 2461 } 2462 } 2463 } 2464 migrateSystemToLockWallpaperLocked(int userId)2465 private void migrateSystemToLockWallpaperLocked(int userId) { 2466 WallpaperData sysWP = mWallpaperMap.get(userId); 2467 if (sysWP == null) { 2468 if (DEBUG) { 2469 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only"); 2470 } 2471 return; 2472 } 2473 2474 // We know a-priori that there is no lock-only wallpaper currently 2475 WallpaperData lockWP = new WallpaperData(userId, getWallpaperDir(userId), 2476 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); 2477 lockWP.wallpaperId = sysWP.wallpaperId; 2478 lockWP.cropHint.set(sysWP.cropHint); 2479 lockWP.allowBackup = sysWP.allowBackup; 2480 lockWP.primaryColors = sysWP.primaryColors; 2481 2482 // Migrate the bitmap files outright; no need to copy 2483 try { 2484 Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath()); 2485 Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath()); 2486 } catch (ErrnoException e) { 2487 Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage()); 2488 lockWP.wallpaperFile.delete(); 2489 lockWP.cropFile.delete(); 2490 return; 2491 } 2492 2493 mLockWallpaperMap.put(userId, lockWP); 2494 } 2495 updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, Bundle extras)2496 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, 2497 Bundle extras) { 2498 if (name == null) name = ""; 2499 try { 2500 File dir = getWallpaperDir(wallpaper.userId); 2501 if (!dir.exists()) { 2502 dir.mkdir(); 2503 FileUtils.setPermissions( 2504 dir.getPath(), 2505 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, 2506 -1, -1); 2507 } 2508 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile, 2509 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE); 2510 if (!SELinux.restorecon(wallpaper.wallpaperFile)) { 2511 Slog.w(TAG, "restorecon failed for wallpaper file: " + 2512 wallpaper.wallpaperFile.getPath()); 2513 return null; 2514 } 2515 wallpaper.name = name; 2516 wallpaper.wallpaperId = makeWallpaperIdLocked(); 2517 if (extras != null) { 2518 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId); 2519 } 2520 // Nullify field to require new computation 2521 wallpaper.primaryColors = null; 2522 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId 2523 + " name=" + name + " file=" + wallpaper.wallpaperFile.getName()); 2524 return fd; 2525 } catch (FileNotFoundException e) { 2526 Slog.w(TAG, "Error setting wallpaper", e); 2527 } 2528 return null; 2529 } 2530 2531 @Override setWallpaperComponentChecked(ComponentName name, String callingPackage, int userId)2532 public void setWallpaperComponentChecked(ComponentName name, String callingPackage, 2533 int userId) { 2534 2535 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) { 2536 setWallpaperComponent(name, userId); 2537 } 2538 } 2539 2540 // ToDo: Remove this version of the function 2541 @Override setWallpaperComponent(ComponentName name)2542 public void setWallpaperComponent(ComponentName name) { 2543 setWallpaperComponent(name, UserHandle.getCallingUserId()); 2544 } 2545 setWallpaperComponent(ComponentName name, int userId)2546 private void setWallpaperComponent(ComponentName name, int userId) { 2547 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, 2548 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */); 2549 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); 2550 2551 int which = FLAG_SYSTEM; 2552 boolean shouldNotifyColors = false; 2553 WallpaperData wallpaper; 2554 2555 synchronized (mLock) { 2556 Slog.v(TAG, "setWallpaperComponent name=" + name); 2557 wallpaper = mWallpaperMap.get(userId); 2558 if (wallpaper == null) { 2559 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); 2560 } 2561 final long ident = Binder.clearCallingIdentity(); 2562 2563 // Live wallpapers can't be specified for keyguard. If we're using a static 2564 // system+lock image currently, migrate the system wallpaper to be a lock-only 2565 // image as part of making a different live component active as the system 2566 // wallpaper. 2567 if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) { 2568 if (mLockWallpaperMap.get(userId) == null) { 2569 // We're using the static imagery and there is no lock-specific image in place, 2570 // therefore it's a shared system+lock image that we need to migrate. 2571 Slog.i(TAG, "Migrating current wallpaper to be lock-only before" 2572 + "updating system wallpaper"); 2573 migrateSystemToLockWallpaperLocked(userId); 2574 } 2575 } 2576 2577 // New live wallpaper is also a lock wallpaper if nothing is set 2578 if (mLockWallpaperMap.get(userId) == null) { 2579 which |= FLAG_LOCK; 2580 } 2581 2582 try { 2583 wallpaper.imageWallpaperPending = false; 2584 boolean same = changingToSame(name, wallpaper); 2585 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) { 2586 if (!same) { 2587 wallpaper.primaryColors = null; 2588 } else { 2589 if (wallpaper.connection != null) { 2590 wallpaper.connection.forEachDisplayConnector(displayConnector -> { 2591 try { 2592 if (displayConnector.mEngine != null) { 2593 displayConnector.mEngine.dispatchWallpaperCommand( 2594 COMMAND_REAPPLY, 0, 0, 0, null); 2595 } 2596 } catch (RemoteException e) { 2597 Slog.w(TAG, "Error sending apply message to wallpaper", e); 2598 } 2599 }); 2600 } 2601 } 2602 wallpaper.wallpaperId = makeWallpaperIdLocked(); 2603 notifyCallbacksLocked(wallpaper); 2604 shouldNotifyColors = true; 2605 } 2606 } finally { 2607 Binder.restoreCallingIdentity(ident); 2608 } 2609 } 2610 2611 if (shouldNotifyColors) { 2612 notifyWallpaperColorsChanged(wallpaper, which); 2613 notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM); 2614 } 2615 } 2616 changingToSame(ComponentName componentName, WallpaperData wallpaper)2617 private boolean changingToSame(ComponentName componentName, WallpaperData wallpaper) { 2618 if (wallpaper.connection != null) { 2619 if (wallpaper.wallpaperComponent == null) { 2620 if (componentName == null) { 2621 if (DEBUG) Slog.v(TAG, "changingToSame: still using default"); 2622 // Still using default wallpaper. 2623 return true; 2624 } 2625 } else if (wallpaper.wallpaperComponent.equals(componentName)) { 2626 // Changing to same wallpaper. 2627 if (DEBUG) Slog.v(TAG, "same wallpaper"); 2628 return true; 2629 } 2630 } 2631 return false; 2632 } 2633 bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply)2634 private boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, 2635 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { 2636 if (DEBUG_LIVE) { 2637 Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); 2638 } 2639 // Has the component changed? 2640 if (!force && changingToSame(componentName, wallpaper)) { 2641 return true; 2642 } 2643 2644 try { 2645 if (componentName == null) { 2646 componentName = mDefaultWallpaperComponent; 2647 if (componentName == null) { 2648 // Fall back to static image wallpaper 2649 componentName = mImageWallpaper; 2650 //clearWallpaperComponentLocked(); 2651 //return; 2652 if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper"); 2653 } 2654 } 2655 int serviceUserId = wallpaper.userId; 2656 ServiceInfo si = mIPackageManager.getServiceInfo(componentName, 2657 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId); 2658 if (si == null) { 2659 // The wallpaper component we're trying to use doesn't exist 2660 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable"); 2661 return false; 2662 } 2663 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) { 2664 String msg = "Selected service does not have " 2665 + android.Manifest.permission.BIND_WALLPAPER 2666 + ": " + componentName; 2667 if (fromUser) { 2668 throw new SecurityException(msg); 2669 } 2670 Slog.w(TAG, msg); 2671 return false; 2672 } 2673 2674 WallpaperInfo wi = null; 2675 2676 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); 2677 if (componentName != null && !componentName.equals(mImageWallpaper)) { 2678 // Make sure the selected service is actually a wallpaper service. 2679 List<ResolveInfo> ris = 2680 mIPackageManager.queryIntentServices(intent, 2681 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 2682 PackageManager.GET_META_DATA, serviceUserId).getList(); 2683 for (int i=0; i<ris.size(); i++) { 2684 ServiceInfo rsi = ris.get(i).serviceInfo; 2685 if (rsi.name.equals(si.name) && 2686 rsi.packageName.equals(si.packageName)) { 2687 try { 2688 wi = new WallpaperInfo(mContext, ris.get(i)); 2689 } catch (XmlPullParserException e) { 2690 if (fromUser) { 2691 throw new IllegalArgumentException(e); 2692 } 2693 Slog.w(TAG, e); 2694 return false; 2695 } catch (IOException e) { 2696 if (fromUser) { 2697 throw new IllegalArgumentException(e); 2698 } 2699 Slog.w(TAG, e); 2700 return false; 2701 } 2702 break; 2703 } 2704 } 2705 if (wi == null) { 2706 String msg = "Selected service is not a wallpaper: " 2707 + componentName; 2708 if (fromUser) { 2709 throw new SecurityException(msg); 2710 } 2711 Slog.w(TAG, msg); 2712 return false; 2713 } 2714 } 2715 2716 if (wi != null && wi.supportsAmbientMode()) { 2717 final int hasPrivilege = mIPackageManager.checkPermission( 2718 android.Manifest.permission.AMBIENT_WALLPAPER, wi.getPackageName(), 2719 serviceUserId); 2720 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) { 2721 String msg = "Selected service does not have " 2722 + android.Manifest.permission.AMBIENT_WALLPAPER 2723 + ": " + componentName; 2724 if (fromUser) { 2725 throw new SecurityException(msg); 2726 } 2727 Slog.w(TAG, msg); 2728 return false; 2729 } 2730 } 2731 2732 // Bind the service! 2733 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName); 2734 final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(), 2735 MATCH_DIRECT_BOOT_AUTO, wallpaper.userId); 2736 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid); 2737 intent.setComponent(componentName); 2738 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, 2739 com.android.internal.R.string.wallpaper_binding_label); 2740 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser( 2741 mContext, 0, 2742 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), 2743 mContext.getText(com.android.internal.R.string.chooser_wallpaper)), 2744 PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId))); 2745 if (!mContext.bindServiceAsUser(intent, newConn, 2746 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI 2747 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE 2748 | Context.BIND_INCLUDE_CAPABILITIES, 2749 new UserHandle(serviceUserId))) { 2750 String msg = "Unable to bind service: " 2751 + componentName; 2752 if (fromUser) { 2753 throw new IllegalArgumentException(msg); 2754 } 2755 Slog.w(TAG, msg); 2756 return false; 2757 } 2758 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null 2759 && !wallpaper.equals(mFallbackWallpaper)) { 2760 detachWallpaperLocked(mLastWallpaper); 2761 } 2762 wallpaper.wallpaperComponent = componentName; 2763 wallpaper.connection = newConn; 2764 newConn.mReply = reply; 2765 if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(mFallbackWallpaper)) { 2766 mLastWallpaper = wallpaper; 2767 } 2768 updateFallbackConnection(); 2769 } catch (RemoteException e) { 2770 String msg = "Remote exception for " + componentName + "\n" + e; 2771 if (fromUser) { 2772 throw new IllegalArgumentException(msg); 2773 } 2774 Slog.w(TAG, msg); 2775 return false; 2776 } 2777 return true; 2778 } 2779 detachWallpaperLocked(WallpaperData wallpaper)2780 private void detachWallpaperLocked(WallpaperData wallpaper) { 2781 if (wallpaper.connection != null) { 2782 if (wallpaper.connection.mReply != null) { 2783 try { 2784 wallpaper.connection.mReply.sendResult(null); 2785 } catch (RemoteException e) { 2786 } 2787 wallpaper.connection.mReply = null; 2788 } 2789 try { 2790 // It can be null if user switching happens before service connection. 2791 if (wallpaper.connection.mService != null) { 2792 wallpaper.connection.mService.detach(); 2793 } 2794 } catch (RemoteException e) { 2795 Slog.w(TAG, "Failed detaching wallpaper service ", e); 2796 } 2797 mContext.unbindService(wallpaper.connection); 2798 wallpaper.connection.forEachDisplayConnector( 2799 WallpaperConnection.DisplayConnector::disconnectLocked); 2800 wallpaper.connection.mService = null; 2801 wallpaper.connection.mDisplayConnector.clear(); 2802 2803 FgThread.getHandler().removeCallbacks(wallpaper.connection.mResetRunnable); 2804 mContext.getMainThreadHandler().removeCallbacks( 2805 wallpaper.connection.mDisconnectRunnable); 2806 mContext.getMainThreadHandler().removeCallbacks( 2807 wallpaper.connection.mTryToRebindRunnable); 2808 2809 wallpaper.connection = null; 2810 if (wallpaper == mLastWallpaper) mLastWallpaper = null; 2811 } 2812 } 2813 clearWallpaperComponentLocked(WallpaperData wallpaper)2814 private void clearWallpaperComponentLocked(WallpaperData wallpaper) { 2815 wallpaper.wallpaperComponent = null; 2816 detachWallpaperLocked(wallpaper); 2817 } 2818 attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper)2819 private void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) { 2820 conn.forEachDisplayConnector(connector-> connector.connectLocked(conn, wallpaper)); 2821 } 2822 notifyCallbacksLocked(WallpaperData wallpaper)2823 private void notifyCallbacksLocked(WallpaperData wallpaper) { 2824 final int n = wallpaper.callbacks.beginBroadcast(); 2825 for (int i = 0; i < n; i++) { 2826 try { 2827 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged(); 2828 } catch (RemoteException e) { 2829 2830 // The RemoteCallbackList will take care of removing 2831 // the dead object for us. 2832 } 2833 } 2834 wallpaper.callbacks.finishBroadcast(); 2835 2836 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 2837 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId)); 2838 } 2839 checkPermission(String permission)2840 private void checkPermission(String permission) { 2841 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) { 2842 throw new SecurityException("Access denied to process: " + Binder.getCallingPid() 2843 + ", must have permission " + permission); 2844 } 2845 } 2846 2847 /** 2848 * Certain user types do not support wallpapers (e.g. managed profiles). The check is 2849 * implemented through through the OP_WRITE_WALLPAPER AppOp. 2850 */ isWallpaperSupported(String callingPackage)2851 public boolean isWallpaperSupported(String callingPackage) { 2852 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(), 2853 callingPackage) == AppOpsManager.MODE_ALLOWED; 2854 } 2855 2856 @Override isSetWallpaperAllowed(String callingPackage)2857 public boolean isSetWallpaperAllowed(String callingPackage) { 2858 final PackageManager pm = mContext.getPackageManager(); 2859 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid()); 2860 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage); 2861 if (!uidMatchPackage) { 2862 return false; // callingPackage was faked. 2863 } 2864 DevicePolicyManagerInternal devicePolicyManagerInternal = 2865 LocalServices.getService(DevicePolicyManagerInternal.class); 2866 if (devicePolicyManagerInternal != null && 2867 devicePolicyManagerInternal.isDeviceOrProfileOwnerInCallingUser(callingPackage)) { 2868 return true; 2869 } 2870 final int callingUserId = UserHandle.getCallingUserId(); 2871 final long ident = Binder.clearCallingIdentity(); 2872 try { 2873 UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 2874 return !umi.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER, callingUserId); 2875 } finally { 2876 Binder.restoreCallingIdentity(ident); 2877 } 2878 } 2879 2880 @Override isWallpaperBackupEligible(int which, int userId)2881 public boolean isWallpaperBackupEligible(int which, int userId) { 2882 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 2883 throw new SecurityException("Only the system may call isWallpaperBackupEligible"); 2884 } 2885 2886 WallpaperData wallpaper = (which == FLAG_LOCK) 2887 ? mLockWallpaperMap.get(userId) 2888 : mWallpaperMap.get(userId); 2889 return (wallpaper != null) ? wallpaper.allowBackup : false; 2890 } 2891 onDisplayReadyInternal(int displayId)2892 private void onDisplayReadyInternal(int displayId) { 2893 synchronized (mLock) { 2894 if (mLastWallpaper == null) { 2895 return; 2896 } 2897 if (supportsMultiDisplay(mLastWallpaper.connection)) { 2898 final WallpaperConnection.DisplayConnector connector = 2899 mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId); 2900 if (connector == null) return; 2901 connector.connectLocked(mLastWallpaper.connection, mLastWallpaper); 2902 return; 2903 } 2904 // System wallpaper does not support multiple displays, attach this display to 2905 // the fallback wallpaper. 2906 if (mFallbackWallpaper != null) { 2907 final WallpaperConnection.DisplayConnector connector = mFallbackWallpaper 2908 .connection.getDisplayConnectorOrCreate(displayId); 2909 if (connector == null) return; 2910 connector.connectLocked(mFallbackWallpaper.connection, mFallbackWallpaper); 2911 } else { 2912 Slog.w(TAG, "No wallpaper can be added to the new display"); 2913 } 2914 } 2915 } 2916 makeJournaledFile(int userId)2917 private JournaledFile makeJournaledFile(int userId) { 2918 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath(); 2919 return new JournaledFile(new File(base), new File(base + ".tmp")); 2920 } 2921 saveSettingsLocked(int userId)2922 private void saveSettingsLocked(int userId) { 2923 JournaledFile journal = makeJournaledFile(userId); 2924 FileOutputStream fstream = null; 2925 BufferedOutputStream stream = null; 2926 try { 2927 XmlSerializer out = new FastXmlSerializer(); 2928 fstream = new FileOutputStream(journal.chooseForWrite(), false); 2929 stream = new BufferedOutputStream(fstream); 2930 out.setOutput(stream, StandardCharsets.UTF_8.name()); 2931 out.startDocument(null, true); 2932 2933 WallpaperData wallpaper; 2934 2935 wallpaper = mWallpaperMap.get(userId); 2936 if (wallpaper != null) { 2937 writeWallpaperAttributes(out, "wp", wallpaper); 2938 } 2939 wallpaper = mLockWallpaperMap.get(userId); 2940 if (wallpaper != null) { 2941 writeWallpaperAttributes(out, "kwp", wallpaper); 2942 } 2943 2944 out.endDocument(); 2945 2946 stream.flush(); // also flushes fstream 2947 FileUtils.sync(fstream); 2948 stream.close(); // also closes fstream 2949 journal.commit(); 2950 } catch (IOException e) { 2951 IoUtils.closeQuietly(stream); 2952 journal.rollback(); 2953 } 2954 } 2955 writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)2956 private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper) 2957 throws IllegalArgumentException, IllegalStateException, IOException { 2958 if (DEBUG) { 2959 Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId); 2960 } 2961 final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY); 2962 out.startTag(null, tag); 2963 out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId)); 2964 out.attribute(null, "width", Integer.toString(wpdData.mWidth)); 2965 out.attribute(null, "height", Integer.toString(wpdData.mHeight)); 2966 2967 out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left)); 2968 out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top)); 2969 out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right)); 2970 out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom)); 2971 2972 if (wpdData.mPadding.left != 0) { 2973 out.attribute(null, "paddingLeft", Integer.toString(wpdData.mPadding.left)); 2974 } 2975 if (wpdData.mPadding.top != 0) { 2976 out.attribute(null, "paddingTop", Integer.toString(wpdData.mPadding.top)); 2977 } 2978 if (wpdData.mPadding.right != 0) { 2979 out.attribute(null, "paddingRight", Integer.toString(wpdData.mPadding.right)); 2980 } 2981 if (wpdData.mPadding.bottom != 0) { 2982 out.attribute(null, "paddingBottom", Integer.toString(wpdData.mPadding.bottom)); 2983 } 2984 2985 if (wallpaper.primaryColors != null) { 2986 int colorsCount = wallpaper.primaryColors.getMainColors().size(); 2987 out.attribute(null, "colorsCount", Integer.toString(colorsCount)); 2988 if (colorsCount > 0) { 2989 for (int i = 0; i < colorsCount; i++) { 2990 final Color wc = wallpaper.primaryColors.getMainColors().get(i); 2991 out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb())); 2992 } 2993 } 2994 out.attribute(null, "colorHints", 2995 Integer.toString(wallpaper.primaryColors.getColorHints())); 2996 } 2997 2998 out.attribute(null, "name", wallpaper.name); 2999 if (wallpaper.wallpaperComponent != null 3000 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) { 3001 out.attribute(null, "component", 3002 wallpaper.wallpaperComponent.flattenToShortString()); 3003 } 3004 3005 if (wallpaper.allowBackup) { 3006 out.attribute(null, "backup", "true"); 3007 } 3008 3009 out.endTag(null, tag); 3010 } 3011 migrateFromOld()3012 private void migrateFromOld() { 3013 // Pre-N, what existed is the one we're now using as the display crop 3014 File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP); 3015 // In the very-long-ago, imagery lived with the settings app 3016 File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY); 3017 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER); 3018 3019 // Migrations from earlier wallpaper image storage schemas 3020 if (preNWallpaper.exists()) { 3021 if (!newWallpaper.exists()) { 3022 // we've got the 'wallpaper' crop file but not the nominal source image, 3023 // so do the simple "just take everything" straight copy of legacy data 3024 if (DEBUG) { 3025 Slog.i(TAG, "Migrating wallpaper schema"); 3026 } 3027 FileUtils.copyFile(preNWallpaper, newWallpaper); 3028 } // else we're in the usual modern case: both source & crop exist 3029 } else if (originalWallpaper.exists()) { 3030 // VERY old schema; make sure things exist and are in the right place 3031 if (DEBUG) { 3032 Slog.i(TAG, "Migrating antique wallpaper schema"); 3033 } 3034 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY); 3035 if (oldInfo.exists()) { 3036 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO); 3037 oldInfo.renameTo(newInfo); 3038 } 3039 3040 FileUtils.copyFile(originalWallpaper, preNWallpaper); 3041 originalWallpaper.renameTo(newWallpaper); 3042 } 3043 } 3044 getAttributeInt(XmlPullParser parser, String name, int defValue)3045 private int getAttributeInt(XmlPullParser parser, String name, int defValue) { 3046 String value = parser.getAttributeValue(null, name); 3047 if (value == null) { 3048 return defValue; 3049 } 3050 return Integer.parseInt(value); 3051 } 3052 3053 /** 3054 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could 3055 * happen during user switch. The async user switch observer may not have received 3056 * the event yet. We use this safe method when we don't care about this ordering and just 3057 * want to update the data. The data is going to be applied when the user switch observer 3058 * is eventually executed. 3059 * 3060 * Important: this method loads settings to initialize the given user's wallpaper data if 3061 * there is no current in-memory state. 3062 */ getWallpaperSafeLocked(int userId, int which)3063 private WallpaperData getWallpaperSafeLocked(int userId, int which) { 3064 // We're setting either just system (work with the system wallpaper), 3065 // both (also work with the system wallpaper), or just the lock 3066 // wallpaper (update against the existing lock wallpaper if any). 3067 // Combined or just-system operations use the 'system' WallpaperData 3068 // for this use; lock-only operations use the dedicated one. 3069 final SparseArray<WallpaperData> whichSet = 3070 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap; 3071 WallpaperData wallpaper = whichSet.get(userId); 3072 if (wallpaper == null) { 3073 // common case, this is the first lookup post-boot of the system or 3074 // unified lock, so we bring up the saved state lazily now and recheck. 3075 loadSettingsLocked(userId, false); 3076 wallpaper = whichSet.get(userId); 3077 // if it's still null here, this is a lock-only operation and there is not 3078 // yet a lock-only wallpaper set for this user, so we need to establish 3079 // it now. 3080 if (wallpaper == null) { 3081 if (which == FLAG_LOCK) { 3082 wallpaper = new WallpaperData(userId, getWallpaperDir(userId), 3083 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); 3084 mLockWallpaperMap.put(userId, wallpaper); 3085 ensureSaneWallpaperData(wallpaper); 3086 } else { 3087 // sanity fallback: we're in bad shape, but establishing a known 3088 // valid system+lock WallpaperData will keep us from dying. 3089 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!"); 3090 wallpaper = new WallpaperData(userId, getWallpaperDir(userId), 3091 WALLPAPER, WALLPAPER_CROP); 3092 mWallpaperMap.put(userId, wallpaper); 3093 ensureSaneWallpaperData(wallpaper); 3094 } 3095 } 3096 } 3097 return wallpaper; 3098 } 3099 loadSettingsLocked(int userId, boolean keepDimensionHints)3100 private void loadSettingsLocked(int userId, boolean keepDimensionHints) { 3101 JournaledFile journal = makeJournaledFile(userId); 3102 FileInputStream stream = null; 3103 File file = journal.chooseForRead(); 3104 3105 WallpaperData wallpaper = mWallpaperMap.get(userId); 3106 if (wallpaper == null) { 3107 // Do this once per boot 3108 migrateFromOld(); 3109 3110 wallpaper = new WallpaperData(userId, getWallpaperDir(userId), 3111 WALLPAPER, WALLPAPER_CROP); 3112 wallpaper.allowBackup = true; 3113 mWallpaperMap.put(userId, wallpaper); 3114 if (!wallpaper.cropExists()) { 3115 if (wallpaper.sourceExists()) { 3116 generateCrop(wallpaper); 3117 } else { 3118 Slog.i(TAG, "No static wallpaper imagery; defaults will be shown"); 3119 } 3120 } 3121 initializeFallbackWallpaper(); 3122 } 3123 boolean success = false; 3124 final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY); 3125 try { 3126 stream = new FileInputStream(file); 3127 XmlPullParser parser = Xml.newPullParser(); 3128 parser.setInput(stream, StandardCharsets.UTF_8.name()); 3129 3130 int type; 3131 do { 3132 type = parser.next(); 3133 if (type == XmlPullParser.START_TAG) { 3134 String tag = parser.getName(); 3135 if ("wp".equals(tag)) { 3136 // Common to system + lock wallpapers 3137 parseWallpaperAttributes(parser, wallpaper, keepDimensionHints); 3138 3139 // A system wallpaper might also be a live wallpaper 3140 String comp = parser.getAttributeValue(null, "component"); 3141 wallpaper.nextWallpaperComponent = comp != null 3142 ? ComponentName.unflattenFromString(comp) 3143 : null; 3144 if (wallpaper.nextWallpaperComponent == null 3145 || "android".equals(wallpaper.nextWallpaperComponent 3146 .getPackageName())) { 3147 wallpaper.nextWallpaperComponent = mImageWallpaper; 3148 } 3149 3150 if (DEBUG) { 3151 Slog.v(TAG, "mWidth:" + wpdData.mWidth); 3152 Slog.v(TAG, "mHeight:" + wpdData.mHeight); 3153 Slog.v(TAG, "cropRect:" + wallpaper.cropHint); 3154 Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors); 3155 Slog.v(TAG, "mName:" + wallpaper.name); 3156 Slog.v(TAG, "mNextWallpaperComponent:" 3157 + wallpaper.nextWallpaperComponent); 3158 } 3159 } else if ("kwp".equals(tag)) { 3160 // keyguard-specific wallpaper for this user 3161 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); 3162 if (lockWallpaper == null) { 3163 lockWallpaper = new WallpaperData(userId, getWallpaperDir(userId), 3164 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); 3165 mLockWallpaperMap.put(userId, lockWallpaper); 3166 } 3167 parseWallpaperAttributes(parser, lockWallpaper, false); 3168 } 3169 } 3170 } while (type != XmlPullParser.END_DOCUMENT); 3171 success = true; 3172 } catch (FileNotFoundException e) { 3173 Slog.w(TAG, "no current wallpaper -- first boot?"); 3174 } catch (NullPointerException e) { 3175 Slog.w(TAG, "failed parsing " + file + " " + e); 3176 } catch (NumberFormatException e) { 3177 Slog.w(TAG, "failed parsing " + file + " " + e); 3178 } catch (XmlPullParserException e) { 3179 Slog.w(TAG, "failed parsing " + file + " " + e); 3180 } catch (IOException e) { 3181 Slog.w(TAG, "failed parsing " + file + " " + e); 3182 } catch (IndexOutOfBoundsException e) { 3183 Slog.w(TAG, "failed parsing " + file + " " + e); 3184 } 3185 IoUtils.closeQuietly(stream); 3186 3187 if (!success) { 3188 wallpaper.cropHint.set(0, 0, 0, 0); 3189 wpdData.mPadding.set(0, 0, 0, 0); 3190 wallpaper.name = ""; 3191 3192 mLockWallpaperMap.remove(userId); 3193 } else { 3194 if (wallpaper.wallpaperId <= 0) { 3195 wallpaper.wallpaperId = makeWallpaperIdLocked(); 3196 if (DEBUG) { 3197 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId 3198 + "); now " + wallpaper.wallpaperId); 3199 } 3200 } 3201 } 3202 3203 ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY); 3204 ensureSaneWallpaperData(wallpaper); 3205 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); 3206 if (lockWallpaper != null) { 3207 ensureSaneWallpaperData(lockWallpaper); 3208 } 3209 } 3210 initializeFallbackWallpaper()3211 private void initializeFallbackWallpaper() { 3212 if (mFallbackWallpaper == null) { 3213 if (DEBUG) Slog.d(TAG, "Initialize fallback wallpaper"); 3214 final int systemUserId = UserHandle.USER_SYSTEM; 3215 mFallbackWallpaper = new WallpaperData(systemUserId, getWallpaperDir(systemUserId), 3216 WALLPAPER, WALLPAPER_CROP); 3217 mFallbackWallpaper.allowBackup = false; 3218 mFallbackWallpaper.wallpaperId = makeWallpaperIdLocked(); 3219 bindWallpaperComponentLocked(mImageWallpaper, true, false, mFallbackWallpaper, null); 3220 } 3221 } 3222 ensureSaneWallpaperData(WallpaperData wallpaper)3223 private void ensureSaneWallpaperData(WallpaperData wallpaper) { 3224 // Only overwrite cropHint if the rectangle is invalid. 3225 if (wallpaper.cropHint.width() < 0 3226 || wallpaper.cropHint.height() < 0) { 3227 wallpaper.cropHint.set(0, 0, 0, 0); 3228 } 3229 } 3230 parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper, boolean keepDimensionHints)3231 private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper, 3232 boolean keepDimensionHints) { 3233 final String idString = parser.getAttributeValue(null, "id"); 3234 if (idString != null) { 3235 final int id = wallpaper.wallpaperId = Integer.parseInt(idString); 3236 if (id > mWallpaperId) { 3237 mWallpaperId = id; 3238 } 3239 } else { 3240 wallpaper.wallpaperId = makeWallpaperIdLocked(); 3241 } 3242 3243 final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY); 3244 3245 if (!keepDimensionHints) { 3246 wpData.mWidth = Integer.parseInt(parser.getAttributeValue(null, "width")); 3247 wpData.mHeight = Integer.parseInt(parser.getAttributeValue(null, "height")); 3248 } 3249 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0); 3250 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0); 3251 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0); 3252 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); 3253 wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0); 3254 wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0); 3255 wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0); 3256 wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0); 3257 int colorsCount = getAttributeInt(parser, "colorsCount", 0); 3258 if (colorsCount > 0) { 3259 Color primary = null, secondary = null, tertiary = null; 3260 for (int i = 0; i < colorsCount; i++) { 3261 Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0)); 3262 if (i == 0) { 3263 primary = color; 3264 } else if (i == 1) { 3265 secondary = color; 3266 } else if (i == 2) { 3267 tertiary = color; 3268 } else { 3269 break; 3270 } 3271 } 3272 int colorHints = getAttributeInt(parser, "colorHints", 0); 3273 wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints); 3274 } 3275 wallpaper.name = parser.getAttributeValue(null, "name"); 3276 wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup")); 3277 } 3278 3279 // Called by SystemBackupAgent after files are restored to disk. settingsRestored()3280 public void settingsRestored() { 3281 // Verify caller is the system 3282 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 3283 throw new RuntimeException("settingsRestored() can only be called from the system process"); 3284 } 3285 // TODO: If necessary, make it work for secondary users as well. This currently assumes 3286 // restores only to the primary user 3287 if (DEBUG) Slog.v(TAG, "settingsRestored"); 3288 WallpaperData wallpaper = null; 3289 boolean success = false; 3290 synchronized (mLock) { 3291 loadSettingsLocked(UserHandle.USER_SYSTEM, false); 3292 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM); 3293 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore 3294 wallpaper.allowBackup = true; // by definition if it was restored 3295 if (wallpaper.nextWallpaperComponent != null 3296 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) { 3297 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false, 3298 wallpaper, null)) { 3299 // No such live wallpaper or other failure; fall back to the default 3300 // live wallpaper (since the profile being restored indicated that the 3301 // user had selected a live rather than static one). 3302 bindWallpaperComponentLocked(null, false, false, wallpaper, null); 3303 } 3304 success = true; 3305 } else { 3306 // If there's a wallpaper name, we use that. If that can't be loaded, then we 3307 // use the default. 3308 if ("".equals(wallpaper.name)) { 3309 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty"); 3310 success = true; 3311 } else { 3312 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource"); 3313 success = restoreNamedResourceLocked(wallpaper); 3314 } 3315 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success 3316 + " id=" + wallpaper.wallpaperId); 3317 if (success) { 3318 generateCrop(wallpaper); // based on the new image + metadata 3319 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false, 3320 wallpaper, null); 3321 } 3322 } 3323 } 3324 3325 if (!success) { 3326 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'"); 3327 wallpaper.name = ""; 3328 getWallpaperDir(UserHandle.USER_SYSTEM).delete(); 3329 } 3330 3331 synchronized (mLock) { 3332 saveSettingsLocked(UserHandle.USER_SYSTEM); 3333 } 3334 } 3335 3336 // Restore the named resource bitmap to both source + crop files restoreNamedResourceLocked(WallpaperData wallpaper)3337 private boolean restoreNamedResourceLocked(WallpaperData wallpaper) { 3338 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) { 3339 String resName = wallpaper.name.substring(4); 3340 3341 String pkg = null; 3342 int colon = resName.indexOf(':'); 3343 if (colon > 0) { 3344 pkg = resName.substring(0, colon); 3345 } 3346 3347 String ident = null; 3348 int slash = resName.lastIndexOf('/'); 3349 if (slash > 0) { 3350 ident = resName.substring(slash+1); 3351 } 3352 3353 String type = null; 3354 if (colon > 0 && slash > 0 && (slash-colon) > 1) { 3355 type = resName.substring(colon+1, slash); 3356 } 3357 3358 if (pkg != null && ident != null && type != null) { 3359 int resId = -1; 3360 InputStream res = null; 3361 FileOutputStream fos = null; 3362 FileOutputStream cos = null; 3363 try { 3364 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); 3365 Resources r = c.getResources(); 3366 resId = r.getIdentifier(resName, null, null); 3367 if (resId == 0) { 3368 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type 3369 + " ident=" + ident); 3370 return false; 3371 } 3372 3373 res = r.openRawResource(resId); 3374 if (wallpaper.wallpaperFile.exists()) { 3375 wallpaper.wallpaperFile.delete(); 3376 wallpaper.cropFile.delete(); 3377 } 3378 fos = new FileOutputStream(wallpaper.wallpaperFile); 3379 cos = new FileOutputStream(wallpaper.cropFile); 3380 3381 byte[] buffer = new byte[32768]; 3382 int amt; 3383 while ((amt=res.read(buffer)) > 0) { 3384 fos.write(buffer, 0, amt); 3385 cos.write(buffer, 0, amt); 3386 } 3387 // mWallpaperObserver will notice the close and send the change broadcast 3388 3389 Slog.v(TAG, "Restored wallpaper: " + resName); 3390 return true; 3391 } catch (NameNotFoundException e) { 3392 Slog.e(TAG, "Package name " + pkg + " not found"); 3393 } catch (Resources.NotFoundException e) { 3394 Slog.e(TAG, "Resource not found: " + resId); 3395 } catch (IOException e) { 3396 Slog.e(TAG, "IOException while restoring wallpaper ", e); 3397 } finally { 3398 IoUtils.closeQuietly(res); 3399 if (fos != null) { 3400 FileUtils.sync(fos); 3401 } 3402 if (cos != null) { 3403 FileUtils.sync(cos); 3404 } 3405 IoUtils.closeQuietly(fos); 3406 IoUtils.closeQuietly(cos); 3407 } 3408 } 3409 } 3410 return false; 3411 } 3412 3413 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)3414 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3415 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 3416 3417 pw.print("mDefaultWallpaperComponent="); pw.println(mDefaultWallpaperComponent); 3418 pw.print("mImageWallpaper="); pw.println(mImageWallpaper); 3419 3420 synchronized (mLock) { 3421 pw.println("System wallpaper state:"); 3422 for (int i = 0; i < mWallpaperMap.size(); i++) { 3423 WallpaperData wallpaper = mWallpaperMap.valueAt(i); 3424 pw.print(" User "); pw.print(wallpaper.userId); 3425 pw.print(": id="); pw.println(wallpaper.wallpaperId); 3426 pw.println(" Display state:"); 3427 forEachDisplayData(wpSize -> { 3428 pw.print(" displayId="); 3429 pw.println(wpSize.mDisplayId); 3430 pw.print(" mWidth="); 3431 pw.print(wpSize.mWidth); 3432 pw.print(" mHeight="); 3433 pw.println(wpSize.mHeight); 3434 pw.print(" mPadding="); pw.println(wpSize.mPadding); 3435 }); 3436 pw.print(" mCropHint="); pw.println(wallpaper.cropHint); 3437 pw.print(" mName="); pw.println(wallpaper.name); 3438 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup); 3439 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent); 3440 if (wallpaper.connection != null) { 3441 WallpaperConnection conn = wallpaper.connection; 3442 pw.print(" Wallpaper connection "); 3443 pw.print(conn); 3444 pw.println(":"); 3445 if (conn.mInfo != null) { 3446 pw.print(" mInfo.component="); 3447 pw.println(conn.mInfo.getComponent()); 3448 } 3449 conn.forEachDisplayConnector(connector -> { 3450 pw.print(" mDisplayId="); 3451 pw.println(connector.mDisplayId); 3452 pw.print(" mToken="); 3453 pw.println(connector.mToken); 3454 pw.print(" mEngine="); 3455 pw.println(connector.mEngine); 3456 }); 3457 pw.print(" mService="); 3458 pw.println(conn.mService); 3459 pw.print(" mLastDiedTime="); 3460 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis()); 3461 } 3462 } 3463 pw.println("Lock wallpaper state:"); 3464 for (int i = 0; i < mLockWallpaperMap.size(); i++) { 3465 WallpaperData wallpaper = mLockWallpaperMap.valueAt(i); 3466 pw.print(" User "); pw.print(wallpaper.userId); 3467 pw.print(": id="); pw.println(wallpaper.wallpaperId); 3468 pw.print(" mCropHint="); pw.println(wallpaper.cropHint); 3469 pw.print(" mName="); pw.println(wallpaper.name); 3470 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup); 3471 } 3472 pw.println("Fallback wallpaper state:"); 3473 pw.print(" User "); pw.print(mFallbackWallpaper.userId); 3474 pw.print(": id="); pw.println(mFallbackWallpaper.wallpaperId); 3475 pw.print(" mCropHint="); pw.println(mFallbackWallpaper.cropHint); 3476 pw.print(" mName="); pw.println(mFallbackWallpaper.name); 3477 pw.print(" mAllowBackup="); pw.println(mFallbackWallpaper.allowBackup); 3478 if (mFallbackWallpaper.connection != null) { 3479 WallpaperConnection conn = mFallbackWallpaper.connection; 3480 pw.print(" Fallback Wallpaper connection "); 3481 pw.print(conn); 3482 pw.println(":"); 3483 if (conn.mInfo != null) { 3484 pw.print(" mInfo.component="); 3485 pw.println(conn.mInfo.getComponent()); 3486 } 3487 conn.forEachDisplayConnector(connector -> { 3488 pw.print(" mDisplayId="); 3489 pw.println(connector.mDisplayId); 3490 pw.print(" mToken="); 3491 pw.println(connector.mToken); 3492 pw.print(" mEngine="); 3493 pw.println(connector.mEngine); 3494 }); 3495 pw.print(" mService="); 3496 pw.println(conn.mService); 3497 pw.print(" mLastDiedTime="); 3498 pw.println(mFallbackWallpaper.lastDiedTime - SystemClock.uptimeMillis()); 3499 } 3500 } 3501 } 3502 } 3503