• 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.FileObserver.*;
20 import static android.os.ParcelFileDescriptor.*;
21 
22 import android.app.IWallpaperManager;
23 import android.app.IWallpaperManagerCallback;
24 import android.app.PendingIntent;
25 import android.app.WallpaperInfo;
26 import android.backup.BackupManager;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.ServiceConnection;
31 import android.content.pm.PackageManager;
32 import android.content.pm.ResolveInfo;
33 import android.content.pm.ServiceInfo;
34 import android.content.pm.PackageManager.NameNotFoundException;
35 import android.content.res.Resources;
36 import android.os.Binder;
37 import android.os.Bundle;
38 import android.os.IBinder;
39 import android.os.RemoteException;
40 import android.os.FileObserver;
41 import android.os.ParcelFileDescriptor;
42 import android.os.RemoteCallbackList;
43 import android.os.ServiceManager;
44 import android.os.SystemClock;
45 import android.service.wallpaper.IWallpaperConnection;
46 import android.service.wallpaper.IWallpaperEngine;
47 import android.service.wallpaper.IWallpaperService;
48 import android.service.wallpaper.WallpaperService;
49 import android.util.Log;
50 import android.util.Xml;
51 import android.view.IWindowManager;
52 import android.view.WindowManager;
53 
54 import java.io.FileDescriptor;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.io.File;
58 import java.io.FileNotFoundException;
59 import java.io.FileInputStream;
60 import java.io.FileOutputStream;
61 import java.io.PrintWriter;
62 import java.util.List;
63 
64 import org.xmlpull.v1.XmlPullParser;
65 import org.xmlpull.v1.XmlPullParserException;
66 import org.xmlpull.v1.XmlSerializer;
67 
68 import com.android.internal.service.wallpaper.ImageWallpaper;
69 import com.android.internal.util.FastXmlSerializer;
70 
71 class WallpaperManagerService extends IWallpaperManager.Stub {
72     static final String TAG = "WallpaperService";
73     static final boolean DEBUG = false;
74 
75     Object mLock = new Object();
76 
77     /**
78      * Minimum time between crashes of a wallpaper service for us to consider
79      * restarting it vs. just reverting to the static wallpaper.
80      */
81     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
82 
83     static final File WALLPAPER_DIR = new File(
84             "/data/data/com.android.settings/files");
85     static final String WALLPAPER = "wallpaper";
86     static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
87 
88     /**
89      * List of callbacks registered they should each be notified
90      * when the wallpaper is changed.
91      */
92     private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
93             = new RemoteCallbackList<IWallpaperManagerCallback>();
94 
95     /**
96      * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
97      * that the wallpaper has changed. The CREATE is triggered when there is no
98      * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
99      * everytime the wallpaper is changed.
100      */
101     private final FileObserver mWallpaperObserver = new FileObserver(
102             WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) {
103                 @Override
104                 public void onEvent(int event, String path) {
105                     if (path == null) {
106                         return;
107                     }
108                     synchronized (mLock) {
109                         // changing the wallpaper means we'll need to back up the new one
110                         long origId = Binder.clearCallingIdentity();
111                         BackupManager bm = new BackupManager(mContext);
112                         bm.dataChanged();
113                         Binder.restoreCallingIdentity(origId);
114 
115                         File changedFile = new File(WALLPAPER_DIR, path);
116                         if (WALLPAPER_FILE.equals(changedFile)) {
117                             notifyCallbacksLocked();
118                         }
119                     }
120                 }
121             };
122 
123     final Context mContext;
124     final IWindowManager mIWindowManager;
125 
126     int mWidth = -1;
127     int mHeight = -1;
128     String mName = "";
129 
130     /**
131      * The component name of the currently set live wallpaper. This will be null if the
132      * wallpaper uses the built in ImageWallpaper component to display a bitmap.
133      */
134     ComponentName mWallpaperComponent;
135     WallpaperConnection mWallpaperConnection;
136     long mLastDiedTime;
137 
138     class WallpaperConnection extends IWallpaperConnection.Stub
139             implements ServiceConnection {
140         final WallpaperInfo mInfo;
141         final Binder mToken = new Binder();
142         IWallpaperService mService;
143         IWallpaperEngine mEngine;
144 
WallpaperConnection(WallpaperInfo info)145         public WallpaperConnection(WallpaperInfo info) {
146             mInfo = info;
147         }
148 
onServiceConnected(ComponentName name, IBinder service)149         public void onServiceConnected(ComponentName name, IBinder service) {
150             synchronized (mLock) {
151                 if (mWallpaperConnection == this) {
152                     mService = IWallpaperService.Stub.asInterface(service);
153                     attachServiceLocked(this);
154                     // XXX should probably do saveSettingsLocked() later
155                     // when we have an engine, but I'm not sure about
156                     // locking there and anyway we always need to be able to
157                     // recover if there is something wrong.
158                     saveSettingsLocked();
159                 }
160             }
161         }
162 
onServiceDisconnected(ComponentName name)163         public void onServiceDisconnected(ComponentName name) {
164             synchronized (mLock) {
165                 mService = null;
166                 mEngine = null;
167                 if (mWallpaperConnection == this) {
168                     Log.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
169                     if ((mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
170                             < SystemClock.uptimeMillis()) {
171                         Log.w(TAG, "Reverting to built-in wallpaper!");
172                         bindWallpaperComponentLocked(null, false);
173                     }
174                 }
175             }
176         }
177 
attachEngine(IWallpaperEngine engine)178         public void attachEngine(IWallpaperEngine engine) {
179             mEngine = engine;
180         }
181 
setWallpaper(String name)182         public ParcelFileDescriptor setWallpaper(String name) {
183             synchronized (mLock) {
184                 if (mWallpaperConnection == this) {
185                     return updateWallpaperBitmapLocked(name);
186                 }
187                 return null;
188             }
189         }
190     }
191 
WallpaperManagerService(Context context)192     public WallpaperManagerService(Context context) {
193         if (DEBUG) Log.d(TAG, "WallpaperService startup");
194         mContext = context;
195         mIWindowManager = IWindowManager.Stub.asInterface(
196                 ServiceManager.getService(Context.WINDOW_SERVICE));
197         WALLPAPER_DIR.mkdirs();
198         loadSettingsLocked();
199         mWallpaperObserver.startWatching();
200     }
201 
202     @Override
finalize()203     protected void finalize() throws Throwable {
204         super.finalize();
205         mWallpaperObserver.stopWatching();
206     }
207 
systemReady()208     public void systemReady() {
209         synchronized (mLock) {
210             try {
211                 bindWallpaperComponentLocked(mWallpaperComponent, false);
212             } catch (RuntimeException e) {
213                 Log.w(TAG, "Failure starting previous wallpaper", e);
214                 try {
215                     bindWallpaperComponentLocked(null, false);
216                 } catch (RuntimeException e2) {
217                     Log.w(TAG, "Failure starting default wallpaper", e2);
218                     clearWallpaperComponentLocked();
219                 }
220             }
221         }
222     }
223 
clearWallpaper()224     public void clearWallpaper() {
225         synchronized (mLock) {
226             File f = WALLPAPER_FILE;
227             if (f.exists()) {
228                 f.delete();
229             }
230             final long ident = Binder.clearCallingIdentity();
231             try {
232                 bindWallpaperComponentLocked(null, false);
233             } finally {
234                 Binder.restoreCallingIdentity(ident);
235             }
236         }
237     }
238 
setDimensionHints(int width, int height)239     public void setDimensionHints(int width, int height) throws RemoteException {
240         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
241 
242         if (width <= 0 || height <= 0) {
243             throw new IllegalArgumentException("width and height must be > 0");
244         }
245 
246         synchronized (mLock) {
247             if (width != mWidth || height != mHeight) {
248                 mWidth = width;
249                 mHeight = height;
250                 saveSettingsLocked();
251                 if (mWallpaperConnection != null) {
252                     if (mWallpaperConnection.mEngine != null) {
253                         try {
254                             mWallpaperConnection.mEngine.setDesiredSize(
255                                     width, height);
256                         } catch (RemoteException e) {
257                         }
258                         notifyCallbacksLocked();
259                     }
260                 }
261             }
262         }
263     }
264 
getWidthHint()265     public int getWidthHint() throws RemoteException {
266         synchronized (mLock) {
267             return mWidth;
268         }
269     }
270 
getHeightHint()271     public int getHeightHint() throws RemoteException {
272         synchronized (mLock) {
273             return mHeight;
274         }
275     }
276 
getWallpaper(IWallpaperManagerCallback cb, Bundle outParams)277     public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
278             Bundle outParams) {
279         synchronized (mLock) {
280             try {
281                 if (outParams != null) {
282                     outParams.putInt("width", mWidth);
283                     outParams.putInt("height", mHeight);
284                 }
285                 mCallbacks.register(cb);
286                 File f = WALLPAPER_FILE;
287                 if (!f.exists()) {
288                     return null;
289                 }
290                 return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
291             } catch (FileNotFoundException e) {
292                 /* Shouldn't happen as we check to see if the file exists */
293                 Log.w(TAG, "Error getting wallpaper", e);
294             }
295             return null;
296         }
297     }
298 
getWallpaperInfo()299     public WallpaperInfo getWallpaperInfo() {
300         synchronized (mLock) {
301             if (mWallpaperConnection != null) {
302                 return mWallpaperConnection.mInfo;
303             }
304             return null;
305         }
306     }
307 
setWallpaper(String name)308     public ParcelFileDescriptor setWallpaper(String name) {
309         checkPermission(android.Manifest.permission.SET_WALLPAPER);
310         synchronized (mLock) {
311             final long ident = Binder.clearCallingIdentity();
312             try {
313                 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
314                 if (pfd != null) {
315                     // Bind the wallpaper to an ImageWallpaper
316                     bindWallpaperComponentLocked(null, true);
317                     saveSettingsLocked();
318                 }
319                 return pfd;
320             } finally {
321                 Binder.restoreCallingIdentity(ident);
322             }
323         }
324     }
325 
updateWallpaperBitmapLocked(String name)326     ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
327         if (name == null) name = "";
328         try {
329             ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
330                     MODE_CREATE|MODE_READ_WRITE);
331             mName = name;
332             return fd;
333         } catch (FileNotFoundException e) {
334             Log.w(TAG, "Error setting wallpaper", e);
335         }
336         return null;
337     }
338 
setWallpaperComponent(ComponentName name)339     public void setWallpaperComponent(ComponentName name) {
340         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
341         synchronized (mLock) {
342             final long ident = Binder.clearCallingIdentity();
343             try {
344                 bindWallpaperComponentLocked(name, false);
345             } finally {
346                 Binder.restoreCallingIdentity(ident);
347             }
348         }
349     }
350 
bindWallpaperComponentLocked(ComponentName componentName, boolean isBitmap)351     void bindWallpaperComponentLocked(ComponentName componentName, boolean isBitmap) {
352         // Has the component changed?
353         if (mWallpaperConnection != null) {
354             if (mWallpaperComponent == null) {
355                 if (componentName == null) {
356                     // Still using default wallpaper.
357                     return;
358                 }
359             } else if (mWallpaperComponent.equals(componentName)) {
360                 // Changing to same wallpaper.
361                 return;
362             }
363         }
364 
365         try {
366             ComponentName realComponentName = componentName;
367             if (realComponentName == null) {
368                 String defaultComponent =
369                     mContext.getString(com.android.internal.R.string.default_wallpaper_component);
370                 if (defaultComponent != null && !isBitmap) {
371                     // See if there is a default wallpaper component specified
372                     // Only look for this if the wallpaper is not being set to a bitmap
373                     realComponentName = ComponentName.unflattenFromString(defaultComponent);
374                     componentName = realComponentName;
375                 }
376                 if (realComponentName == null) {
377                     // Fall back to static image wallpaper
378                     realComponentName = new ComponentName("android",
379                             ImageWallpaper.class.getName());
380                     //clearWallpaperComponentLocked();
381                     //return;
382                 }
383             }
384             ServiceInfo si = mContext.getPackageManager().getServiceInfo(realComponentName,
385                     PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS);
386             if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
387                 throw new SecurityException("Selected service does not require "
388                         + android.Manifest.permission.BIND_WALLPAPER
389                         + ": " + realComponentName);
390             }
391 
392             WallpaperInfo wi = null;
393 
394             Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
395             if (componentName != null) {
396                 // Make sure the selected service is actually a wallpaper service.
397                 List<ResolveInfo> ris = mContext.getPackageManager()
398                         .queryIntentServices(intent, PackageManager.GET_META_DATA);
399                 for (int i=0; i<ris.size(); i++) {
400                     ServiceInfo rsi = ris.get(i).serviceInfo;
401                     if (rsi.name.equals(si.name) &&
402                             rsi.packageName.equals(si.packageName)) {
403                         try {
404                             wi = new WallpaperInfo(mContext, ris.get(i));
405                         } catch (XmlPullParserException e) {
406                             throw new IllegalArgumentException(e);
407                         } catch (IOException e) {
408                             throw new IllegalArgumentException(e);
409                         }
410                         break;
411                     }
412                 }
413                 if (wi == null) {
414                     throw new SecurityException("Selected service is not a wallpaper: "
415                             + realComponentName);
416                 }
417             }
418 
419             // Bind the service!
420             WallpaperConnection newConn = new WallpaperConnection(wi);
421             intent.setComponent(realComponentName);
422             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
423                     com.android.internal.R.string.wallpaper_binding_label);
424             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
425                     mContext, 0,
426                     Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
427                             mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
428                             0));
429             if (!mContext.bindService(intent, newConn,
430                     Context.BIND_AUTO_CREATE)) {
431                 throw new IllegalArgumentException("Unable to bind service: "
432                         + componentName);
433             }
434 
435             clearWallpaperComponentLocked();
436             mWallpaperComponent = componentName;
437             mWallpaperConnection = newConn;
438             mLastDiedTime = SystemClock.uptimeMillis();
439             try {
440                 if (DEBUG) Log.v(TAG, "Adding window token: " + newConn.mToken);
441                 mIWindowManager.addWindowToken(newConn.mToken,
442                         WindowManager.LayoutParams.TYPE_WALLPAPER);
443             } catch (RemoteException e) {
444             }
445 
446         } catch (PackageManager.NameNotFoundException e) {
447             throw new IllegalArgumentException("Unknown component " + componentName);
448         }
449     }
450 
clearWallpaperComponentLocked()451     void clearWallpaperComponentLocked() {
452         mWallpaperComponent = null;
453         if (mWallpaperConnection != null) {
454             if (mWallpaperConnection.mEngine != null) {
455                 try {
456                     mWallpaperConnection.mEngine.destroy();
457                 } catch (RemoteException e) {
458                 }
459             }
460             mContext.unbindService(mWallpaperConnection);
461             try {
462                 if (DEBUG) Log.v(TAG, "Removing window token: "
463                         + mWallpaperConnection.mToken);
464                 mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
465             } catch (RemoteException e) {
466             }
467             mWallpaperConnection = null;
468         }
469     }
470 
attachServiceLocked(WallpaperConnection conn)471     void attachServiceLocked(WallpaperConnection conn) {
472         try {
473             conn.mService.attach(conn, conn.mToken,
474                     WindowManager.LayoutParams.TYPE_WALLPAPER, false,
475                     mWidth, mHeight);
476         } catch (RemoteException e) {
477             Log.w(TAG, "Failed attaching wallpaper; clearing", e);
478             bindWallpaperComponentLocked(null, false);
479         }
480     }
481 
notifyCallbacksLocked()482     private void notifyCallbacksLocked() {
483         final int n = mCallbacks.beginBroadcast();
484         for (int i = 0; i < n; i++) {
485             try {
486                 mCallbacks.getBroadcastItem(i).onWallpaperChanged();
487             } catch (RemoteException e) {
488 
489                 // The RemoteCallbackList will take care of removing
490                 // the dead object for us.
491             }
492         }
493         mCallbacks.finishBroadcast();
494         final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
495         mContext.sendBroadcast(intent);
496     }
497 
checkPermission(String permission)498     private void checkPermission(String permission) {
499         if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
500             throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
501                     + ", must have permission " + permission);
502         }
503     }
504 
makeJournaledFile()505     private static JournaledFile makeJournaledFile() {
506         final String base = "/data/system/wallpaper_info.xml";
507         return new JournaledFile(new File(base), new File(base + ".tmp"));
508     }
509 
saveSettingsLocked()510     private void saveSettingsLocked() {
511         JournaledFile journal = makeJournaledFile();
512         FileOutputStream stream = null;
513         try {
514             stream = new FileOutputStream(journal.chooseForWrite(), false);
515             XmlSerializer out = new FastXmlSerializer();
516             out.setOutput(stream, "utf-8");
517             out.startDocument(null, true);
518 
519             out.startTag(null, "wp");
520             out.attribute(null, "width", Integer.toString(mWidth));
521             out.attribute(null, "height", Integer.toString(mHeight));
522             out.attribute(null, "name", mName);
523             if (mWallpaperComponent != null) {
524                 out.attribute(null, "component",
525                         mWallpaperComponent.flattenToShortString());
526             }
527             out.endTag(null, "wp");
528 
529             out.endDocument();
530             stream.close();
531             journal.commit();
532         } catch (IOException e) {
533             try {
534                 if (stream != null) {
535                     stream.close();
536                 }
537             } catch (IOException ex) {
538                 // Ignore
539             }
540             journal.rollback();
541         }
542     }
543 
loadSettingsLocked()544     private void loadSettingsLocked() {
545         JournaledFile journal = makeJournaledFile();
546         FileInputStream stream = null;
547         File file = journal.chooseForRead();
548         boolean success = false;
549         try {
550             stream = new FileInputStream(file);
551             XmlPullParser parser = Xml.newPullParser();
552             parser.setInput(stream, null);
553 
554             int type;
555             do {
556                 type = parser.next();
557                 if (type == XmlPullParser.START_TAG) {
558                     String tag = parser.getName();
559                     if ("wp".equals(tag)) {
560                         mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
561                         mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
562                         mName = parser.getAttributeValue(null, "name");
563                         String comp = parser.getAttributeValue(null, "component");
564                         mWallpaperComponent = comp != null
565                                 ? ComponentName.unflattenFromString(comp)
566                                 : null;
567                     }
568                 }
569             } while (type != XmlPullParser.END_DOCUMENT);
570             success = true;
571         } catch (NullPointerException e) {
572             Log.w(TAG, "failed parsing " + file + " " + e);
573         } catch (NumberFormatException e) {
574             Log.w(TAG, "failed parsing " + file + " " + e);
575         } catch (XmlPullParserException e) {
576             Log.w(TAG, "failed parsing " + file + " " + e);
577         } catch (IOException e) {
578             Log.w(TAG, "failed parsing " + file + " " + e);
579         } catch (IndexOutOfBoundsException e) {
580             Log.w(TAG, "failed parsing " + file + " " + e);
581         }
582         try {
583             if (stream != null) {
584                 stream.close();
585             }
586         } catch (IOException e) {
587             // Ignore
588         }
589 
590         if (!success) {
591             mWidth = -1;
592             mHeight = -1;
593             mName = "";
594         }
595     }
596 
settingsRestored()597     void settingsRestored() {
598         boolean success = false;
599         synchronized (mLock) {
600             loadSettingsLocked();
601             // If there's a wallpaper name, we use that.  If that can't be loaded, then we
602             // use the default.
603             if ("".equals(mName)) {
604                 success = true;
605             } else {
606                 success = restoreNamedResourceLocked();
607             }
608         }
609 
610         if (!success) {
611             Log.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
612             mName = "";
613             WALLPAPER_FILE.delete();
614         }
615         saveSettingsLocked();
616     }
617 
restoreNamedResourceLocked()618     boolean restoreNamedResourceLocked() {
619         if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
620             String resName = mName.substring(4);
621 
622             String pkg = null;
623             int colon = resName.indexOf(':');
624             if (colon > 0) {
625                 pkg = resName.substring(0, colon);
626             }
627 
628             String ident = null;
629             int slash = resName.lastIndexOf('/');
630             if (slash > 0) {
631                 ident = resName.substring(slash+1);
632             }
633 
634             String type = null;
635             if (colon > 0 && slash > 0 && (slash-colon) > 1) {
636                 type = resName.substring(colon+1, slash);
637             }
638 
639             if (pkg != null && ident != null && type != null) {
640                 int resId = -1;
641                 InputStream res = null;
642                 FileOutputStream fos = null;
643                 try {
644                     Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
645                     Resources r = c.getResources();
646                     resId = r.getIdentifier(resName, null, null);
647                     if (resId == 0) {
648                         Log.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
649                                 + " ident=" + ident);
650                         return false;
651                     }
652 
653                     res = r.openRawResource(resId);
654                     fos = new FileOutputStream(WALLPAPER_FILE);
655 
656                     byte[] buffer = new byte[32768];
657                     int amt;
658                     while ((amt=res.read(buffer)) > 0) {
659                         fos.write(buffer, 0, amt);
660                     }
661                     // mWallpaperObserver will notice the close and send the change broadcast
662 
663                     Log.d(TAG, "Restored wallpaper: " + resName);
664                     return true;
665                 } catch (NameNotFoundException e) {
666                     Log.e(TAG, "Package name " + pkg + " not found");
667                 } catch (Resources.NotFoundException e) {
668                     Log.e(TAG, "Resource not found: " + resId);
669                 } catch (IOException e) {
670                     Log.e(TAG, "IOException while restoring wallpaper ", e);
671                 } finally {
672                     if (res != null) {
673                         try {
674                             res.close();
675                         } catch (IOException ex) {}
676                     }
677                     if (fos != null) {
678                         try {
679                             fos.close();
680                         } catch (IOException ex) {}
681                     }
682                 }
683             }
684         }
685         return false;
686     }
687 
688     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)689     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
690         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
691                 != PackageManager.PERMISSION_GRANTED) {
692 
693             pw.println("Permission Denial: can't dump wallpaper service from from pid="
694                     + Binder.getCallingPid()
695                     + ", uid=" + Binder.getCallingUid());
696             return;
697         }
698 
699         synchronized (mLock) {
700             pw.println("Current Wallpaper Service state:");
701             pw.print("  mWidth="); pw.print(mWidth);
702                     pw.print(" mHeight="); pw.println(mHeight);
703             pw.print("  mName="); pw.println(mName);
704             pw.print("  mWallpaperComponent="); pw.println(mWallpaperComponent);
705             if (mWallpaperConnection != null) {
706                 WallpaperConnection conn = mWallpaperConnection;
707                 pw.print("  Wallpaper connection ");
708                         pw.print(conn); pw.println(":");
709                 pw.print("    mInfo.component="); pw.println(conn.mInfo.getComponent());
710                 pw.print("    mToken="); pw.println(conn.mToken);
711                 pw.print("    mService="); pw.println(conn.mService);
712                 pw.print("    mEngine="); pw.println(conn.mEngine);
713                 pw.print("    mLastDiedTime=");
714                         pw.println(mLastDiedTime - SystemClock.uptimeMillis());
715             }
716         }
717     }
718 }
719