WallpaperManagerService.java revision 9e9e2e73c6ec7bece20268196dc89ad0c8bafad4
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 17package com.android.server.wallpaper; 18 19import static android.os.ParcelFileDescriptor.*; 20 21import android.app.ActivityManagerNative; 22import android.app.AppGlobals; 23import android.app.AppOpsManager; 24import android.app.IUserSwitchObserver; 25import android.app.IWallpaperManager; 26import android.app.IWallpaperManagerCallback; 27import android.app.PendingIntent; 28import android.app.WallpaperInfo; 29import android.app.WallpaperManager; 30import android.app.backup.BackupManager; 31import android.app.backup.WallpaperBackupHelper; 32import android.content.BroadcastReceiver; 33import android.content.ComponentName; 34import android.content.Context; 35import android.content.Intent; 36import android.content.IntentFilter; 37import android.content.ServiceConnection; 38import android.content.pm.IPackageManager; 39import android.content.pm.PackageManager; 40import android.content.pm.ResolveInfo; 41import android.content.pm.ServiceInfo; 42import android.content.pm.PackageManager.NameNotFoundException; 43import android.content.pm.UserInfo; 44import android.content.res.Resources; 45import android.graphics.Point; 46import android.graphics.Rect; 47import android.os.Binder; 48import android.os.Bundle; 49import android.os.Environment; 50import android.os.FileUtils; 51import android.os.IBinder; 52import android.os.IRemoteCallback; 53import android.os.RemoteException; 54import android.os.FileObserver; 55import android.os.ParcelFileDescriptor; 56import android.os.RemoteCallbackList; 57import android.os.SELinux; 58import android.os.ServiceManager; 59import android.os.SystemClock; 60import android.os.UserHandle; 61import android.os.UserManager; 62import android.service.wallpaper.IWallpaperConnection; 63import android.service.wallpaper.IWallpaperEngine; 64import android.service.wallpaper.IWallpaperService; 65import android.service.wallpaper.WallpaperService; 66import android.util.EventLog; 67import android.util.Slog; 68import android.util.SparseArray; 69import android.util.Xml; 70import android.view.Display; 71import android.view.IWindowManager; 72import android.view.WindowManager; 73 74import java.io.FileDescriptor; 75import java.io.IOException; 76import java.io.InputStream; 77import java.io.File; 78import java.io.FileNotFoundException; 79import java.io.FileInputStream; 80import java.io.FileOutputStream; 81import java.io.PrintWriter; 82import java.nio.charset.StandardCharsets; 83import java.util.List; 84 85import org.xmlpull.v1.XmlPullParser; 86import org.xmlpull.v1.XmlPullParserException; 87import org.xmlpull.v1.XmlSerializer; 88 89import com.android.internal.content.PackageMonitor; 90import com.android.internal.util.FastXmlSerializer; 91import com.android.internal.util.JournaledFile; 92import com.android.internal.R; 93import com.android.server.EventLogTags; 94 95public class WallpaperManagerService extends IWallpaperManager.Stub { 96 static final String TAG = "WallpaperManagerService"; 97 static final boolean DEBUG = false; 98 99 final Object mLock = new Object[0]; 100 101 /** 102 * Minimum time between crashes of a wallpaper service for us to consider 103 * restarting it vs. just reverting to the static wallpaper. 104 */ 105 static final long MIN_WALLPAPER_CRASH_TIME = 10000; 106 static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128; 107 static final String WALLPAPER = "wallpaper"; 108 static final String WALLPAPER_INFO = "wallpaper_info.xml"; 109 110 /** 111 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks 112 * that the wallpaper has changed. The CREATE is triggered when there is no 113 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered 114 * everytime the wallpaper is changed. 115 */ 116 private class WallpaperObserver extends FileObserver { 117 118 final WallpaperData mWallpaper; 119 final File mWallpaperDir; 120 final File mWallpaperFile; 121 final File mWallpaperInfoFile; 122 123 public WallpaperObserver(WallpaperData wallpaper) { 124 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(), 125 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF); 126 mWallpaperDir = getWallpaperDir(wallpaper.userId); 127 mWallpaper = wallpaper; 128 mWallpaperFile = new File(mWallpaperDir, WALLPAPER); 129 mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO); 130 } 131 132 @Override 133 public void onEvent(int event, String path) { 134 if (path == null) { 135 return; 136 } 137 synchronized (mLock) { 138 File changedFile = new File(mWallpaperDir, path); 139 if (mWallpaperFile.equals(changedFile) 140 || mWallpaperInfoFile.equals(changedFile)) { 141 // changing the wallpaper means we'll need to back up the new one 142 long origId = Binder.clearCallingIdentity(); 143 BackupManager bm = new BackupManager(mContext); 144 bm.dataChanged(); 145 Binder.restoreCallingIdentity(origId); 146 } 147 if (mWallpaperFile.equals(changedFile)) { 148 notifyCallbacksLocked(mWallpaper); 149 final boolean written = (event == CLOSE_WRITE || event == MOVED_TO); 150 if (mWallpaper.wallpaperComponent == null 151 || event != CLOSE_WRITE // includes the MOVED_TO case 152 || mWallpaper.imageWallpaperPending) { 153 if (written) { 154 mWallpaper.imageWallpaperPending = false; 155 } 156 bindWallpaperComponentLocked(mImageWallpaper, true, 157 false, mWallpaper, null); 158 saveSettingsLocked(mWallpaper); 159 } 160 } 161 } 162 } 163 } 164 165 final Context mContext; 166 final IWindowManager mIWindowManager; 167 final IPackageManager mIPackageManager; 168 final MyPackageMonitor mMonitor; 169 final AppOpsManager mAppOpsManager; 170 WallpaperData mLastWallpaper; 171 172 /** 173 * Name of the component used to display bitmap wallpapers from either the gallery or 174 * built-in wallpapers. 175 */ 176 final ComponentName mImageWallpaper; 177 178 SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>(); 179 180 int mCurrentUserId; 181 182 static class WallpaperData { 183 184 int userId; 185 186 File wallpaperFile; 187 188 /** 189 * Client is currently writing a new image wallpaper. 190 */ 191 boolean imageWallpaperPending; 192 193 /** 194 * Resource name if using a picture from the wallpaper gallery 195 */ 196 String name = ""; 197 198 /** 199 * The component name of the currently set live wallpaper. 200 */ 201 ComponentName wallpaperComponent; 202 203 /** 204 * The component name of the wallpaper that should be set next. 205 */ 206 ComponentName nextWallpaperComponent; 207 208 WallpaperConnection connection; 209 long lastDiedTime; 210 boolean wallpaperUpdating; 211 WallpaperObserver wallpaperObserver; 212 213 /** 214 * List of callbacks registered they should each be notified when the wallpaper is changed. 215 */ 216 private RemoteCallbackList<IWallpaperManagerCallback> callbacks 217 = new RemoteCallbackList<IWallpaperManagerCallback>(); 218 219 int width = -1; 220 int height = -1; 221 222 final Rect padding = new Rect(0, 0, 0, 0); 223 224 WallpaperData(int userId) { 225 this.userId = userId; 226 wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); 227 } 228 } 229 230 class WallpaperConnection extends IWallpaperConnection.Stub 231 implements ServiceConnection { 232 final WallpaperInfo mInfo; 233 final Binder mToken = new Binder(); 234 IWallpaperService mService; 235 IWallpaperEngine mEngine; 236 WallpaperData mWallpaper; 237 IRemoteCallback mReply; 238 239 boolean mDimensionsChanged = false; 240 boolean mPaddingChanged = false; 241 242 public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) { 243 mInfo = info; 244 mWallpaper = wallpaper; 245 } 246 247 @Override 248 public void onServiceConnected(ComponentName name, IBinder service) { 249 synchronized (mLock) { 250 if (mWallpaper.connection == this) { 251 mService = IWallpaperService.Stub.asInterface(service); 252 attachServiceLocked(this, mWallpaper); 253 // XXX should probably do saveSettingsLocked() later 254 // when we have an engine, but I'm not sure about 255 // locking there and anyway we always need to be able to 256 // recover if there is something wrong. 257 saveSettingsLocked(mWallpaper); 258 } 259 } 260 } 261 262 @Override 263 public void onServiceDisconnected(ComponentName name) { 264 synchronized (mLock) { 265 mService = null; 266 mEngine = null; 267 if (mWallpaper.connection == this) { 268 Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent); 269 if (!mWallpaper.wallpaperUpdating 270 && mWallpaper.userId == mCurrentUserId) { 271 // There is a race condition which causes 272 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is 273 // currently updating since the broadcast notifying us is async. 274 // This race is overcome by the general rule that we only reset the 275 // wallpaper if its service was shut down twice 276 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis. 277 if (mWallpaper.lastDiedTime != 0 278 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME 279 > SystemClock.uptimeMillis()) { 280 Slog.w(TAG, "Reverting to built-in wallpaper!"); 281 clearWallpaperLocked(true, mWallpaper.userId, null); 282 } else { 283 mWallpaper.lastDiedTime = SystemClock.uptimeMillis(); 284 } 285 final String flattened = name.flattenToString(); 286 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED, 287 flattened.substring(0, Math.min(flattened.length(), 288 MAX_WALLPAPER_COMPONENT_LOG_LENGTH))); 289 } 290 } 291 } 292 } 293 294 @Override 295 public void attachEngine(IWallpaperEngine engine) { 296 synchronized (mLock) { 297 mEngine = engine; 298 if (mDimensionsChanged) { 299 try { 300 mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height); 301 } catch (RemoteException e) { 302 Slog.w(TAG, "Failed to set wallpaper dimensions", e); 303 } 304 mDimensionsChanged = false; 305 } 306 if (mPaddingChanged) { 307 try { 308 mEngine.setDisplayPadding(mWallpaper.padding); 309 } catch (RemoteException e) { 310 Slog.w(TAG, "Failed to set wallpaper padding", e); 311 } 312 mPaddingChanged = false; 313 } 314 } 315 } 316 317 @Override 318 public void engineShown(IWallpaperEngine engine) { 319 synchronized (mLock) { 320 if (mReply != null) { 321 long ident = Binder.clearCallingIdentity(); 322 try { 323 mReply.sendResult(null); 324 } catch (RemoteException e) { 325 Binder.restoreCallingIdentity(ident); 326 } 327 mReply = null; 328 } 329 } 330 } 331 332 @Override 333 public ParcelFileDescriptor setWallpaper(String name) { 334 synchronized (mLock) { 335 if (mWallpaper.connection == this) { 336 return updateWallpaperBitmapLocked(name, mWallpaper); 337 } 338 return null; 339 } 340 } 341 } 342 343 class MyPackageMonitor extends PackageMonitor { 344 @Override 345 public void onPackageUpdateFinished(String packageName, int uid) { 346 synchronized (mLock) { 347 if (mCurrentUserId != getChangingUserId()) { 348 return; 349 } 350 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 351 if (wallpaper != null) { 352 if (wallpaper.wallpaperComponent != null 353 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { 354 wallpaper.wallpaperUpdating = false; 355 ComponentName comp = wallpaper.wallpaperComponent; 356 clearWallpaperComponentLocked(wallpaper); 357 if (!bindWallpaperComponentLocked(comp, false, false, 358 wallpaper, null)) { 359 Slog.w(TAG, "Wallpaper no longer available; reverting to default"); 360 clearWallpaperLocked(false, wallpaper.userId, null); 361 } 362 } 363 } 364 } 365 } 366 367 @Override 368 public void onPackageModified(String packageName) { 369 synchronized (mLock) { 370 if (mCurrentUserId != getChangingUserId()) { 371 return; 372 } 373 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 374 if (wallpaper != null) { 375 if (wallpaper.wallpaperComponent == null 376 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { 377 return; 378 } 379 doPackagesChangedLocked(true, wallpaper); 380 } 381 } 382 } 383 384 @Override 385 public void onPackageUpdateStarted(String packageName, int uid) { 386 synchronized (mLock) { 387 if (mCurrentUserId != getChangingUserId()) { 388 return; 389 } 390 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 391 if (wallpaper != null) { 392 if (wallpaper.wallpaperComponent != null 393 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { 394 wallpaper.wallpaperUpdating = true; 395 } 396 } 397 } 398 } 399 400 @Override 401 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 402 synchronized (mLock) { 403 boolean changed = false; 404 if (mCurrentUserId != getChangingUserId()) { 405 return false; 406 } 407 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 408 if (wallpaper != null) { 409 boolean res = doPackagesChangedLocked(doit, wallpaper); 410 changed |= res; 411 } 412 return changed; 413 } 414 } 415 416 @Override 417 public void onSomePackagesChanged() { 418 synchronized (mLock) { 419 if (mCurrentUserId != getChangingUserId()) { 420 return; 421 } 422 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); 423 if (wallpaper != null) { 424 doPackagesChangedLocked(true, wallpaper); 425 } 426 } 427 } 428 429 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) { 430 boolean changed = false; 431 if (wallpaper.wallpaperComponent != null) { 432 int change = isPackageDisappearing(wallpaper.wallpaperComponent 433 .getPackageName()); 434 if (change == PACKAGE_PERMANENT_CHANGE 435 || change == PACKAGE_TEMPORARY_CHANGE) { 436 changed = true; 437 if (doit) { 438 Slog.w(TAG, "Wallpaper uninstalled, removing: " 439 + wallpaper.wallpaperComponent); 440 clearWallpaperLocked(false, wallpaper.userId, null); 441 } 442 } 443 } 444 if (wallpaper.nextWallpaperComponent != null) { 445 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent 446 .getPackageName()); 447 if (change == PACKAGE_PERMANENT_CHANGE 448 || change == PACKAGE_TEMPORARY_CHANGE) { 449 wallpaper.nextWallpaperComponent = null; 450 } 451 } 452 if (wallpaper.wallpaperComponent != null 453 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) { 454 try { 455 mContext.getPackageManager().getServiceInfo( 456 wallpaper.wallpaperComponent, 0); 457 } catch (NameNotFoundException e) { 458 Slog.w(TAG, "Wallpaper component gone, removing: " 459 + wallpaper.wallpaperComponent); 460 clearWallpaperLocked(false, wallpaper.userId, null); 461 } 462 } 463 if (wallpaper.nextWallpaperComponent != null 464 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) { 465 try { 466 mContext.getPackageManager().getServiceInfo( 467 wallpaper.nextWallpaperComponent, 0); 468 } catch (NameNotFoundException e) { 469 wallpaper.nextWallpaperComponent = null; 470 } 471 } 472 return changed; 473 } 474 } 475 476 public WallpaperManagerService(Context context) { 477 if (DEBUG) Slog.v(TAG, "WallpaperService startup"); 478 mContext = context; 479 mImageWallpaper = ComponentName.unflattenFromString( 480 context.getResources().getString(R.string.image_wallpaper_component)); 481 mIWindowManager = IWindowManager.Stub.asInterface( 482 ServiceManager.getService(Context.WINDOW_SERVICE)); 483 mIPackageManager = AppGlobals.getPackageManager(); 484 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 485 mMonitor = new MyPackageMonitor(); 486 mMonitor.register(context, null, UserHandle.ALL, true); 487 getWallpaperDir(UserHandle.USER_OWNER).mkdirs(); 488 loadSettingsLocked(UserHandle.USER_OWNER); 489 } 490 491 private static File getWallpaperDir(int userId) { 492 return Environment.getUserSystemDirectory(userId); 493 } 494 495 @Override 496 protected void finalize() throws Throwable { 497 super.finalize(); 498 for (int i = 0; i < mWallpaperMap.size(); i++) { 499 WallpaperData wallpaper = mWallpaperMap.valueAt(i); 500 wallpaper.wallpaperObserver.stopWatching(); 501 } 502 } 503 504 public void systemRunning() { 505 if (DEBUG) Slog.v(TAG, "systemReady"); 506 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER); 507 switchWallpaper(wallpaper, null); 508 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper); 509 wallpaper.wallpaperObserver.startWatching(); 510 511 IntentFilter userFilter = new IntentFilter(); 512 userFilter.addAction(Intent.ACTION_USER_REMOVED); 513 userFilter.addAction(Intent.ACTION_USER_STOPPING); 514 mContext.registerReceiver(new BroadcastReceiver() { 515 @Override 516 public void onReceive(Context context, Intent intent) { 517 String action = intent.getAction(); 518 if (Intent.ACTION_USER_REMOVED.equals(action)) { 519 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 520 UserHandle.USER_NULL)); 521 } 522 // TODO: Race condition causing problems when cleaning up on stopping a user. 523 // Comment this out for now. 524 // else if (Intent.ACTION_USER_STOPPING.equals(action)) { 525 // onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 526 // UserHandle.USER_NULL)); 527 // } 528 } 529 }, userFilter); 530 531 try { 532 ActivityManagerNative.getDefault().registerUserSwitchObserver( 533 new IUserSwitchObserver.Stub() { 534 @Override 535 public void onUserSwitching(int newUserId, IRemoteCallback reply) { 536 switchUser(newUserId, reply); 537 } 538 539 @Override 540 public void onUserSwitchComplete(int newUserId) throws RemoteException { 541 } 542 543 @Override 544 public void onForegroundProfileSwitch(int newProfileId) { 545 // Ignore. 546 } 547 }); 548 } catch (RemoteException e) { 549 // TODO Auto-generated catch block 550 e.printStackTrace(); 551 } 552 } 553 554 /** Called by SystemBackupAgent */ 555 public String getName() { 556 // Verify caller is the system 557 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 558 throw new RuntimeException("getName() can only be called from the system process"); 559 } 560 synchronized (mLock) { 561 return mWallpaperMap.get(0).name; 562 } 563 } 564 565 void onStoppingUser(int userId) { 566 if (userId < 1) return; 567 synchronized (mLock) { 568 WallpaperData wallpaper = mWallpaperMap.get(userId); 569 if (wallpaper != null) { 570 if (wallpaper.wallpaperObserver != null) { 571 wallpaper.wallpaperObserver.stopWatching(); 572 wallpaper.wallpaperObserver = null; 573 } 574 mWallpaperMap.remove(userId); 575 } 576 } 577 } 578 579 void onRemoveUser(int userId) { 580 if (userId < 1) return; 581 synchronized (mLock) { 582 onStoppingUser(userId); 583 File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); 584 wallpaperFile.delete(); 585 File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO); 586 wallpaperInfoFile.delete(); 587 } 588 } 589 590 void switchUser(int userId, IRemoteCallback reply) { 591 synchronized (mLock) { 592 mCurrentUserId = userId; 593 WallpaperData wallpaper = mWallpaperMap.get(userId); 594 if (wallpaper == null) { 595 wallpaper = new WallpaperData(userId); 596 mWallpaperMap.put(userId, wallpaper); 597 loadSettingsLocked(userId); 598 } 599 // Not started watching yet, in case wallpaper data was loaded for other reasons. 600 if (wallpaper.wallpaperObserver == null) { 601 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper); 602 wallpaper.wallpaperObserver.startWatching(); 603 } 604 switchWallpaper(wallpaper, reply); 605 } 606 } 607 608 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) { 609 synchronized (mLock) { 610 RuntimeException e = null; 611 try { 612 ComponentName cname = wallpaper.wallpaperComponent != null ? 613 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent; 614 if (bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) { 615 return; 616 } 617 } catch (RuntimeException e1) { 618 e = e1; 619 } 620 Slog.w(TAG, "Failure starting previous wallpaper", e); 621 clearWallpaperLocked(false, wallpaper.userId, reply); 622 } 623 } 624 625 public void clearWallpaper(String callingPackage) { 626 if (DEBUG) Slog.v(TAG, "clearWallpaper"); 627 checkPermission(android.Manifest.permission.SET_WALLPAPER); 628 if (!isWallpaperSupported(callingPackage)) { 629 return; 630 } 631 synchronized (mLock) { 632 clearWallpaperLocked(false, UserHandle.getCallingUserId(), null); 633 } 634 } 635 636 void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) { 637 WallpaperData wallpaper = mWallpaperMap.get(userId); 638 if (wallpaper == null) { 639 return; 640 } 641 File f = new File(getWallpaperDir(userId), WALLPAPER); 642 if (f.exists()) { 643 f.delete(); 644 } 645 final long ident = Binder.clearCallingIdentity(); 646 try { 647 RuntimeException e = null; 648 try { 649 wallpaper.imageWallpaperPending = false; 650 if (userId != mCurrentUserId) return; 651 if (bindWallpaperComponentLocked(defaultFailed 652 ? mImageWallpaper 653 : null, true, false, wallpaper, reply)) { 654 return; 655 } 656 } catch (IllegalArgumentException e1) { 657 e = e1; 658 } 659 660 // This can happen if the default wallpaper component doesn't 661 // exist. This should be a system configuration problem, but 662 // let's not let it crash the system and just live with no 663 // wallpaper. 664 Slog.e(TAG, "Default wallpaper component not found!", e); 665 clearWallpaperComponentLocked(wallpaper); 666 if (reply != null) { 667 try { 668 reply.sendResult(null); 669 } catch (RemoteException e1) { 670 } 671 } 672 } finally { 673 Binder.restoreCallingIdentity(ident); 674 } 675 } 676 677 public boolean hasNamedWallpaper(String name) { 678 synchronized (mLock) { 679 List<UserInfo> users; 680 long ident = Binder.clearCallingIdentity(); 681 try { 682 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers(); 683 } finally { 684 Binder.restoreCallingIdentity(ident); 685 } 686 for (UserInfo user: users) { 687 // ignore managed profiles 688 if (user.isManagedProfile()) { 689 continue; 690 } 691 WallpaperData wd = mWallpaperMap.get(user.id); 692 if (wd == null) { 693 // User hasn't started yet, so load her settings to peek at the wallpaper 694 loadSettingsLocked(user.id); 695 wd = mWallpaperMap.get(user.id); 696 } 697 if (wd != null && name.equals(wd.name)) { 698 return true; 699 } 700 } 701 } 702 return false; 703 } 704 705 private Point getDefaultDisplaySize() { 706 Point p = new Point(); 707 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); 708 Display d = wm.getDefaultDisplay(); 709 d.getRealSize(p); 710 return p; 711 } 712 713 public void setDimensionHints(int width, int height, String callingPackage) 714 throws RemoteException { 715 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 716 if (!isWallpaperSupported(callingPackage)) { 717 return; 718 } 719 synchronized (mLock) { 720 int userId = UserHandle.getCallingUserId(); 721 WallpaperData wallpaper = mWallpaperMap.get(userId); 722 if (wallpaper == null) { 723 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); 724 } 725 if (width <= 0 || height <= 0) { 726 throw new IllegalArgumentException("width and height must be > 0"); 727 } 728 // Make sure it is at least as large as the display. 729 Point displaySize = getDefaultDisplaySize(); 730 width = Math.max(width, displaySize.x); 731 height = Math.max(height, displaySize.y); 732 733 if (width != wallpaper.width || height != wallpaper.height) { 734 wallpaper.width = width; 735 wallpaper.height = height; 736 saveSettingsLocked(wallpaper); 737 if (mCurrentUserId != userId) return; // Don't change the properties now 738 if (wallpaper.connection != null) { 739 if (wallpaper.connection.mEngine != null) { 740 try { 741 wallpaper.connection.mEngine.setDesiredSize( 742 width, height); 743 } catch (RemoteException e) { 744 } 745 notifyCallbacksLocked(wallpaper); 746 } else if (wallpaper.connection.mService != null) { 747 // We've attached to the service but the engine hasn't attached back to us 748 // yet. This means it will be created with the previous dimensions, so we 749 // need to update it to the new dimensions once it attaches. 750 wallpaper.connection.mDimensionsChanged = true; 751 } 752 } 753 } 754 } 755 } 756 757 public int getWidthHint() throws RemoteException { 758 synchronized (mLock) { 759 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); 760 if (wallpaper != null) { 761 return wallpaper.width; 762 } else { 763 return 0; 764 } 765 } 766 } 767 768 public int getHeightHint() throws RemoteException { 769 synchronized (mLock) { 770 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId()); 771 if (wallpaper != null) { 772 return wallpaper.height; 773 } else { 774 return 0; 775 } 776 } 777 } 778 779 public void setDisplayPadding(Rect padding, String callingPackage) { 780 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 781 if (!isWallpaperSupported(callingPackage)) { 782 return; 783 } 784 synchronized (mLock) { 785 int userId = UserHandle.getCallingUserId(); 786 WallpaperData wallpaper = mWallpaperMap.get(userId); 787 if (wallpaper == null) { 788 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); 789 } 790 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) { 791 throw new IllegalArgumentException("padding must be positive: " + padding); 792 } 793 794 if (!padding.equals(wallpaper.padding)) { 795 wallpaper.padding.set(padding); 796 saveSettingsLocked(wallpaper); 797 if (mCurrentUserId != userId) return; // Don't change the properties now 798 if (wallpaper.connection != null) { 799 if (wallpaper.connection.mEngine != null) { 800 try { 801 wallpaper.connection.mEngine.setDisplayPadding(padding); 802 } catch (RemoteException e) { 803 } 804 notifyCallbacksLocked(wallpaper); 805 } else if (wallpaper.connection.mService != null) { 806 // We've attached to the service but the engine hasn't attached back to us 807 // yet. This means it will be created with the previous dimensions, so we 808 // need to update it to the new dimensions once it attaches. 809 wallpaper.connection.mPaddingChanged = true; 810 } 811 } 812 } 813 } 814 } 815 816 public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, 817 Bundle outParams) { 818 synchronized (mLock) { 819 // This returns the current user's wallpaper, if called by a system service. Else it 820 // returns the wallpaper for the calling user. 821 int callingUid = Binder.getCallingUid(); 822 int wallpaperUserId = 0; 823 if (callingUid == android.os.Process.SYSTEM_UID) { 824 wallpaperUserId = mCurrentUserId; 825 } else { 826 wallpaperUserId = UserHandle.getUserId(callingUid); 827 } 828 WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId); 829 if (wallpaper == null) { 830 return null; 831 } 832 try { 833 if (outParams != null) { 834 outParams.putInt("width", wallpaper.width); 835 outParams.putInt("height", wallpaper.height); 836 } 837 wallpaper.callbacks.register(cb); 838 File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER); 839 if (!f.exists()) { 840 return null; 841 } 842 return ParcelFileDescriptor.open(f, MODE_READ_ONLY); 843 } catch (FileNotFoundException e) { 844 /* Shouldn't happen as we check to see if the file exists */ 845 Slog.w(TAG, "Error getting wallpaper", e); 846 } 847 return null; 848 } 849 } 850 851 public WallpaperInfo getWallpaperInfo() { 852 int userId = UserHandle.getCallingUserId(); 853 synchronized (mLock) { 854 WallpaperData wallpaper = mWallpaperMap.get(userId); 855 if (wallpaper != null && wallpaper.connection != null) { 856 return wallpaper.connection.mInfo; 857 } 858 return null; 859 } 860 } 861 862 public ParcelFileDescriptor setWallpaper(String name, String callingPackage) { 863 checkPermission(android.Manifest.permission.SET_WALLPAPER); 864 if (!isWallpaperSupported(callingPackage)) { 865 return null; 866 } 867 synchronized (mLock) { 868 if (DEBUG) Slog.v(TAG, "setWallpaper"); 869 int userId = UserHandle.getCallingUserId(); 870 WallpaperData wallpaper = mWallpaperMap.get(userId); 871 if (wallpaper == null) { 872 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); 873 } 874 final long ident = Binder.clearCallingIdentity(); 875 try { 876 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper); 877 if (pfd != null) { 878 wallpaper.imageWallpaperPending = true; 879 } 880 return pfd; 881 } finally { 882 Binder.restoreCallingIdentity(ident); 883 } 884 } 885 } 886 887 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) { 888 if (name == null) name = ""; 889 try { 890 File dir = getWallpaperDir(wallpaper.userId); 891 if (!dir.exists()) { 892 dir.mkdir(); 893 FileUtils.setPermissions( 894 dir.getPath(), 895 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, 896 -1, -1); 897 } 898 File file = new File(dir, WALLPAPER); 899 ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, 900 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE); 901 if (!SELinux.restorecon(file)) { 902 return null; 903 } 904 wallpaper.name = name; 905 return fd; 906 } catch (FileNotFoundException e) { 907 Slog.w(TAG, "Error setting wallpaper", e); 908 } 909 return null; 910 } 911 912 public void setWallpaperComponentChecked(ComponentName name, String callingPackage) { 913 if (isWallpaperSupported(callingPackage)) { 914 setWallpaperComponent(name); 915 } 916 } 917 918 // ToDo: Remove this version of the function 919 public void setWallpaperComponent(ComponentName name) { 920 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); 921 synchronized (mLock) { 922 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name); 923 int userId = UserHandle.getCallingUserId(); 924 WallpaperData wallpaper = mWallpaperMap.get(userId); 925 if (wallpaper == null) { 926 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId); 927 } 928 final long ident = Binder.clearCallingIdentity(); 929 try { 930 wallpaper.imageWallpaperPending = false; 931 bindWallpaperComponentLocked(name, false, true, wallpaper, null); 932 } finally { 933 Binder.restoreCallingIdentity(ident); 934 } 935 } 936 } 937 938 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, 939 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { 940 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); 941 // Has the component changed? 942 if (!force) { 943 if (wallpaper.connection != null) { 944 if (wallpaper.wallpaperComponent == null) { 945 if (componentName == null) { 946 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default"); 947 // Still using default wallpaper. 948 return true; 949 } 950 } else if (wallpaper.wallpaperComponent.equals(componentName)) { 951 // Changing to same wallpaper. 952 if (DEBUG) Slog.v(TAG, "same wallpaper"); 953 return true; 954 } 955 } 956 } 957 958 try { 959 if (componentName == null) { 960 componentName = WallpaperManager.getDefaultWallpaperComponent(mContext); 961 if (componentName == null) { 962 // Fall back to static image wallpaper 963 componentName = mImageWallpaper; 964 //clearWallpaperComponentLocked(); 965 //return; 966 if (DEBUG) Slog.v(TAG, "Using image wallpaper"); 967 } 968 } 969 int serviceUserId = wallpaper.userId; 970 ServiceInfo si = mIPackageManager.getServiceInfo(componentName, 971 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId); 972 if (si == null) { 973 // The wallpaper component we're trying to use doesn't exist 974 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable"); 975 return false; 976 } 977 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) { 978 String msg = "Selected service does not require " 979 + android.Manifest.permission.BIND_WALLPAPER 980 + ": " + componentName; 981 if (fromUser) { 982 throw new SecurityException(msg); 983 } 984 Slog.w(TAG, msg); 985 return false; 986 } 987 988 WallpaperInfo wi = null; 989 990 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); 991 if (componentName != null && !componentName.equals(mImageWallpaper)) { 992 // Make sure the selected service is actually a wallpaper service. 993 List<ResolveInfo> ris = 994 mIPackageManager.queryIntentServices(intent, 995 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 996 PackageManager.GET_META_DATA, serviceUserId); 997 for (int i=0; i<ris.size(); i++) { 998 ServiceInfo rsi = ris.get(i).serviceInfo; 999 if (rsi.name.equals(si.name) && 1000 rsi.packageName.equals(si.packageName)) { 1001 try { 1002 wi = new WallpaperInfo(mContext, ris.get(i)); 1003 } catch (XmlPullParserException e) { 1004 if (fromUser) { 1005 throw new IllegalArgumentException(e); 1006 } 1007 Slog.w(TAG, e); 1008 return false; 1009 } catch (IOException e) { 1010 if (fromUser) { 1011 throw new IllegalArgumentException(e); 1012 } 1013 Slog.w(TAG, e); 1014 return false; 1015 } 1016 break; 1017 } 1018 } 1019 if (wi == null) { 1020 String msg = "Selected service is not a wallpaper: " 1021 + componentName; 1022 if (fromUser) { 1023 throw new SecurityException(msg); 1024 } 1025 Slog.w(TAG, msg); 1026 return false; 1027 } 1028 } 1029 1030 // Bind the service! 1031 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName); 1032 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper); 1033 intent.setComponent(componentName); 1034 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, 1035 com.android.internal.R.string.wallpaper_binding_label); 1036 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser( 1037 mContext, 0, 1038 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), 1039 mContext.getText(com.android.internal.R.string.chooser_wallpaper)), 1040 0, null, new UserHandle(serviceUserId))); 1041 if (!mContext.bindServiceAsUser(intent, newConn, 1042 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI 1043 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, 1044 new UserHandle(serviceUserId))) { 1045 String msg = "Unable to bind service: " 1046 + componentName; 1047 if (fromUser) { 1048 throw new IllegalArgumentException(msg); 1049 } 1050 Slog.w(TAG, msg); 1051 return false; 1052 } 1053 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) { 1054 detachWallpaperLocked(mLastWallpaper); 1055 } 1056 wallpaper.wallpaperComponent = componentName; 1057 wallpaper.connection = newConn; 1058 newConn.mReply = reply; 1059 try { 1060 if (wallpaper.userId == mCurrentUserId) { 1061 if (DEBUG) 1062 Slog.v(TAG, "Adding window token: " + newConn.mToken); 1063 mIWindowManager.addWindowToken(newConn.mToken, 1064 WindowManager.LayoutParams.TYPE_WALLPAPER); 1065 mLastWallpaper = wallpaper; 1066 } 1067 } catch (RemoteException e) { 1068 } 1069 } catch (RemoteException e) { 1070 String msg = "Remote exception for " + componentName + "\n" + e; 1071 if (fromUser) { 1072 throw new IllegalArgumentException(msg); 1073 } 1074 Slog.w(TAG, msg); 1075 return false; 1076 } 1077 return true; 1078 } 1079 1080 void detachWallpaperLocked(WallpaperData wallpaper) { 1081 if (wallpaper.connection != null) { 1082 if (wallpaper.connection.mReply != null) { 1083 try { 1084 wallpaper.connection.mReply.sendResult(null); 1085 } catch (RemoteException e) { 1086 } 1087 wallpaper.connection.mReply = null; 1088 } 1089 if (wallpaper.connection.mEngine != null) { 1090 try { 1091 wallpaper.connection.mEngine.destroy(); 1092 } catch (RemoteException e) { 1093 } 1094 } 1095 mContext.unbindService(wallpaper.connection); 1096 try { 1097 if (DEBUG) 1098 Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken); 1099 mIWindowManager.removeWindowToken(wallpaper.connection.mToken); 1100 } catch (RemoteException e) { 1101 } 1102 wallpaper.connection.mService = null; 1103 wallpaper.connection.mEngine = null; 1104 wallpaper.connection = null; 1105 } 1106 } 1107 1108 void clearWallpaperComponentLocked(WallpaperData wallpaper) { 1109 wallpaper.wallpaperComponent = null; 1110 detachWallpaperLocked(wallpaper); 1111 } 1112 1113 void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) { 1114 try { 1115 conn.mService.attach(conn, conn.mToken, 1116 WindowManager.LayoutParams.TYPE_WALLPAPER, false, 1117 wallpaper.width, wallpaper.height, wallpaper.padding); 1118 } catch (RemoteException e) { 1119 Slog.w(TAG, "Failed attaching wallpaper; clearing", e); 1120 if (!wallpaper.wallpaperUpdating) { 1121 bindWallpaperComponentLocked(null, false, false, wallpaper, null); 1122 } 1123 } 1124 } 1125 1126 private void notifyCallbacksLocked(WallpaperData wallpaper) { 1127 final int n = wallpaper.callbacks.beginBroadcast(); 1128 for (int i = 0; i < n; i++) { 1129 try { 1130 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged(); 1131 } catch (RemoteException e) { 1132 1133 // The RemoteCallbackList will take care of removing 1134 // the dead object for us. 1135 } 1136 } 1137 wallpaper.callbacks.finishBroadcast(); 1138 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 1139 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId)); 1140 } 1141 1142 private void checkPermission(String permission) { 1143 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) { 1144 throw new SecurityException("Access denied to process: " + Binder.getCallingPid() 1145 + ", must have permission " + permission); 1146 } 1147 } 1148 1149 /** 1150 * Certain user types do not support wallpapers (e.g. managed profiles). The check is 1151 * implemented through through the OP_WRITE_WALLPAPER AppOp. 1152 */ 1153 public boolean isWallpaperSupported(String callingPackage) { 1154 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(), 1155 callingPackage) == AppOpsManager.MODE_ALLOWED; 1156 } 1157 1158 private static JournaledFile makeJournaledFile(int userId) { 1159 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath(); 1160 return new JournaledFile(new File(base), new File(base + ".tmp")); 1161 } 1162 1163 private void saveSettingsLocked(WallpaperData wallpaper) { 1164 JournaledFile journal = makeJournaledFile(wallpaper.userId); 1165 FileOutputStream stream = null; 1166 try { 1167 stream = new FileOutputStream(journal.chooseForWrite(), false); 1168 XmlSerializer out = new FastXmlSerializer(); 1169 out.setOutput(stream, StandardCharsets.UTF_8.name()); 1170 out.startDocument(null, true); 1171 1172 out.startTag(null, "wp"); 1173 out.attribute(null, "width", Integer.toString(wallpaper.width)); 1174 out.attribute(null, "height", Integer.toString(wallpaper.height)); 1175 if (wallpaper.padding.left != 0) { 1176 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left)); 1177 } 1178 if (wallpaper.padding.top != 0) { 1179 out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top)); 1180 } 1181 if (wallpaper.padding.right != 0) { 1182 out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right)); 1183 } 1184 if (wallpaper.padding.bottom != 0) { 1185 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom)); 1186 } 1187 out.attribute(null, "name", wallpaper.name); 1188 if (wallpaper.wallpaperComponent != null 1189 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) { 1190 out.attribute(null, "component", 1191 wallpaper.wallpaperComponent.flattenToShortString()); 1192 } 1193 out.endTag(null, "wp"); 1194 1195 out.endDocument(); 1196 stream.flush(); 1197 FileUtils.sync(stream); 1198 stream.close(); 1199 journal.commit(); 1200 } catch (IOException e) { 1201 try { 1202 if (stream != null) { 1203 stream.close(); 1204 } 1205 } catch (IOException ex) { 1206 // Ignore 1207 } 1208 journal.rollback(); 1209 } 1210 } 1211 1212 private void migrateFromOld() { 1213 File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY); 1214 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY); 1215 if (oldWallpaper.exists()) { 1216 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER); 1217 oldWallpaper.renameTo(newWallpaper); 1218 } 1219 if (oldInfo.exists()) { 1220 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO); 1221 oldInfo.renameTo(newInfo); 1222 } 1223 } 1224 1225 private int getAttributeInt(XmlPullParser parser, String name, int defValue) { 1226 String value = parser.getAttributeValue(null, name); 1227 if (value == null) { 1228 return defValue; 1229 } 1230 return Integer.parseInt(value); 1231 } 1232 1233 private void loadSettingsLocked(int userId) { 1234 if (DEBUG) Slog.v(TAG, "loadSettingsLocked"); 1235 1236 JournaledFile journal = makeJournaledFile(userId); 1237 FileInputStream stream = null; 1238 File file = journal.chooseForRead(); 1239 if (!file.exists()) { 1240 // This should only happen one time, when upgrading from a legacy system 1241 migrateFromOld(); 1242 } 1243 WallpaperData wallpaper = mWallpaperMap.get(userId); 1244 if (wallpaper == null) { 1245 wallpaper = new WallpaperData(userId); 1246 mWallpaperMap.put(userId, wallpaper); 1247 } 1248 boolean success = false; 1249 try { 1250 stream = new FileInputStream(file); 1251 XmlPullParser parser = Xml.newPullParser(); 1252 parser.setInput(stream, StandardCharsets.UTF_8.name()); 1253 1254 int type; 1255 do { 1256 type = parser.next(); 1257 if (type == XmlPullParser.START_TAG) { 1258 String tag = parser.getName(); 1259 if ("wp".equals(tag)) { 1260 wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width")); 1261 wallpaper.height = Integer.parseInt(parser 1262 .getAttributeValue(null, "height")); 1263 wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0); 1264 wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0); 1265 wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0); 1266 wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0); 1267 wallpaper.name = parser.getAttributeValue(null, "name"); 1268 String comp = parser.getAttributeValue(null, "component"); 1269 wallpaper.nextWallpaperComponent = comp != null 1270 ? ComponentName.unflattenFromString(comp) 1271 : null; 1272 if (wallpaper.nextWallpaperComponent == null 1273 || "android".equals(wallpaper.nextWallpaperComponent 1274 .getPackageName())) { 1275 wallpaper.nextWallpaperComponent = mImageWallpaper; 1276 } 1277 1278 if (DEBUG) { 1279 Slog.v(TAG, "mWidth:" + wallpaper.width); 1280 Slog.v(TAG, "mHeight:" + wallpaper.height); 1281 Slog.v(TAG, "mName:" + wallpaper.name); 1282 Slog.v(TAG, "mNextWallpaperComponent:" 1283 + wallpaper.nextWallpaperComponent); 1284 } 1285 } 1286 } 1287 } while (type != XmlPullParser.END_DOCUMENT); 1288 success = true; 1289 } catch (FileNotFoundException e) { 1290 Slog.w(TAG, "no current wallpaper -- first boot?"); 1291 } catch (NullPointerException e) { 1292 Slog.w(TAG, "failed parsing " + file + " " + e); 1293 } catch (NumberFormatException e) { 1294 Slog.w(TAG, "failed parsing " + file + " " + e); 1295 } catch (XmlPullParserException e) { 1296 Slog.w(TAG, "failed parsing " + file + " " + e); 1297 } catch (IOException e) { 1298 Slog.w(TAG, "failed parsing " + file + " " + e); 1299 } catch (IndexOutOfBoundsException e) { 1300 Slog.w(TAG, "failed parsing " + file + " " + e); 1301 } 1302 try { 1303 if (stream != null) { 1304 stream.close(); 1305 } 1306 } catch (IOException e) { 1307 // Ignore 1308 } 1309 1310 if (!success) { 1311 wallpaper.width = -1; 1312 wallpaper.height = -1; 1313 wallpaper.padding.set(0, 0, 0, 0); 1314 wallpaper.name = ""; 1315 } 1316 1317 // We always want to have some reasonable width hint. 1318 int baseSize = getMaximumSizeDimension(); 1319 if (wallpaper.width < baseSize) { 1320 wallpaper.width = baseSize; 1321 } 1322 if (wallpaper.height < baseSize) { 1323 wallpaper.height = baseSize; 1324 } 1325 } 1326 1327 private int getMaximumSizeDimension() { 1328 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); 1329 Display d = wm.getDefaultDisplay(); 1330 return d.getMaximumSizeDimension(); 1331 } 1332 1333 // Called by SystemBackupAgent after files are restored to disk. 1334 public void settingsRestored() { 1335 // Verify caller is the system 1336 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 1337 throw new RuntimeException("settingsRestored() can only be called from the system process"); 1338 } 1339 // TODO: If necessary, make it work for secondary users as well. This currently assumes 1340 // restores only to the primary user 1341 if (DEBUG) Slog.v(TAG, "settingsRestored"); 1342 WallpaperData wallpaper = null; 1343 boolean success = false; 1344 synchronized (mLock) { 1345 loadSettingsLocked(0); 1346 wallpaper = mWallpaperMap.get(0); 1347 if (wallpaper.nextWallpaperComponent != null 1348 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) { 1349 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false, 1350 wallpaper, null)) { 1351 // No such live wallpaper or other failure; fall back to the default 1352 // live wallpaper (since the profile being restored indicated that the 1353 // user had selected a live rather than static one). 1354 bindWallpaperComponentLocked(null, false, false, wallpaper, null); 1355 } 1356 success = true; 1357 } else { 1358 // If there's a wallpaper name, we use that. If that can't be loaded, then we 1359 // use the default. 1360 if ("".equals(wallpaper.name)) { 1361 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty"); 1362 success = true; 1363 } else { 1364 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource"); 1365 success = restoreNamedResourceLocked(wallpaper); 1366 } 1367 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success); 1368 if (success) { 1369 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false, 1370 wallpaper, null); 1371 } 1372 } 1373 } 1374 1375 if (!success) { 1376 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'"); 1377 wallpaper.name = ""; 1378 getWallpaperDir(0).delete(); 1379 } 1380 1381 synchronized (mLock) { 1382 saveSettingsLocked(wallpaper); 1383 } 1384 } 1385 1386 boolean restoreNamedResourceLocked(WallpaperData wallpaper) { 1387 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) { 1388 String resName = wallpaper.name.substring(4); 1389 1390 String pkg = null; 1391 int colon = resName.indexOf(':'); 1392 if (colon > 0) { 1393 pkg = resName.substring(0, colon); 1394 } 1395 1396 String ident = null; 1397 int slash = resName.lastIndexOf('/'); 1398 if (slash > 0) { 1399 ident = resName.substring(slash+1); 1400 } 1401 1402 String type = null; 1403 if (colon > 0 && slash > 0 && (slash-colon) > 1) { 1404 type = resName.substring(colon+1, slash); 1405 } 1406 1407 if (pkg != null && ident != null && type != null) { 1408 int resId = -1; 1409 InputStream res = null; 1410 FileOutputStream fos = null; 1411 try { 1412 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); 1413 Resources r = c.getResources(); 1414 resId = r.getIdentifier(resName, null, null); 1415 if (resId == 0) { 1416 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type 1417 + " ident=" + ident); 1418 return false; 1419 } 1420 1421 res = r.openRawResource(resId); 1422 if (wallpaper.wallpaperFile.exists()) { 1423 wallpaper.wallpaperFile.delete(); 1424 } 1425 fos = new FileOutputStream(wallpaper.wallpaperFile); 1426 1427 byte[] buffer = new byte[32768]; 1428 int amt; 1429 while ((amt=res.read(buffer)) > 0) { 1430 fos.write(buffer, 0, amt); 1431 } 1432 // mWallpaperObserver will notice the close and send the change broadcast 1433 1434 Slog.v(TAG, "Restored wallpaper: " + resName); 1435 return true; 1436 } catch (NameNotFoundException e) { 1437 Slog.e(TAG, "Package name " + pkg + " not found"); 1438 } catch (Resources.NotFoundException e) { 1439 Slog.e(TAG, "Resource not found: " + resId); 1440 } catch (IOException e) { 1441 Slog.e(TAG, "IOException while restoring wallpaper ", e); 1442 } finally { 1443 if (res != null) { 1444 try { 1445 res.close(); 1446 } catch (IOException ex) {} 1447 } 1448 if (fos != null) { 1449 FileUtils.sync(fos); 1450 try { 1451 fos.close(); 1452 } catch (IOException ex) {} 1453 } 1454 } 1455 } 1456 } 1457 return false; 1458 } 1459 1460 @Override 1461 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1462 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1463 != PackageManager.PERMISSION_GRANTED) { 1464 1465 pw.println("Permission Denial: can't dump wallpaper service from from pid=" 1466 + Binder.getCallingPid() 1467 + ", uid=" + Binder.getCallingUid()); 1468 return; 1469 } 1470 1471 synchronized (mLock) { 1472 pw.println("Current Wallpaper Service state:"); 1473 for (int i = 0; i < mWallpaperMap.size(); i++) { 1474 WallpaperData wallpaper = mWallpaperMap.valueAt(i); 1475 pw.println(" User " + wallpaper.userId + ":"); 1476 pw.print(" mWidth="); 1477 pw.print(wallpaper.width); 1478 pw.print(" mHeight="); 1479 pw.println(wallpaper.height); 1480 pw.print(" mPadding="); pw.println(wallpaper.padding); 1481 pw.print(" mName="); pw.println(wallpaper.name); 1482 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent); 1483 if (wallpaper.connection != null) { 1484 WallpaperConnection conn = wallpaper.connection; 1485 pw.print(" Wallpaper connection "); 1486 pw.print(conn); 1487 pw.println(":"); 1488 if (conn.mInfo != null) { 1489 pw.print(" mInfo.component="); 1490 pw.println(conn.mInfo.getComponent()); 1491 } 1492 pw.print(" mToken="); 1493 pw.println(conn.mToken); 1494 pw.print(" mService="); 1495 pw.println(conn.mService); 1496 pw.print(" mEngine="); 1497 pw.println(conn.mEngine); 1498 pw.print(" mLastDiedTime="); 1499 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis()); 1500 } 1501 } 1502 } 1503 } 1504} 1505