• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WallpaperObserver(WallpaperData wallpaper)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
onEvent(int event, String path)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 
WallpaperData(int userId)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 
WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper)222         public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
223             mInfo = info;
224             mWallpaper = wallpaper;
225         }
226 
227         @Override
onServiceConnected(ComponentName name, IBinder service)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
onServiceDisconnected(ComponentName name)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
attachEngine(IWallpaperEngine engine)262         public void attachEngine(IWallpaperEngine engine) {
263             synchronized (mLock) {
264                 mEngine = engine;
265             }
266         }
267 
268         @Override
engineShown(IWallpaperEngine engine)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
setWallpaper(String name)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
onPackageUpdateFinished(String packageName, int uid)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
onPackageModified(String packageName)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
onPackageUpdateStarted(String packageName, int uid)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
onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)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
onSomePackagesChanged()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 
doPackagesChangedLocked(boolean doit, WallpaperData wallpaper)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 
WallpaperManagerService(Context context)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 
getWallpaperDir(int userId)439     private static File getWallpaperDir(int userId) {
440         return Environment.getUserSystemDirectory(userId);
441     }
442 
443     @Override
finalize()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 
systemReady()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 
getName()497     String getName() {
498         synchronized (mLock) {
499             return mWallpaperMap.get(0).name;
500         }
501     }
502 
onStoppingUser(int userId)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 
onRemoveUser(int userId)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 
switchUser(int userId, IRemoteCallback reply)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 
switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply)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 
clearWallpaper()563     public void clearWallpaper() {
564         if (DEBUG) Slog.v(TAG, "clearWallpaper");
565         synchronized (mLock) {
566             clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
567         }
568     }
569 
clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply)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 
hasNamedWallpaper(String name)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 
setDimensionHints(int width, int height)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 
getWidthHint()661     public int getWidthHint() throws RemoteException {
662         synchronized (mLock) {
663             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
664             return wallpaper.width;
665         }
666     }
667 
getHeightHint()668     public int getHeightHint() throws RemoteException {
669         synchronized (mLock) {
670             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
671             return wallpaper.height;
672         }
673     }
674 
getWallpaper(IWallpaperManagerCallback cb, Bundle outParams)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 
getWallpaperInfo()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 
setWallpaper(String name)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 
updateWallpaperBitmapLocked(String name, WallpaperData wallpaper)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 
setWallpaperComponent(ComponentName name)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 
bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply)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 
detachWallpaperLocked(WallpaperData wallpaper)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 
clearWallpaperComponentLocked(WallpaperData wallpaper)954     void clearWallpaperComponentLocked(WallpaperData wallpaper) {
955         wallpaper.wallpaperComponent = null;
956         detachWallpaperLocked(wallpaper);
957     }
958 
attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper)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 
notifyCallbacksLocked(WallpaperData wallpaper)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 
checkPermission(String permission)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 
makeJournaledFile(int userId)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 
saveSettingsLocked(WallpaperData wallpaper)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 
migrateFromOld()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 
loadSettingsLocked(int userId)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.
settingsRestored()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 
restoreNamedResourceLocked(WallpaperData wallpaper)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
dump(FileDescriptor fd, PrintWriter pw, String[] args)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