OSDN Git Service

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