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