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