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