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.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