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; 18 19 import static android.os.FileObserver.*; 20 import static android.os.ParcelFileDescriptor.*; 21 22 import android.app.IWallpaperManager; 23 import android.app.IWallpaperManagerCallback; 24 import android.app.PendingIntent; 25 import android.app.WallpaperInfo; 26 import android.app.backup.BackupManager; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.ServiceConnection; 31 import android.content.pm.PackageManager; 32 import android.content.pm.ResolveInfo; 33 import android.content.pm.ServiceInfo; 34 import android.content.pm.PackageManager.NameNotFoundException; 35 import android.content.res.Resources; 36 import android.os.Binder; 37 import android.os.Bundle; 38 import android.os.FileUtils; 39 import android.os.IBinder; 40 import android.os.RemoteException; 41 import android.os.FileObserver; 42 import android.os.ParcelFileDescriptor; 43 import android.os.RemoteCallbackList; 44 import android.os.ServiceManager; 45 import android.os.SystemClock; 46 import android.service.wallpaper.IWallpaperConnection; 47 import android.service.wallpaper.IWallpaperEngine; 48 import android.service.wallpaper.IWallpaperService; 49 import android.service.wallpaper.WallpaperService; 50 import android.util.Slog; 51 import android.util.Xml; 52 import android.view.IWindowManager; 53 import android.view.WindowManager; 54 55 import java.io.FileDescriptor; 56 import java.io.IOException; 57 import java.io.InputStream; 58 import java.io.File; 59 import java.io.FileNotFoundException; 60 import java.io.FileInputStream; 61 import java.io.FileOutputStream; 62 import java.io.PrintWriter; 63 import java.util.List; 64 65 import org.xmlpull.v1.XmlPullParser; 66 import org.xmlpull.v1.XmlPullParserException; 67 import org.xmlpull.v1.XmlSerializer; 68 69 import com.android.internal.content.PackageMonitor; 70 import com.android.internal.service.wallpaper.ImageWallpaper; 71 import com.android.internal.util.FastXmlSerializer; 72 import com.android.internal.util.JournaledFile; 73 import com.android.server.DevicePolicyManagerService.ActiveAdmin; 74 import com.android.server.DevicePolicyManagerService.MyPackageMonitor; 75 76 class WallpaperManagerService extends IWallpaperManager.Stub { 77 static final String TAG = "WallpaperService"; 78 static final boolean DEBUG = false; 79 80 Object mLock = new Object(); 81 82 /** 83 * Minimum time between crashes of a wallpaper service for us to consider 84 * restarting it vs. just reverting to the static wallpaper. 85 */ 86 static final long MIN_WALLPAPER_CRASH_TIME = 10000; 87 88 static final File WALLPAPER_DIR = new File( 89 "/data/data/com.android.settings/files"); 90 static final String WALLPAPER = "wallpaper"; 91 static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER); 92 93 /** 94 * List of callbacks registered they should each be notified 95 * when the wallpaper is changed. 96 */ 97 private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks 98 = new RemoteCallbackList<IWallpaperManagerCallback>(); 99 100 /** 101 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks 102 * that the wallpaper has changed. The CREATE is triggered when there is no 103 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered 104 * everytime the wallpaper is changed. 105 */ 106 private final FileObserver mWallpaperObserver = new FileObserver( 107 WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) { 108 @Override 109 public void onEvent(int event, String path) { 110 if (path == null) { 111 return; 112 } 113 synchronized (mLock) { 114 // changing the wallpaper means we'll need to back up the new one 115 long origId = Binder.clearCallingIdentity(); 116 BackupManager bm = new BackupManager(mContext); 117 bm.dataChanged(); 118 Binder.restoreCallingIdentity(origId); 119 120 File changedFile = new File(WALLPAPER_DIR, path); 121 if (WALLPAPER_FILE.equals(changedFile)) { 122 notifyCallbacksLocked(); 123 } 124 } 125 } 126 }; 127 128 final Context mContext; 129 final IWindowManager mIWindowManager; 130 final MyPackageMonitor mMonitor; 131 132 int mWidth = -1; 133 int mHeight = -1; 134 135 /** 136 * Resource name if using a picture from the wallpaper gallery 137 */ 138 String mName = ""; 139 140 /** 141 * The component name of the currently set live wallpaper. 142 */ 143 ComponentName mWallpaperComponent; 144 145 /** 146 * The component name of the wallpaper that should be set next. 147 */ 148 ComponentName mNextWallpaperComponent; 149 150 /** 151 * Name of the component used to display bitmap wallpapers from either the gallery or 152 * built-in wallpapers. 153 */ 154 ComponentName mImageWallpaperComponent = new ComponentName("android", 155 ImageWallpaper.class.getName()); 156 157 WallpaperConnection mWallpaperConnection; 158 long mLastDiedTime; 159 boolean mWallpaperUpdating; 160 161 class WallpaperConnection extends IWallpaperConnection.Stub 162 implements ServiceConnection { 163 final WallpaperInfo mInfo; 164 final Binder mToken = new Binder(); 165 IWallpaperService mService; 166 IWallpaperEngine mEngine; 167 168 public WallpaperConnection(WallpaperInfo info) { 169 mInfo = info; 170 } 171 172 public void onServiceConnected(ComponentName name, IBinder service) { 173 synchronized (mLock) { 174 if (mWallpaperConnection == this) { 175 mLastDiedTime = SystemClock.uptimeMillis(); 176 mService = IWallpaperService.Stub.asInterface(service); 177 attachServiceLocked(this); 178 // XXX should probably do saveSettingsLocked() later 179 // when we have an engine, but I'm not sure about 180 // locking there and anyway we always need to be able to 181 // recover if there is something wrong. 182 saveSettingsLocked(); 183 } 184 } 185 } 186 187 public void onServiceDisconnected(ComponentName name) { 188 synchronized (mLock) { 189 mService = null; 190 mEngine = null; 191 if (mWallpaperConnection == this) { 192 Slog.w(TAG, "Wallpaper service gone: " + mWallpaperComponent); 193 if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME) 194 > SystemClock.uptimeMillis()) { 195 Slog.w(TAG, "Reverting to built-in wallpaper!"); 196 bindWallpaperComponentLocked(null); 197 } 198 } 199 } 200 } 201 202 public void attachEngine(IWallpaperEngine engine) { 203 mEngine = engine; 204 } 205 206 public ParcelFileDescriptor setWallpaper(String name) { 207 synchronized (mLock) { 208 if (mWallpaperConnection == this) { 209 return updateWallpaperBitmapLocked(name); 210 } 211 return null; 212 } 213 } 214 } 215 216 class MyPackageMonitor extends PackageMonitor { 217 @Override 218 public void onPackageUpdateFinished(String packageName, int uid) { 219 synchronized (mLock) { 220 if (mWallpaperComponent != null && 221 mWallpaperComponent.getPackageName().equals(packageName)) { 222 mWallpaperUpdating = false; 223 ComponentName comp = mWallpaperComponent; 224 clearWallpaperComponentLocked(); 225 bindWallpaperComponentLocked(comp); 226 } 227 } 228 } 229 230 @Override 231 public void onPackageUpdateStarted(String packageName, int uid) { 232 synchronized (mLock) { 233 if (mWallpaperComponent != null && 234 mWallpaperComponent.getPackageName().equals(packageName)) { 235 mWallpaperUpdating = true; 236 } 237 } 238 } 239 240 @Override 241 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 242 return doPackagesChanged(doit); 243 } 244 245 @Override 246 public void onSomePackagesChanged() { 247 doPackagesChanged(true); 248 } 249 250 boolean doPackagesChanged(boolean doit) { 251 boolean changed = false; 252 synchronized (mLock) { 253 if (mWallpaperComponent != null) { 254 int change = isPackageDisappearing(mWallpaperComponent.getPackageName()); 255 if (change == PACKAGE_PERMANENT_CHANGE 256 || change == PACKAGE_TEMPORARY_CHANGE) { 257 changed = true; 258 if (doit) { 259 Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent); 260 clearWallpaperLocked(); 261 } 262 } 263 } 264 if (mNextWallpaperComponent != null) { 265 int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName()); 266 if (change == PACKAGE_PERMANENT_CHANGE 267 || change == PACKAGE_TEMPORARY_CHANGE) { 268 mNextWallpaperComponent = null; 269 } 270 } 271 if (mWallpaperComponent != null 272 && isPackageModified(mWallpaperComponent.getPackageName())) { 273 try { 274 mContext.getPackageManager().getServiceInfo( 275 mWallpaperComponent, 0); 276 } catch (NameNotFoundException e) { 277 Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent); 278 clearWallpaperLocked(); 279 } 280 } 281 if (mNextWallpaperComponent != null 282 && isPackageModified(mNextWallpaperComponent.getPackageName())) { 283 try { 284 mContext.getPackageManager().getServiceInfo( 285 mNextWallpaperComponent, 0); 286 } catch (NameNotFoundException e) { 287 mNextWallpaperComponent = null; 288 } 289 } 290 } 291 return changed; 292 } 293 } 294 295 public WallpaperManagerService(Context context) { 296 if (DEBUG) Slog.v(TAG, "WallpaperService startup"); 297 mContext = context; 298 mIWindowManager = IWindowManager.Stub.asInterface( 299 ServiceManager.getService(Context.WINDOW_SERVICE)); 300 mMonitor = new MyPackageMonitor(); 301 mMonitor.register(context, true); 302 WALLPAPER_DIR.mkdirs(); 303 loadSettingsLocked(); 304 mWallpaperObserver.startWatching(); 305 } 306 307 @Override 308 protected void finalize() throws Throwable { 309 super.finalize(); 310 mWallpaperObserver.stopWatching(); 311 } 312 313 public void systemReady() { 314 if (DEBUG) Slog.v(TAG, "systemReady"); 315 synchronized (mLock) { 316 try { 317 bindWallpaperComponentLocked(mNextWallpaperComponent); 318 } catch (RuntimeException e) { 319 Slog.w(TAG, "Failure starting previous wallpaper", e); 320 try { 321 bindWallpaperComponentLocked(null); 322 } catch (RuntimeException e2) { 323 Slog.w(TAG, "Failure starting default wallpaper", e2); 324 clearWallpaperComponentLocked(); 325 } 326 } 327 } 328 } 329 330 public void clearWallpaper() { 331 if (DEBUG) Slog.v(TAG, "clearWallpaper"); 332 synchronized (mLock) { 333 clearWallpaperLocked(); 334 } 335 } 336 337 public void clearWallpaperLocked() { 338 File f = WALLPAPER_FILE; 339 if (f.exists()) { 340 f.delete(); 341 } 342 final long ident = Binder.clearCallingIdentity(); 343 try { 344 bindWallpaperComponentLocked(null); 345 } catch (IllegalArgumentException e) { 346 // This can happen if the default wallpaper component doesn't 347 // exist. This should be a system configuration problem, but 348 // let's not let it crash the system and just live with no 349 // wallpaper. 350 Slog.e(TAG, "Default wallpaper component not found!", e); 351 } finally { 352 Binder.restoreCallingIdentity(ident); 353 } 354 } 355 356 public void setDimensionHints(int width, int height) throws RemoteException { 357 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS); 358 359 if (width <= 0 || height <= 0) { 360 throw new IllegalArgumentException("width and height must be > 0"); 361 } 362 363 synchronized (mLock) { 364 if (width != mWidth || height != mHeight) { 365 mWidth = width; 366 mHeight = height; 367 saveSettingsLocked(); 368 if (mWallpaperConnection != null) { 369 if (mWallpaperConnection.mEngine != null) { 370 try { 371 mWallpaperConnection.mEngine.setDesiredSize( 372 width, height); 373 } catch (RemoteException e) { 374 } 375 notifyCallbacksLocked(); 376 } 377 } 378 } 379 } 380 } 381 382 public int getWidthHint() throws RemoteException { 383 synchronized (mLock) { 384 return mWidth; 385 } 386 } 387 388 public int getHeightHint() throws RemoteException { 389 synchronized (mLock) { 390 return mHeight; 391 } 392 } 393 394 public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, 395 Bundle outParams) { 396 synchronized (mLock) { 397 try { 398 if (outParams != null) { 399 outParams.putInt("width", mWidth); 400 outParams.putInt("height", mHeight); 401 } 402 mCallbacks.register(cb); 403 File f = WALLPAPER_FILE; 404 if (!f.exists()) { 405 return null; 406 } 407 return ParcelFileDescriptor.open(f, MODE_READ_ONLY); 408 } catch (FileNotFoundException e) { 409 /* Shouldn't happen as we check to see if the file exists */ 410 Slog.w(TAG, "Error getting wallpaper", e); 411 } 412 return null; 413 } 414 } 415 416 public WallpaperInfo getWallpaperInfo() { 417 synchronized (mLock) { 418 if (mWallpaperConnection != null) { 419 return mWallpaperConnection.mInfo; 420 } 421 return null; 422 } 423 } 424 425 public ParcelFileDescriptor setWallpaper(String name) { 426 if (DEBUG) Slog.v(TAG, "setWallpaper"); 427 428 checkPermission(android.Manifest.permission.SET_WALLPAPER); 429 synchronized (mLock) { 430 final long ident = Binder.clearCallingIdentity(); 431 try { 432 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name); 433 if (pfd != null) { 434 // Bind the wallpaper to an ImageWallpaper 435 bindWallpaperComponentLocked(mImageWallpaperComponent); 436 saveSettingsLocked(); 437 } 438 return pfd; 439 } finally { 440 Binder.restoreCallingIdentity(ident); 441 } 442 } 443 } 444 445 ParcelFileDescriptor updateWallpaperBitmapLocked(String name) { 446 if (name == null) name = ""; 447 try { 448 ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE, 449 MODE_CREATE|MODE_READ_WRITE); 450 mName = name; 451 return fd; 452 } catch (FileNotFoundException e) { 453 Slog.w(TAG, "Error setting wallpaper", e); 454 } 455 return null; 456 } 457 458 public void setWallpaperComponent(ComponentName name) { 459 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name); 460 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); 461 synchronized (mLock) { 462 final long ident = Binder.clearCallingIdentity(); 463 try { 464 bindWallpaperComponentLocked(name); 465 } finally { 466 Binder.restoreCallingIdentity(ident); 467 } 468 } 469 } 470 471 void bindWallpaperComponentLocked(ComponentName componentName) { 472 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); 473 474 // Has the component changed? 475 if (mWallpaperConnection != null) { 476 if (mWallpaperComponent == null) { 477 if (componentName == null) { 478 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default"); 479 // Still using default wallpaper. 480 return; 481 } 482 } else if (mWallpaperComponent.equals(componentName)) { 483 // Changing to same wallpaper. 484 if (DEBUG) Slog.v(TAG, "same wallpaper"); 485 return; 486 } 487 } 488 489 try { 490 if (componentName == null) { 491 String defaultComponent = 492 mContext.getString(com.android.internal.R.string.default_wallpaper_component); 493 if (defaultComponent != null) { 494 // See if there is a default wallpaper component specified 495 componentName = ComponentName.unflattenFromString(defaultComponent); 496 if (DEBUG) Slog.v(TAG, "Use default component wallpaper:" + componentName); 497 } 498 if (componentName == null) { 499 // Fall back to static image wallpaper 500 componentName = mImageWallpaperComponent; 501 //clearWallpaperComponentLocked(); 502 //return; 503 if (DEBUG) Slog.v(TAG, "Using image wallpaper"); 504 } 505 } 506 ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName, 507 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS); 508 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) { 509 throw new SecurityException("Selected service does not require " 510 + android.Manifest.permission.BIND_WALLPAPER 511 + ": " + componentName); 512 } 513 514 WallpaperInfo wi = null; 515 516 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); 517 if (componentName != null && !componentName.equals(mImageWallpaperComponent)) { 518 // Make sure the selected service is actually a wallpaper service. 519 List<ResolveInfo> ris = mContext.getPackageManager() 520 .queryIntentServices(intent, PackageManager.GET_META_DATA); 521 for (int i=0; i<ris.size(); i++) { 522 ServiceInfo rsi = ris.get(i).serviceInfo; 523 if (rsi.name.equals(si.name) && 524 rsi.packageName.equals(si.packageName)) { 525 try { 526 wi = new WallpaperInfo(mContext, ris.get(i)); 527 } catch (XmlPullParserException e) { 528 throw new IllegalArgumentException(e); 529 } catch (IOException e) { 530 throw new IllegalArgumentException(e); 531 } 532 break; 533 } 534 } 535 if (wi == null) { 536 throw new SecurityException("Selected service is not a wallpaper: " 537 + componentName); 538 } 539 } 540 541 // Bind the service! 542 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName); 543 WallpaperConnection newConn = new WallpaperConnection(wi); 544 intent.setComponent(componentName); 545 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, 546 com.android.internal.R.string.wallpaper_binding_label); 547 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( 548 mContext, 0, 549 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), 550 mContext.getText(com.android.internal.R.string.chooser_wallpaper)), 551 0)); 552 if (!mContext.bindService(intent, newConn, 553 Context.BIND_AUTO_CREATE)) { 554 throw new IllegalArgumentException("Unable to bind service: " 555 + componentName); 556 } 557 558 clearWallpaperComponentLocked(); 559 mWallpaperComponent = componentName; 560 mWallpaperConnection = newConn; 561 mLastDiedTime = SystemClock.uptimeMillis(); 562 try { 563 if (DEBUG) Slog.v(TAG, "Adding window token: " + newConn.mToken); 564 mIWindowManager.addWindowToken(newConn.mToken, 565 WindowManager.LayoutParams.TYPE_WALLPAPER); 566 } catch (RemoteException e) { 567 } 568 569 } catch (PackageManager.NameNotFoundException e) { 570 throw new IllegalArgumentException("Unknown component " + componentName); 571 } 572 } 573 574 void clearWallpaperComponentLocked() { 575 mWallpaperComponent = null; 576 if (mWallpaperConnection != null) { 577 if (mWallpaperConnection.mEngine != null) { 578 try { 579 mWallpaperConnection.mEngine.destroy(); 580 } catch (RemoteException e) { 581 } 582 } 583 mContext.unbindService(mWallpaperConnection); 584 try { 585 if (DEBUG) Slog.v(TAG, "Removing window token: " 586 + mWallpaperConnection.mToken); 587 mIWindowManager.removeWindowToken(mWallpaperConnection.mToken); 588 } catch (RemoteException e) { 589 } 590 mWallpaperConnection = null; 591 } 592 } 593 594 void attachServiceLocked(WallpaperConnection conn) { 595 try { 596 conn.mService.attach(conn, conn.mToken, 597 WindowManager.LayoutParams.TYPE_WALLPAPER, false, 598 mWidth, mHeight); 599 } catch (RemoteException e) { 600 Slog.w(TAG, "Failed attaching wallpaper; clearing", e); 601 if (!mWallpaperUpdating) { 602 bindWallpaperComponentLocked(null); 603 } 604 } 605 } 606 607 private void notifyCallbacksLocked() { 608 final int n = mCallbacks.beginBroadcast(); 609 for (int i = 0; i < n; i++) { 610 try { 611 mCallbacks.getBroadcastItem(i).onWallpaperChanged(); 612 } catch (RemoteException e) { 613 614 // The RemoteCallbackList will take care of removing 615 // the dead object for us. 616 } 617 } 618 mCallbacks.finishBroadcast(); 619 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED); 620 mContext.sendBroadcast(intent); 621 } 622 623 private void checkPermission(String permission) { 624 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) { 625 throw new SecurityException("Access denied to process: " + Binder.getCallingPid() 626 + ", must have permission " + permission); 627 } 628 } 629 630 private static JournaledFile makeJournaledFile() { 631 final String base = "/data/system/wallpaper_info.xml"; 632 return new JournaledFile(new File(base), new File(base + ".tmp")); 633 } 634 635 private void saveSettingsLocked() { 636 JournaledFile journal = makeJournaledFile(); 637 FileOutputStream stream = null; 638 try { 639 stream = new FileOutputStream(journal.chooseForWrite(), false); 640 XmlSerializer out = new FastXmlSerializer(); 641 out.setOutput(stream, "utf-8"); 642 out.startDocument(null, true); 643 644 out.startTag(null, "wp"); 645 out.attribute(null, "width", Integer.toString(mWidth)); 646 out.attribute(null, "height", Integer.toString(mHeight)); 647 out.attribute(null, "name", mName); 648 if (mWallpaperComponent != null) { 649 out.attribute(null, "component", 650 mWallpaperComponent.flattenToShortString()); 651 } 652 out.endTag(null, "wp"); 653 654 out.endDocument(); 655 stream.close(); 656 journal.commit(); 657 } catch (IOException e) { 658 try { 659 if (stream != null) { 660 stream.close(); 661 } 662 } catch (IOException ex) { 663 // Ignore 664 } 665 journal.rollback(); 666 } 667 } 668 669 private void loadSettingsLocked() { 670 if (DEBUG) Slog.v(TAG, "loadSettingsLocked"); 671 672 JournaledFile journal = makeJournaledFile(); 673 FileInputStream stream = null; 674 File file = journal.chooseForRead(); 675 boolean success = false; 676 try { 677 stream = new FileInputStream(file); 678 XmlPullParser parser = Xml.newPullParser(); 679 parser.setInput(stream, null); 680 681 int type; 682 do { 683 type = parser.next(); 684 if (type == XmlPullParser.START_TAG) { 685 String tag = parser.getName(); 686 if ("wp".equals(tag)) { 687 mWidth = Integer.parseInt(parser.getAttributeValue(null, "width")); 688 mHeight = Integer.parseInt(parser.getAttributeValue(null, "height")); 689 mName = parser.getAttributeValue(null, "name"); 690 String comp = parser.getAttributeValue(null, "component"); 691 mNextWallpaperComponent = comp != null 692 ? ComponentName.unflattenFromString(comp) 693 : null; 694 695 if (DEBUG) { 696 Slog.v(TAG, "mWidth:" + mWidth); 697 Slog.v(TAG, "mHeight:" + mHeight); 698 Slog.v(TAG, "mName:" + mName); 699 Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent); 700 } 701 } 702 } 703 } while (type != XmlPullParser.END_DOCUMENT); 704 success = true; 705 } catch (NullPointerException e) { 706 Slog.w(TAG, "failed parsing " + file + " " + e); 707 } catch (NumberFormatException e) { 708 Slog.w(TAG, "failed parsing " + file + " " + e); 709 } catch (XmlPullParserException e) { 710 Slog.w(TAG, "failed parsing " + file + " " + e); 711 } catch (IOException e) { 712 Slog.w(TAG, "failed parsing " + file + " " + e); 713 } catch (IndexOutOfBoundsException e) { 714 Slog.w(TAG, "failed parsing " + file + " " + e); 715 } 716 try { 717 if (stream != null) { 718 stream.close(); 719 } 720 } catch (IOException e) { 721 // Ignore 722 } 723 724 if (!success) { 725 mWidth = -1; 726 mHeight = -1; 727 mName = ""; 728 } 729 } 730 731 // Called by SystemBackupAgent after files are restored to disk. 732 void settingsRestored() { 733 if (DEBUG) Slog.v(TAG, "settingsRestored"); 734 735 boolean success = false; 736 synchronized (mLock) { 737 loadSettingsLocked(); 738 if (mNextWallpaperComponent != null && 739 !mNextWallpaperComponent.equals(mImageWallpaperComponent)) { 740 try { 741 bindWallpaperComponentLocked(mNextWallpaperComponent); 742 } catch (IllegalArgumentException e) { 743 // No such live wallpaper or other failure; fall back to the default 744 // live wallpaper (since the profile being restored indicated that the 745 // user had selected a live rather than static one). 746 bindWallpaperComponentLocked(null); 747 } 748 success = true; 749 } else { 750 // If there's a wallpaper name, we use that. If that can't be loaded, then we 751 // use the default. 752 if ("".equals(mName)) { 753 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty"); 754 success = true; 755 } else { 756 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource"); 757 success = restoreNamedResourceLocked(); 758 } 759 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success); 760 if (success) { 761 bindWallpaperComponentLocked(mImageWallpaperComponent); 762 } 763 } 764 } 765 766 if (!success) { 767 Slog.e(TAG, "Failed to restore wallpaper: '" + mName + "'"); 768 mName = ""; 769 WALLPAPER_FILE.delete(); 770 } 771 772 synchronized (mLock) { 773 saveSettingsLocked(); 774 } 775 } 776 777 boolean restoreNamedResourceLocked() { 778 if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) { 779 String resName = mName.substring(4); 780 781 String pkg = null; 782 int colon = resName.indexOf(':'); 783 if (colon > 0) { 784 pkg = resName.substring(0, colon); 785 } 786 787 String ident = null; 788 int slash = resName.lastIndexOf('/'); 789 if (slash > 0) { 790 ident = resName.substring(slash+1); 791 } 792 793 String type = null; 794 if (colon > 0 && slash > 0 && (slash-colon) > 1) { 795 type = resName.substring(colon+1, slash); 796 } 797 798 if (pkg != null && ident != null && type != null) { 799 int resId = -1; 800 InputStream res = null; 801 FileOutputStream fos = null; 802 try { 803 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); 804 Resources r = c.getResources(); 805 resId = r.getIdentifier(resName, null, null); 806 if (resId == 0) { 807 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type 808 + " ident=" + ident); 809 return false; 810 } 811 812 res = r.openRawResource(resId); 813 if (WALLPAPER_FILE.exists()) { 814 WALLPAPER_FILE.delete(); 815 } 816 fos = new FileOutputStream(WALLPAPER_FILE); 817 818 byte[] buffer = new byte[32768]; 819 int amt; 820 while ((amt=res.read(buffer)) > 0) { 821 fos.write(buffer, 0, amt); 822 } 823 // mWallpaperObserver will notice the close and send the change broadcast 824 825 Slog.v(TAG, "Restored wallpaper: " + resName); 826 return true; 827 } catch (NameNotFoundException e) { 828 Slog.e(TAG, "Package name " + pkg + " not found"); 829 } catch (Resources.NotFoundException e) { 830 Slog.e(TAG, "Resource not found: " + resId); 831 } catch (IOException e) { 832 Slog.e(TAG, "IOException while restoring wallpaper ", e); 833 } finally { 834 if (res != null) { 835 try { 836 res.close(); 837 } catch (IOException ex) {} 838 } 839 if (fos != null) { 840 FileUtils.sync(fos); 841 try { 842 fos.close(); 843 } catch (IOException ex) {} 844 } 845 } 846 } 847 } 848 return false; 849 } 850 851 @Override 852 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 853 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 854 != PackageManager.PERMISSION_GRANTED) { 855 856 pw.println("Permission Denial: can't dump wallpaper service from from pid=" 857 + Binder.getCallingPid() 858 + ", uid=" + Binder.getCallingUid()); 859 return; 860 } 861 862 synchronized (mLock) { 863 pw.println("Current Wallpaper Service state:"); 864 pw.print(" mWidth="); pw.print(mWidth); 865 pw.print(" mHeight="); pw.println(mHeight); 866 pw.print(" mName="); pw.println(mName); 867 pw.print(" mWallpaperComponent="); pw.println(mWallpaperComponent); 868 if (mWallpaperConnection != null) { 869 WallpaperConnection conn = mWallpaperConnection; 870 pw.print(" Wallpaper connection "); 871 pw.print(conn); pw.println(":"); 872 pw.print(" mInfo.component="); pw.println(conn.mInfo.getComponent()); 873 pw.print(" mToken="); pw.println(conn.mToken); 874 pw.print(" mService="); pw.println(conn.mService); 875 pw.print(" mEngine="); pw.println(conn.mEngine); 876 pw.print(" mLastDiedTime="); 877 pw.println(mLastDiedTime - SystemClock.uptimeMillis()); 878 } 879 } 880 } 881 } 882