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