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