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