• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 android.app.AlarmManager;
20 import android.app.AppGlobals;
21 import android.app.PendingIntent;
22 import android.appwidget.AppWidgetManager;
23 import android.appwidget.AppWidgetProviderInfo;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.Intent.FilterComparison;
28 import android.content.ServiceConnection;
29 import android.content.pm.ActivityInfo;
30 import android.content.pm.ApplicationInfo;
31 import android.content.pm.IPackageManager;
32 import android.content.pm.PackageInfo;
33 import android.content.pm.PackageManager;
34 import android.content.pm.ResolveInfo;
35 import android.content.pm.ServiceInfo;
36 import android.content.res.Resources;
37 import android.content.res.TypedArray;
38 import android.content.res.XmlResourceParser;
39 import android.graphics.Point;
40 import android.net.Uri;
41 import android.os.Binder;
42 import android.os.Bundle;
43 import android.os.Environment;
44 import android.os.Handler;
45 import android.os.HandlerThread;
46 import android.os.IBinder;
47 import android.os.Looper;
48 import android.os.Process;
49 import android.os.RemoteException;
50 import android.os.SystemClock;
51 import android.os.UserHandle;
52 import android.util.AtomicFile;
53 import android.util.AttributeSet;
54 import android.util.Log;
55 import android.util.Pair;
56 import android.util.Slog;
57 import android.util.TypedValue;
58 import android.util.Xml;
59 import android.view.Display;
60 import android.view.WindowManager;
61 import android.widget.RemoteViews;
62 
63 import com.android.internal.appwidget.IAppWidgetHost;
64 import com.android.internal.util.FastXmlSerializer;
65 import com.android.internal.widget.IRemoteViewsAdapterConnection;
66 import com.android.internal.widget.IRemoteViewsFactory;
67 
68 import org.xmlpull.v1.XmlPullParser;
69 import org.xmlpull.v1.XmlPullParserException;
70 import org.xmlpull.v1.XmlSerializer;
71 
72 import java.io.File;
73 import java.io.FileDescriptor;
74 import java.io.FileInputStream;
75 import java.io.FileNotFoundException;
76 import java.io.FileOutputStream;
77 import java.io.IOException;
78 import java.io.PrintWriter;
79 import java.util.ArrayList;
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.Iterator;
83 import java.util.List;
84 import java.util.Locale;
85 import java.util.Set;
86 
87 class AppWidgetServiceImpl {
88 
89     private static final String TAG = "AppWidgetServiceImpl";
90     private static final String SETTINGS_FILENAME = "appwidgets.xml";
91     private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
92 
93     private static boolean DBG = false;
94 
95     /*
96      * When identifying a Host or Provider based on the calling process, use the uid field. When
97      * identifying a Host or Provider based on a package manager broadcast, use the package given.
98      */
99 
100     static class Provider {
101         int uid;
102         AppWidgetProviderInfo info;
103         ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
104         PendingIntent broadcast;
105         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
106 
107         int tag; // for use while saving state (the index)
108     }
109 
110     static class Host {
111         int uid;
112         int hostId;
113         String packageName;
114         ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
115         IAppWidgetHost callbacks;
116         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
117 
118         int tag; // for use while saving state (the index)
119 
uidMatches(int callingUid)120         boolean uidMatches(int callingUid) {
121             if (UserHandle.getAppId(callingUid) == Process.myUid()) {
122                 // For a host that's in the system process, ignore the user id
123                 return UserHandle.isSameApp(this.uid, callingUid);
124             } else {
125                 return this.uid == callingUid;
126             }
127         }
128     }
129 
130     static class AppWidgetId {
131         int appWidgetId;
132         Provider provider;
133         RemoteViews views;
134         Bundle options;
135         Host host;
136     }
137 
138     /**
139      * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This
140      * needs to be a static inner class since a reference to the ServiceConnection is held globally
141      * and may lead us to leak AppWidgetService instances (if there were more than one).
142      */
143     static class ServiceConnectionProxy implements ServiceConnection {
144         private final IBinder mConnectionCb;
145 
ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb)146         ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
147             mConnectionCb = connectionCb;
148         }
149 
onServiceConnected(ComponentName name, IBinder service)150         public void onServiceConnected(ComponentName name, IBinder service) {
151             final IRemoteViewsAdapterConnection cb = IRemoteViewsAdapterConnection.Stub
152                     .asInterface(mConnectionCb);
153             try {
154                 cb.onServiceConnected(service);
155             } catch (Exception e) {
156                 e.printStackTrace();
157             }
158         }
159 
onServiceDisconnected(ComponentName name)160         public void onServiceDisconnected(ComponentName name) {
161             disconnect();
162         }
163 
disconnect()164         public void disconnect() {
165             final IRemoteViewsAdapterConnection cb = IRemoteViewsAdapterConnection.Stub
166                     .asInterface(mConnectionCb);
167             try {
168                 cb.onServiceDisconnected();
169             } catch (Exception e) {
170                 e.printStackTrace();
171             }
172         }
173     }
174 
175     // Manages active connections to RemoteViewsServices
176     private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> mBoundRemoteViewsServices = new HashMap<Pair<Integer, FilterComparison>, ServiceConnection>();
177     // Manages persistent references to RemoteViewsServices from different App Widgets
178     private final HashMap<FilterComparison, HashSet<Integer>> mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>();
179 
180     Context mContext;
181     Locale mLocale;
182     IPackageManager mPm;
183     AlarmManager mAlarmManager;
184     ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
185     int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
186     final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
187     ArrayList<Host> mHosts = new ArrayList<Host>();
188     // set of package names
189     HashSet<String> mPackagesWithBindWidgetPermission = new HashSet<String>();
190     boolean mSafeMode;
191     int mUserId;
192     boolean mStateLoaded;
193     int mMaxWidgetBitmapMemory;
194 
195     private final Handler mSaveStateHandler;
196 
197     // These are for debugging only -- widgets are going missing in some rare instances
198     ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
199     ArrayList<Host> mDeletedHosts = new ArrayList<Host>();
200 
AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler)201     AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler) {
202         mContext = context;
203         mPm = AppGlobals.getPackageManager();
204         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
205         mUserId = userId;
206         mSaveStateHandler = saveStateHandler;
207         computeMaximumWidgetBitmapMemory();
208     }
209 
computeMaximumWidgetBitmapMemory()210     void computeMaximumWidgetBitmapMemory() {
211         WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
212         Display display = wm.getDefaultDisplay();
213         Point size = new Point();
214         display.getRealSize(size);
215         // Cap memory usage at 1.5 times the size of the display
216         // 1.5 * 4 bytes/pixel * w * h ==> 6 * w * h
217         mMaxWidgetBitmapMemory = 6 * size.x * size.y;
218     }
219 
systemReady(boolean safeMode)220     public void systemReady(boolean safeMode) {
221         mSafeMode = safeMode;
222 
223         synchronized (mAppWidgetIds) {
224             ensureStateLoadedLocked();
225         }
226     }
227 
log(String msg)228     private void log(String msg) {
229         Slog.i(TAG, "u=" + mUserId + ": " + msg);
230     }
231 
onConfigurationChanged()232     void onConfigurationChanged() {
233         if (DBG) log("Got onConfigurationChanged()");
234         Locale revised = Locale.getDefault();
235         if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
236             mLocale = revised;
237 
238             synchronized (mAppWidgetIds) {
239                 ensureStateLoadedLocked();
240                 // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the
241                 // list of installed providers and skip providers that we don't need to update.
242                 // Also note that remove the provider does not clear the Provider component data.
243                 ArrayList<Provider> installedProviders =
244                         new ArrayList<Provider>(mInstalledProviders);
245                 HashSet<ComponentName> removedProviders = new HashSet<ComponentName>();
246                 int N = installedProviders.size();
247                 for (int i = N - 1; i >= 0; i--) {
248                     Provider p = installedProviders.get(i);
249                     ComponentName cn = p.info.provider;
250                     if (!removedProviders.contains(cn)) {
251                         updateProvidersForPackageLocked(cn.getPackageName(), removedProviders);
252                     }
253                 }
254                 saveStateAsync();
255             }
256         }
257     }
258 
onBroadcastReceived(Intent intent)259     void onBroadcastReceived(Intent intent) {
260         if (DBG) log("onBroadcast " + intent);
261         final String action = intent.getAction();
262         boolean added = false;
263         boolean changed = false;
264         boolean providersModified = false;
265         String pkgList[] = null;
266         if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
267             pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
268             added = true;
269         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
270             pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
271             added = false;
272         } else {
273             Uri uri = intent.getData();
274             if (uri == null) {
275                 return;
276             }
277             String pkgName = uri.getSchemeSpecificPart();
278             if (pkgName == null) {
279                 return;
280             }
281             pkgList = new String[] { pkgName };
282             added = Intent.ACTION_PACKAGE_ADDED.equals(action);
283             changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
284         }
285         if (pkgList == null || pkgList.length == 0) {
286             return;
287         }
288         if (added || changed) {
289             synchronized (mAppWidgetIds) {
290                 ensureStateLoadedLocked();
291                 Bundle extras = intent.getExtras();
292                 if (changed
293                         || (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
294                     for (String pkgName : pkgList) {
295                         // The package was just upgraded
296                         providersModified |= updateProvidersForPackageLocked(pkgName, null);
297                     }
298                 } else {
299                     // The package was just added
300                     for (String pkgName : pkgList) {
301                         providersModified |= addProvidersForPackageLocked(pkgName);
302                     }
303                 }
304                 saveStateAsync();
305             }
306         } else {
307             Bundle extras = intent.getExtras();
308             if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
309                 // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
310             } else {
311                 synchronized (mAppWidgetIds) {
312                     ensureStateLoadedLocked();
313                     for (String pkgName : pkgList) {
314                         providersModified |= removeProvidersForPackageLocked(pkgName);
315                         saveStateAsync();
316                     }
317                 }
318             }
319         }
320 
321         if (providersModified) {
322             // If the set of providers has been modified, notify each active AppWidgetHost
323             synchronized (mAppWidgetIds) {
324                 ensureStateLoadedLocked();
325                 notifyHostsForProvidersChangedLocked();
326             }
327         }
328     }
329 
dumpProvider(Provider p, int index, PrintWriter pw)330     private void dumpProvider(Provider p, int index, PrintWriter pw) {
331         AppWidgetProviderInfo info = p.info;
332         pw.print("  ["); pw.print(index); pw.print("] provider ");
333                 pw.print(info.provider.flattenToShortString());
334                 pw.println(':');
335         pw.print("    min=("); pw.print(info.minWidth);
336                 pw.print("x"); pw.print(info.minHeight);
337         pw.print(")   minResize=("); pw.print(info.minResizeWidth);
338                 pw.print("x"); pw.print(info.minResizeHeight);
339                 pw.print(") updatePeriodMillis=");
340                 pw.print(info.updatePeriodMillis);
341                 pw.print(" resizeMode=");
342                 pw.print(info.resizeMode);
343                 pw.print(info.widgetCategory);
344                 pw.print(" autoAdvanceViewId=");
345                 pw.print(info.autoAdvanceViewId);
346                 pw.print(" initialLayout=#");
347                 pw.print(Integer.toHexString(info.initialLayout));
348                 pw.print(" uid="); pw.print(p.uid);
349                 pw.print(" zombie="); pw.println(p.zombie);
350     }
351 
dumpHost(Host host, int index, PrintWriter pw)352     private void dumpHost(Host host, int index, PrintWriter pw) {
353         pw.print("  ["); pw.print(index); pw.print("] hostId=");
354                 pw.print(host.hostId); pw.print(' ');
355                 pw.print(host.packageName); pw.print('/');
356         pw.print(host.uid); pw.println(':');
357         pw.print("    callbacks="); pw.println(host.callbacks);
358         pw.print("    instances.size="); pw.print(host.instances.size());
359                 pw.print(" zombie="); pw.println(host.zombie);
360     }
361 
dumpAppWidgetId(AppWidgetId id, int index, PrintWriter pw)362     private void dumpAppWidgetId(AppWidgetId id, int index, PrintWriter pw) {
363         pw.print("  ["); pw.print(index); pw.print("] id=");
364                 pw.println(id.appWidgetId);
365         pw.print("    hostId=");
366                 pw.print(id.host.hostId); pw.print(' ');
367                 pw.print(id.host.packageName); pw.print('/');
368                 pw.println(id.host.uid);
369         if (id.provider != null) {
370             pw.print("    provider=");
371                     pw.println(id.provider.info.provider.flattenToShortString());
372         }
373         if (id.host != null) {
374             pw.print("    host.callbacks="); pw.println(id.host.callbacks);
375         }
376         if (id.views != null) {
377             pw.print("    views="); pw.println(id.views);
378         }
379     }
380 
dump(FileDescriptor fd, PrintWriter pw, String[] args)381     void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
382         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
383                 != PackageManager.PERMISSION_GRANTED) {
384             pw.println("Permission Denial: can't dump from from pid="
385                     + Binder.getCallingPid()
386                     + ", uid=" + Binder.getCallingUid());
387             return;
388         }
389 
390         synchronized (mAppWidgetIds) {
391             int N = mInstalledProviders.size();
392             pw.println("Providers:");
393             for (int i=0; i<N; i++) {
394                 dumpProvider(mInstalledProviders.get(i), i, pw);
395             }
396 
397             N = mAppWidgetIds.size();
398             pw.println(" ");
399             pw.println("AppWidgetIds:");
400             for (int i=0; i<N; i++) {
401                 dumpAppWidgetId(mAppWidgetIds.get(i), i, pw);
402             }
403 
404             N = mHosts.size();
405             pw.println(" ");
406             pw.println("Hosts:");
407             for (int i=0; i<N; i++) {
408                 dumpHost(mHosts.get(i), i, pw);
409             }
410 
411             N = mDeletedProviders.size();
412             pw.println(" ");
413             pw.println("Deleted Providers:");
414             for (int i=0; i<N; i++) {
415                 dumpProvider(mDeletedProviders.get(i), i, pw);
416             }
417 
418             N = mDeletedHosts.size();
419             pw.println(" ");
420             pw.println("Deleted Hosts:");
421             for (int i=0; i<N; i++) {
422                 dumpHost(mDeletedHosts.get(i), i, pw);
423             }
424         }
425     }
426 
ensureStateLoadedLocked()427     private void ensureStateLoadedLocked() {
428         if (!mStateLoaded) {
429             loadAppWidgetListLocked();
430             loadStateLocked();
431             mStateLoaded = true;
432         }
433     }
434 
allocateAppWidgetId(String packageName, int hostId)435     public int allocateAppWidgetId(String packageName, int hostId) {
436         int callingUid = enforceSystemOrCallingUid(packageName);
437         synchronized (mAppWidgetIds) {
438             ensureStateLoadedLocked();
439             int appWidgetId = mNextAppWidgetId++;
440 
441             Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
442 
443             AppWidgetId id = new AppWidgetId();
444             id.appWidgetId = appWidgetId;
445             id.host = host;
446 
447             host.instances.add(id);
448             mAppWidgetIds.add(id);
449 
450             saveStateAsync();
451             if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
452                     + " id=" + appWidgetId);
453             return appWidgetId;
454         }
455     }
456 
deleteAppWidgetId(int appWidgetId)457     public void deleteAppWidgetId(int appWidgetId) {
458         synchronized (mAppWidgetIds) {
459             ensureStateLoadedLocked();
460             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
461             if (id != null) {
462                 deleteAppWidgetLocked(id);
463                 saveStateAsync();
464             }
465         }
466     }
467 
deleteHost(int hostId)468     public void deleteHost(int hostId) {
469         synchronized (mAppWidgetIds) {
470             ensureStateLoadedLocked();
471             int callingUid = Binder.getCallingUid();
472             Host host = lookupHostLocked(callingUid, hostId);
473             if (host != null) {
474                 deleteHostLocked(host);
475                 saveStateAsync();
476             }
477         }
478     }
479 
deleteAllHosts()480     public void deleteAllHosts() {
481         synchronized (mAppWidgetIds) {
482             ensureStateLoadedLocked();
483             int callingUid = Binder.getCallingUid();
484             final int N = mHosts.size();
485             boolean changed = false;
486             for (int i = N - 1; i >= 0; i--) {
487                 Host host = mHosts.get(i);
488                 if (host.uidMatches(callingUid)) {
489                     deleteHostLocked(host);
490                     changed = true;
491                 }
492             }
493             if (changed) {
494                 saveStateAsync();
495             }
496         }
497     }
498 
deleteHostLocked(Host host)499     void deleteHostLocked(Host host) {
500         final int N = host.instances.size();
501         for (int i = N - 1; i >= 0; i--) {
502             AppWidgetId id = host.instances.get(i);
503             deleteAppWidgetLocked(id);
504         }
505         host.instances.clear();
506         mHosts.remove(host);
507         mDeletedHosts.add(host);
508         // it's gone or going away, abruptly drop the callback connection
509         host.callbacks = null;
510     }
511 
deleteAppWidgetLocked(AppWidgetId id)512     void deleteAppWidgetLocked(AppWidgetId id) {
513         // We first unbind all services that are bound to this id
514         unbindAppWidgetRemoteViewsServicesLocked(id);
515 
516         Host host = id.host;
517         host.instances.remove(id);
518         pruneHostLocked(host);
519 
520         mAppWidgetIds.remove(id);
521 
522         Provider p = id.provider;
523         if (p != null) {
524             p.instances.remove(id);
525             if (!p.zombie) {
526                 // send the broacast saying that this appWidgetId has been deleted
527                 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
528                 intent.setComponent(p.info.provider);
529                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
530                 mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
531                 if (p.instances.size() == 0) {
532                     // cancel the future updates
533                     cancelBroadcasts(p);
534 
535                     // send the broacast saying that the provider is not in use any more
536                     intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
537                     intent.setComponent(p.info.provider);
538                     mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
539                 }
540             }
541         }
542     }
543 
cancelBroadcasts(Provider p)544     void cancelBroadcasts(Provider p) {
545         if (DBG) log("cancelBroadcasts for " + p);
546         if (p.broadcast != null) {
547             mAlarmManager.cancel(p.broadcast);
548             long token = Binder.clearCallingIdentity();
549             try {
550                 p.broadcast.cancel();
551             } finally {
552                 Binder.restoreCallingIdentity(token);
553             }
554             p.broadcast = null;
555         }
556     }
557 
bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options)558     private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
559         if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId
560                 + " provider=" + provider);
561         final long ident = Binder.clearCallingIdentity();
562         try {
563             synchronized (mAppWidgetIds) {
564                 options = cloneIfLocalBinder(options);
565                 ensureStateLoadedLocked();
566                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
567                 if (id == null) {
568                     throw new IllegalArgumentException("bad appWidgetId");
569                 }
570                 if (id.provider != null) {
571                     throw new IllegalArgumentException("appWidgetId " + appWidgetId
572                             + " already bound to " + id.provider.info.provider);
573                 }
574                 Provider p = lookupProviderLocked(provider);
575                 if (p == null) {
576                     throw new IllegalArgumentException("not a appwidget provider: " + provider);
577                 }
578                 if (p.zombie) {
579                     throw new IllegalArgumentException("can't bind to a 3rd party provider in"
580                             + " safe mode: " + provider);
581                 }
582 
583                 id.provider = p;
584                 if (options == null) {
585                     options = new Bundle();
586                 }
587                 id.options = options;
588 
589                 // We need to provide a default value for the widget category if it is not specified
590                 if (!options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
591                     options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
592                             AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
593                 }
594 
595                 p.instances.add(id);
596                 int instancesSize = p.instances.size();
597                 if (instancesSize == 1) {
598                     // tell the provider that it's ready
599                     sendEnableIntentLocked(p);
600                 }
601 
602                 // send an update now -- We need this update now, and just for this appWidgetId.
603                 // It's less critical when the next one happens, so when we schedule the next one,
604                 // we add updatePeriodMillis to its start time. That time will have some slop,
605                 // but that's okay.
606                 sendUpdateIntentLocked(p, new int[] { appWidgetId });
607 
608                 // schedule the future updates
609                 registerForBroadcastsLocked(p, getAppWidgetIds(p));
610                 saveStateAsync();
611             }
612         } finally {
613             Binder.restoreCallingIdentity(ident);
614         }
615     }
616 
bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)617     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
618         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET,
619             "bindAppWidgetId appWidgetId=" + appWidgetId + " provider=" + provider);
620         bindAppWidgetIdImpl(appWidgetId, provider, options);
621     }
622 
bindAppWidgetIdIfAllowed( String packageName, int appWidgetId, ComponentName provider, Bundle options)623     public boolean bindAppWidgetIdIfAllowed(
624             String packageName, int appWidgetId, ComponentName provider, Bundle options) {
625         try {
626             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, null);
627         } catch (SecurityException se) {
628             if (!callerHasBindAppWidgetPermission(packageName)) {
629                 return false;
630             }
631         }
632         bindAppWidgetIdImpl(appWidgetId, provider, options);
633         return true;
634     }
635 
callerHasBindAppWidgetPermission(String packageName)636     private boolean callerHasBindAppWidgetPermission(String packageName) {
637         int callingUid = Binder.getCallingUid();
638         try {
639             if (!UserHandle.isSameApp(callingUid, getUidForPackage(packageName))) {
640                 return false;
641             }
642         } catch (Exception e) {
643             return false;
644         }
645         synchronized (mAppWidgetIds) {
646             ensureStateLoadedLocked();
647             return mPackagesWithBindWidgetPermission.contains(packageName);
648         }
649     }
650 
hasBindAppWidgetPermission(String packageName)651     public boolean hasBindAppWidgetPermission(String packageName) {
652         mContext.enforceCallingPermission(
653                 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
654                 "hasBindAppWidgetPermission packageName=" + packageName);
655 
656         synchronized (mAppWidgetIds) {
657             ensureStateLoadedLocked();
658             return mPackagesWithBindWidgetPermission.contains(packageName);
659         }
660     }
661 
setBindAppWidgetPermission(String packageName, boolean permission)662     public void setBindAppWidgetPermission(String packageName, boolean permission) {
663         mContext.enforceCallingPermission(
664                 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
665                 "setBindAppWidgetPermission packageName=" + packageName);
666 
667         synchronized (mAppWidgetIds) {
668             ensureStateLoadedLocked();
669             if (permission) {
670                 mPackagesWithBindWidgetPermission.add(packageName);
671             } else {
672                 mPackagesWithBindWidgetPermission.remove(packageName);
673             }
674             saveStateAsync();
675         }
676     }
677 
678     // Binds to a specific RemoteViewsService
bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)679     public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
680         synchronized (mAppWidgetIds) {
681             ensureStateLoadedLocked();
682             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
683             if (id == null) {
684                 throw new IllegalArgumentException("bad appWidgetId");
685             }
686             final ComponentName componentName = intent.getComponent();
687             try {
688                 final ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(componentName,
689                         PackageManager.GET_PERMISSIONS, mUserId);
690                 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) {
691                     throw new SecurityException("Selected service does not require "
692                             + android.Manifest.permission.BIND_REMOTEVIEWS + ": " + componentName);
693                 }
694             } catch (RemoteException e) {
695                 throw new IllegalArgumentException("Unknown component " + componentName);
696             }
697 
698             // If there is already a connection made for this service intent, then disconnect from
699             // that first. (This does not allow multiple connections to the same service under
700             // the same key)
701             ServiceConnectionProxy conn = null;
702             FilterComparison fc = new FilterComparison(intent);
703             Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
704             if (mBoundRemoteViewsServices.containsKey(key)) {
705                 conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
706                 conn.disconnect();
707                 mContext.unbindService(conn);
708                 mBoundRemoteViewsServices.remove(key);
709             }
710 
711             int userId = UserHandle.getUserId(id.provider.uid);
712             if (userId != mUserId) {
713                 Slog.w(TAG, "AppWidgetServiceImpl of user " + mUserId
714                         + " binding to provider on user " + userId);
715             }
716             // Bind to the RemoteViewsService (which will trigger a callback to the
717             // RemoteViewsAdapter.onServiceConnected())
718             final long token = Binder.clearCallingIdentity();
719             try {
720                 conn = new ServiceConnectionProxy(key, connection);
721                 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
722                 mBoundRemoteViewsServices.put(key, conn);
723             } finally {
724                 Binder.restoreCallingIdentity(token);
725             }
726 
727             // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine
728             // when we can call back to the RemoteViewsService later to destroy associated
729             // factories.
730             incrementAppWidgetServiceRefCount(appWidgetId, fc);
731         }
732     }
733 
734     // Unbinds from a specific RemoteViewsService
unbindRemoteViewsService(int appWidgetId, Intent intent)735     public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
736         synchronized (mAppWidgetIds) {
737             ensureStateLoadedLocked();
738             // Unbind from the RemoteViewsService (which will trigger a callback to the bound
739             // RemoteViewsAdapter)
740             Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, new FilterComparison(
741                     intent));
742             if (mBoundRemoteViewsServices.containsKey(key)) {
743                 // We don't need to use the appWidgetId until after we are sure there is something
744                 // to unbind. Note that this may mask certain issues with apps calling unbind()
745                 // more than necessary.
746                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
747                 if (id == null) {
748                     throw new IllegalArgumentException("bad appWidgetId");
749                 }
750 
751                 ServiceConnectionProxy conn = (ServiceConnectionProxy) mBoundRemoteViewsServices
752                         .get(key);
753                 conn.disconnect();
754                 mContext.unbindService(conn);
755                 mBoundRemoteViewsServices.remove(key);
756             }
757         }
758     }
759 
760     // Unbinds from a RemoteViewsService when we delete an app widget
unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id)761     private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
762         int appWidgetId = id.appWidgetId;
763         // Unbind all connections to Services bound to this AppWidgetId
764         Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet()
765                 .iterator();
766         while (it.hasNext()) {
767             final Pair<Integer, Intent.FilterComparison> key = it.next();
768             if (key.first.intValue() == appWidgetId) {
769                 final ServiceConnectionProxy conn = (ServiceConnectionProxy) mBoundRemoteViewsServices
770                         .get(key);
771                 conn.disconnect();
772                 mContext.unbindService(conn);
773                 it.remove();
774             }
775         }
776 
777         // Check if we need to destroy any services (if no other app widgets are
778         // referencing the same service)
779         decrementAppWidgetServiceRefCount(id);
780     }
781 
782     // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
destroyRemoteViewsService(final Intent intent, AppWidgetId id)783     private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) {
784         final ServiceConnection conn = new ServiceConnection() {
785             @Override
786             public void onServiceConnected(ComponentName name, IBinder service) {
787                 final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service);
788                 try {
789                     cb.onDestroy(intent);
790                 } catch (RemoteException e) {
791                     e.printStackTrace();
792                 } catch (RuntimeException e) {
793                     e.printStackTrace();
794                 }
795                 mContext.unbindService(this);
796             }
797 
798             @Override
799             public void onServiceDisconnected(android.content.ComponentName name) {
800                 // Do nothing
801             }
802         };
803 
804         int userId = UserHandle.getUserId(id.provider.uid);
805         // Bind to the service and remove the static intent->factory mapping in the
806         // RemoteViewsService.
807         final long token = Binder.clearCallingIdentity();
808         try {
809             mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
810         } finally {
811             Binder.restoreCallingIdentity(token);
812         }
813     }
814 
815     // Adds to the ref-count for a given RemoteViewsService intent
incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc)816     private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) {
817         HashSet<Integer> appWidgetIds = null;
818         if (mRemoteViewsServicesAppWidgets.containsKey(fc)) {
819             appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc);
820         } else {
821             appWidgetIds = new HashSet<Integer>();
822             mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds);
823         }
824         appWidgetIds.add(appWidgetId);
825     }
826 
827     // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
828     // the ref-count reaches zero.
decrementAppWidgetServiceRefCount(AppWidgetId id)829     private void decrementAppWidgetServiceRefCount(AppWidgetId id) {
830         Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator();
831         while (it.hasNext()) {
832             final FilterComparison key = it.next();
833             final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
834             if (ids.remove(id.appWidgetId)) {
835                 // If we have removed the last app widget referencing this service, then we
836                 // should destroy it and remove it from this set
837                 if (ids.isEmpty()) {
838                     destroyRemoteViewsService(key.getIntent(), id);
839                     it.remove();
840                 }
841             }
842         }
843     }
844 
getAppWidgetInfo(int appWidgetId)845     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
846         synchronized (mAppWidgetIds) {
847             ensureStateLoadedLocked();
848             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
849             if (id != null && id.provider != null && !id.provider.zombie) {
850                 return cloneIfLocalBinder(id.provider.info);
851             }
852             return null;
853         }
854     }
855 
getAppWidgetViews(int appWidgetId)856     public RemoteViews getAppWidgetViews(int appWidgetId) {
857         if (DBG) log("getAppWidgetViews id=" + appWidgetId);
858         synchronized (mAppWidgetIds) {
859             ensureStateLoadedLocked();
860             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
861             if (id != null) {
862                 return cloneIfLocalBinder(id.views);
863             }
864             if (DBG) log("   couldn't find appwidgetid");
865             return null;
866         }
867     }
868 
getInstalledProviders(int categoryFilter)869     public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
870         synchronized (mAppWidgetIds) {
871             ensureStateLoadedLocked();
872             final int N = mInstalledProviders.size();
873             ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
874             for (int i = 0; i < N; i++) {
875                 Provider p = mInstalledProviders.get(i);
876                 if (!p.zombie && (p.info.widgetCategory & categoryFilter) != 0) {
877                     result.add(cloneIfLocalBinder(p.info));
878                 }
879             }
880             return result;
881         }
882     }
883 
updateAppWidgetIds(int[] appWidgetIds, RemoteViews views)884     public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
885         if (appWidgetIds == null) {
886             return;
887         }
888         if (DBG) log("updateAppWidgetIds views: " + views);
889         int bitmapMemoryUsage = 0;
890         if (views != null) {
891             bitmapMemoryUsage = views.estimateMemoryUsage();
892         }
893         if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) {
894             throw new IllegalArgumentException("RemoteViews for widget update exceeds maximum" +
895                     " bitmap memory usage (used: " + bitmapMemoryUsage + ", max: " +
896                     mMaxWidgetBitmapMemory + ") The total memory cannot exceed that required to" +
897                     " fill the device's screen once.");
898         }
899 
900         if (appWidgetIds.length == 0) {
901             return;
902         }
903         final int N = appWidgetIds.length;
904 
905         synchronized (mAppWidgetIds) {
906             ensureStateLoadedLocked();
907             for (int i = 0; i < N; i++) {
908                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
909                 updateAppWidgetInstanceLocked(id, views);
910             }
911         }
912     }
913 
saveStateAsync()914     private void saveStateAsync() {
915         mSaveStateHandler.post(mSaveStateRunnable);
916     }
917 
918     private final Runnable mSaveStateRunnable = new Runnable() {
919         @Override
920         public void run() {
921             synchronized (mAppWidgetIds) {
922                 ensureStateLoadedLocked();
923                 saveStateLocked();
924             }
925         }
926     };
927 
updateAppWidgetOptions(int appWidgetId, Bundle options)928     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
929         synchronized (mAppWidgetIds) {
930             options = cloneIfLocalBinder(options);
931             ensureStateLoadedLocked();
932             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
933 
934             if (id == null) {
935                 return;
936             }
937 
938             Provider p = id.provider;
939             // Merge the options
940             id.options.putAll(options);
941 
942             // send the broacast saying that this appWidgetId has been deleted
943             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED);
944             intent.setComponent(p.info.provider);
945             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
946             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, id.options);
947             mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
948             saveStateAsync();
949         }
950     }
951 
getAppWidgetOptions(int appWidgetId)952     public Bundle getAppWidgetOptions(int appWidgetId) {
953         synchronized (mAppWidgetIds) {
954             ensureStateLoadedLocked();
955             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
956             if (id != null && id.options != null) {
957                 return cloneIfLocalBinder(id.options);
958             } else {
959                 return Bundle.EMPTY;
960             }
961         }
962     }
963 
partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)964     public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
965         if (appWidgetIds == null) {
966             return;
967         }
968         if (appWidgetIds.length == 0) {
969             return;
970         }
971         final int N = appWidgetIds.length;
972 
973         synchronized (mAppWidgetIds) {
974             ensureStateLoadedLocked();
975             for (int i = 0; i < N; i++) {
976                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
977                 if (id == null) {
978                     Slog.w(TAG, "widget id " + appWidgetIds[i] + " not found!");
979                 } else if (id.views != null) {
980                     // Only trigger a partial update for a widget if it has received a full update
981                     updateAppWidgetInstanceLocked(id, views, true);
982                 }
983             }
984         }
985     }
986 
notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)987     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
988         if (appWidgetIds == null) {
989             return;
990         }
991         if (appWidgetIds.length == 0) {
992             return;
993         }
994         final int N = appWidgetIds.length;
995 
996         synchronized (mAppWidgetIds) {
997             ensureStateLoadedLocked();
998             for (int i = 0; i < N; i++) {
999                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
1000                 notifyAppWidgetViewDataChangedInstanceLocked(id, viewId);
1001             }
1002         }
1003     }
1004 
updateAppWidgetProvider(ComponentName provider, RemoteViews views)1005     public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
1006         synchronized (mAppWidgetIds) {
1007             ensureStateLoadedLocked();
1008             Provider p = lookupProviderLocked(provider);
1009             if (p == null) {
1010                 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
1011                 return;
1012             }
1013             ArrayList<AppWidgetId> instances = p.instances;
1014             final int callingUid = Binder.getCallingUid();
1015             final int N = instances.size();
1016             for (int i = 0; i < N; i++) {
1017                 AppWidgetId id = instances.get(i);
1018                 if (canAccessAppWidgetId(id, callingUid)) {
1019                     updateAppWidgetInstanceLocked(id, views);
1020                 }
1021             }
1022         }
1023     }
1024 
updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views)1025     void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
1026         updateAppWidgetInstanceLocked(id, views, false);
1027     }
1028 
updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate)1029     void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) {
1030         // allow for stale appWidgetIds and other badness
1031         // lookup also checks that the calling process can access the appWidgetId
1032         // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
1033         if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
1034 
1035             if (!isPartialUpdate) {
1036                 // For a full update we replace the RemoteViews completely.
1037                 id.views = views;
1038             } else {
1039                 // For a partial update, we merge the new RemoteViews with the old.
1040                 id.views.mergeRemoteViews(views);
1041             }
1042 
1043             // is anyone listening?
1044             if (id.host.callbacks != null) {
1045                 try {
1046                     // the lock is held, but this is a oneway call
1047                     id.host.callbacks.updateAppWidget(id.appWidgetId, views);
1048                 } catch (RemoteException e) {
1049                     // It failed; remove the callback. No need to prune because
1050                     // we know that this host is still referenced by this instance.
1051                     id.host.callbacks = null;
1052                 }
1053             }
1054         }
1055     }
1056 
notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId)1057     void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) {
1058         // allow for stale appWidgetIds and other badness
1059         // lookup also checks that the calling process can access the appWidgetId
1060         // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
1061         if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
1062             // is anyone listening?
1063             if (id.host.callbacks != null) {
1064                 try {
1065                     // the lock is held, but this is a oneway call
1066                     id.host.callbacks.viewDataChanged(id.appWidgetId, viewId);
1067                 } catch (RemoteException e) {
1068                     // It failed; remove the callback. No need to prune because
1069                     // we know that this host is still referenced by this instance.
1070                     id.host.callbacks = null;
1071                 }
1072             }
1073 
1074             // If the host is unavailable, then we call the associated
1075             // RemoteViewsFactory.onDataSetChanged() directly
1076             if (id.host.callbacks == null) {
1077                 Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet();
1078                 for (FilterComparison key : keys) {
1079                     if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) {
1080                         Intent intent = key.getIntent();
1081 
1082                         final ServiceConnection conn = new ServiceConnection() {
1083                             @Override
1084                             public void onServiceConnected(ComponentName name, IBinder service) {
1085                                 IRemoteViewsFactory cb = IRemoteViewsFactory.Stub
1086                                         .asInterface(service);
1087                                 try {
1088                                     cb.onDataSetChangedAsync();
1089                                 } catch (RemoteException e) {
1090                                     e.printStackTrace();
1091                                 } catch (RuntimeException e) {
1092                                     e.printStackTrace();
1093                                 }
1094                                 mContext.unbindService(this);
1095                             }
1096 
1097                             @Override
1098                             public void onServiceDisconnected(android.content.ComponentName name) {
1099                                 // Do nothing
1100                             }
1101                         };
1102 
1103                         int userId = UserHandle.getUserId(id.provider.uid);
1104                         // Bind to the service and call onDataSetChanged()
1105                         final long token = Binder.clearCallingIdentity();
1106                         try {
1107                             mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
1108                         } finally {
1109                             Binder.restoreCallingIdentity(token);
1110                         }
1111                     }
1112                 }
1113             }
1114         }
1115     }
1116 
isLocalBinder()1117     private boolean isLocalBinder() {
1118         return Process.myPid() == Binder.getCallingPid();
1119     }
1120 
cloneIfLocalBinder(RemoteViews rv)1121     private RemoteViews cloneIfLocalBinder(RemoteViews rv) {
1122         if (isLocalBinder() && rv != null) {
1123             return rv.clone();
1124         }
1125         return rv;
1126     }
1127 
cloneIfLocalBinder(AppWidgetProviderInfo info)1128     private AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
1129         if (isLocalBinder() && info != null) {
1130             return info.clone();
1131         }
1132         return info;
1133     }
1134 
cloneIfLocalBinder(Bundle bundle)1135     private Bundle cloneIfLocalBinder(Bundle bundle) {
1136         // Note: this is only a shallow copy. For now this will be fine, but it could be problematic
1137         // if we start adding objects to the options. Further, it would only be an issue if keyguard
1138         // used such options.
1139         if (isLocalBinder() && bundle != null) {
1140             return (Bundle) bundle.clone();
1141         }
1142         return bundle;
1143     }
1144 
startListening(IAppWidgetHost callbacks, String packageName, int hostId, List<RemoteViews> updatedViews)1145     public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
1146             List<RemoteViews> updatedViews) {
1147         int callingUid = enforceCallingUid(packageName);
1148         synchronized (mAppWidgetIds) {
1149             ensureStateLoadedLocked();
1150             Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
1151             host.callbacks = callbacks;
1152 
1153             updatedViews.clear();
1154 
1155             ArrayList<AppWidgetId> instances = host.instances;
1156             int N = instances.size();
1157             int[] updatedIds = new int[N];
1158             for (int i = 0; i < N; i++) {
1159                 AppWidgetId id = instances.get(i);
1160                 updatedIds[i] = id.appWidgetId;
1161                 updatedViews.add(cloneIfLocalBinder(id.views));
1162             }
1163             return updatedIds;
1164         }
1165     }
1166 
stopListening(int hostId)1167     public void stopListening(int hostId) {
1168         synchronized (mAppWidgetIds) {
1169             ensureStateLoadedLocked();
1170             Host host = lookupHostLocked(Binder.getCallingUid(), hostId);
1171             if (host != null) {
1172                 host.callbacks = null;
1173                 pruneHostLocked(host);
1174             }
1175         }
1176     }
1177 
canAccessAppWidgetId(AppWidgetId id, int callingUid)1178     boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
1179         if (id.host.uidMatches(callingUid)) {
1180             // Apps hosting the AppWidget have access to it.
1181             return true;
1182         }
1183         if (id.provider != null && id.provider.uid == callingUid) {
1184             // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
1185             return true;
1186         }
1187         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET) == PackageManager.PERMISSION_GRANTED) {
1188             // Apps that can bind have access to all appWidgetIds.
1189             return true;
1190         }
1191         // Nobody else can access it.
1192         return false;
1193     }
1194 
lookupAppWidgetIdLocked(int appWidgetId)1195     AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
1196         int callingUid = Binder.getCallingUid();
1197         final int N = mAppWidgetIds.size();
1198         for (int i = 0; i < N; i++) {
1199             AppWidgetId id = mAppWidgetIds.get(i);
1200             if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
1201                 return id;
1202             }
1203         }
1204         return null;
1205     }
1206 
lookupProviderLocked(ComponentName provider)1207     Provider lookupProviderLocked(ComponentName provider) {
1208         final int N = mInstalledProviders.size();
1209         for (int i = 0; i < N; i++) {
1210             Provider p = mInstalledProviders.get(i);
1211             if (p.info.provider.equals(provider)) {
1212                 return p;
1213             }
1214         }
1215         return null;
1216     }
1217 
lookupHostLocked(int uid, int hostId)1218     Host lookupHostLocked(int uid, int hostId) {
1219         final int N = mHosts.size();
1220         for (int i = 0; i < N; i++) {
1221             Host h = mHosts.get(i);
1222             if (h.uidMatches(uid) && h.hostId == hostId) {
1223                 return h;
1224             }
1225         }
1226         return null;
1227     }
1228 
lookupOrAddHostLocked(int uid, String packageName, int hostId)1229     Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
1230         final int N = mHosts.size();
1231         for (int i = 0; i < N; i++) {
1232             Host h = mHosts.get(i);
1233             if (h.hostId == hostId && h.packageName.equals(packageName)) {
1234                 return h;
1235             }
1236         }
1237         Host host = new Host();
1238         host.packageName = packageName;
1239         host.uid = uid;
1240         host.hostId = hostId;
1241         mHosts.add(host);
1242         return host;
1243     }
1244 
pruneHostLocked(Host host)1245     void pruneHostLocked(Host host) {
1246         if (host.instances.size() == 0 && host.callbacks == null) {
1247             mHosts.remove(host);
1248         }
1249     }
1250 
loadAppWidgetListLocked()1251     void loadAppWidgetListLocked() {
1252         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1253         try {
1254             List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent,
1255                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
1256                     PackageManager.GET_META_DATA, mUserId);
1257 
1258             final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
1259             for (int i = 0; i < N; i++) {
1260                 ResolveInfo ri = broadcastReceivers.get(i);
1261                 addProviderLocked(ri);
1262             }
1263         } catch (RemoteException re) {
1264             // Shouldn't happen, local call
1265         }
1266     }
1267 
addProviderLocked(ResolveInfo ri)1268     boolean addProviderLocked(ResolveInfo ri) {
1269         if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1270             return false;
1271         }
1272         if (!ri.activityInfo.isEnabled()) {
1273             return false;
1274         }
1275         Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
1276                 ri.activityInfo.name), ri);
1277         if (p != null) {
1278             mInstalledProviders.add(p);
1279             return true;
1280         } else {
1281             return false;
1282         }
1283     }
1284 
removeProviderLocked(int index, Provider p)1285     void removeProviderLocked(int index, Provider p) {
1286         int N = p.instances.size();
1287         for (int i = 0; i < N; i++) {
1288             AppWidgetId id = p.instances.get(i);
1289             // Call back with empty RemoteViews
1290             updateAppWidgetInstanceLocked(id, null);
1291             // Stop telling the host about updates for this from now on
1292             cancelBroadcasts(p);
1293             // clear out references to this appWidgetId
1294             id.host.instances.remove(id);
1295             mAppWidgetIds.remove(id);
1296             id.provider = null;
1297             pruneHostLocked(id.host);
1298             id.host = null;
1299         }
1300         p.instances.clear();
1301         mInstalledProviders.remove(index);
1302         mDeletedProviders.add(p);
1303         // no need to send the DISABLE broadcast, since the receiver is gone anyway
1304         cancelBroadcasts(p);
1305     }
1306 
sendEnableIntentLocked(Provider p)1307     void sendEnableIntentLocked(Provider p) {
1308         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
1309         intent.setComponent(p.info.provider);
1310         mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
1311     }
1312 
sendUpdateIntentLocked(Provider p, int[] appWidgetIds)1313     void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
1314         if (appWidgetIds != null && appWidgetIds.length > 0) {
1315             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1316             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
1317             intent.setComponent(p.info.provider);
1318             mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
1319         }
1320     }
1321 
registerForBroadcastsLocked(Provider p, int[] appWidgetIds)1322     void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
1323         if (p.info.updatePeriodMillis > 0) {
1324             // if this is the first instance, set the alarm. otherwise,
1325             // rely on the fact that we've already set it and that
1326             // PendingIntent.getBroadcast will update the extras.
1327             boolean alreadyRegistered = p.broadcast != null;
1328             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1329             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
1330             intent.setComponent(p.info.provider);
1331             long token = Binder.clearCallingIdentity();
1332             try {
1333                 p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
1334                         PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId));
1335             } finally {
1336                 Binder.restoreCallingIdentity(token);
1337             }
1338             if (!alreadyRegistered) {
1339                 long period = p.info.updatePeriodMillis;
1340                 if (period < MIN_UPDATE_PERIOD) {
1341                     period = MIN_UPDATE_PERIOD;
1342                 }
1343                 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock
1344                         .elapsedRealtime()
1345                         + period, period, p.broadcast);
1346             }
1347         }
1348     }
1349 
getAppWidgetIds(Provider p)1350     static int[] getAppWidgetIds(Provider p) {
1351         int instancesSize = p.instances.size();
1352         int appWidgetIds[] = new int[instancesSize];
1353         for (int i = 0; i < instancesSize; i++) {
1354             appWidgetIds[i] = p.instances.get(i).appWidgetId;
1355         }
1356         return appWidgetIds;
1357     }
1358 
getAppWidgetIds(ComponentName provider)1359     public int[] getAppWidgetIds(ComponentName provider) {
1360         synchronized (mAppWidgetIds) {
1361             ensureStateLoadedLocked();
1362             Provider p = lookupProviderLocked(provider);
1363             if (p != null && Binder.getCallingUid() == p.uid) {
1364                 return getAppWidgetIds(p);
1365             } else {
1366                 return new int[0];
1367             }
1368         }
1369     }
1370 
getAppWidgetIds(Host h)1371     static int[] getAppWidgetIds(Host h) {
1372         int instancesSize = h.instances.size();
1373         int appWidgetIds[] = new int[instancesSize];
1374         for (int i = 0; i < instancesSize; i++) {
1375             appWidgetIds[i] = h.instances.get(i).appWidgetId;
1376         }
1377         return appWidgetIds;
1378     }
1379 
getAppWidgetIdsForHost(int hostId)1380     public int[] getAppWidgetIdsForHost(int hostId) {
1381         synchronized (mAppWidgetIds) {
1382             ensureStateLoadedLocked();
1383             int callingUid = Binder.getCallingUid();
1384             Host host = lookupHostLocked(callingUid, hostId);
1385             if (host != null) {
1386                 return getAppWidgetIds(host);
1387             } else {
1388                 return new int[0];
1389             }
1390         }
1391     }
1392 
parseProviderInfoXml(ComponentName component, ResolveInfo ri)1393     private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
1394         Provider p = null;
1395 
1396         ActivityInfo activityInfo = ri.activityInfo;
1397         XmlResourceParser parser = null;
1398         try {
1399             parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(),
1400                     AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
1401             if (parser == null) {
1402                 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER
1403                         + " meta-data for " + "AppWidget provider '" + component + '\'');
1404                 return null;
1405             }
1406 
1407             AttributeSet attrs = Xml.asAttributeSet(parser);
1408 
1409             int type;
1410             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1411                     && type != XmlPullParser.START_TAG) {
1412                 // drain whitespace, comments, etc.
1413             }
1414 
1415             String nodeName = parser.getName();
1416             if (!"appwidget-provider".equals(nodeName)) {
1417                 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
1418                         + " AppWidget provider '" + component + '\'');
1419                 return null;
1420             }
1421 
1422             p = new Provider();
1423             AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
1424             info.provider = component;
1425             p.uid = activityInfo.applicationInfo.uid;
1426 
1427             Resources res = mContext.getPackageManager()
1428                     .getResourcesForApplicationAsUser(activityInfo.packageName, mUserId);
1429 
1430             TypedArray sa = res.obtainAttributes(attrs,
1431                     com.android.internal.R.styleable.AppWidgetProviderInfo);
1432 
1433             // These dimensions has to be resolved in the application's context.
1434             // We simply send back the raw complex data, which will be
1435             // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
1436             TypedValue value = sa
1437                     .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
1438             info.minWidth = value != null ? value.data : 0;
1439             value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
1440             info.minHeight = value != null ? value.data : 0;
1441             value = sa.peekValue(
1442                     com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
1443             info.minResizeWidth = value != null ? value.data : info.minWidth;
1444             value = sa.peekValue(
1445                     com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
1446             info.minResizeHeight = value != null ? value.data : info.minHeight;
1447             info.updatePeriodMillis = sa.getInt(
1448                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
1449             info.initialLayout = sa.getResourceId(
1450                     com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
1451             info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
1452                     AppWidgetProviderInfo_initialKeyguardLayout, 0);
1453             String className = sa
1454                     .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
1455             if (className != null) {
1456                 info.configure = new ComponentName(component.getPackageName(), className);
1457             }
1458             info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString();
1459             info.icon = ri.getIconResource();
1460             info.previewImage = sa.getResourceId(
1461                     com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
1462             info.autoAdvanceViewId = sa.getResourceId(
1463                     com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
1464             info.resizeMode = sa.getInt(
1465                     com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
1466                     AppWidgetProviderInfo.RESIZE_NONE);
1467             info.widgetCategory = sa.getInt(
1468                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory,
1469                     AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
1470 
1471             sa.recycle();
1472         } catch (Exception e) {
1473             // Ok to catch Exception here, because anything going wrong because
1474             // of what a client process passes to us should not be fatal for the
1475             // system process.
1476             Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
1477             return null;
1478         } finally {
1479             if (parser != null)
1480                 parser.close();
1481         }
1482         return p;
1483     }
1484 
getUidForPackage(String packageName)1485     int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
1486         PackageInfo pkgInfo = null;
1487         try {
1488             pkgInfo = mPm.getPackageInfo(packageName, 0, mUserId);
1489         } catch (RemoteException re) {
1490             // Shouldn't happen, local call
1491         }
1492         if (pkgInfo == null || pkgInfo.applicationInfo == null) {
1493             throw new PackageManager.NameNotFoundException();
1494         }
1495         return pkgInfo.applicationInfo.uid;
1496     }
1497 
enforceSystemOrCallingUid(String packageName)1498     int enforceSystemOrCallingUid(String packageName) throws IllegalArgumentException {
1499         int callingUid = Binder.getCallingUid();
1500         if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID || callingUid == 0) {
1501             return callingUid;
1502         }
1503         return enforceCallingUid(packageName);
1504     }
1505 
enforceCallingUid(String packageName)1506     int enforceCallingUid(String packageName) throws IllegalArgumentException {
1507         int callingUid = Binder.getCallingUid();
1508         int packageUid;
1509         try {
1510             packageUid = getUidForPackage(packageName);
1511         } catch (PackageManager.NameNotFoundException ex) {
1512             throw new IllegalArgumentException("packageName and uid don't match packageName="
1513                     + packageName);
1514         }
1515         if (!UserHandle.isSameApp(callingUid, packageUid)) {
1516             throw new IllegalArgumentException("packageName and uid don't match packageName="
1517                     + packageName);
1518         }
1519         return callingUid;
1520     }
1521 
sendInitialBroadcasts()1522     void sendInitialBroadcasts() {
1523         synchronized (mAppWidgetIds) {
1524             ensureStateLoadedLocked();
1525             final int N = mInstalledProviders.size();
1526             for (int i = 0; i < N; i++) {
1527                 Provider p = mInstalledProviders.get(i);
1528                 if (p.instances.size() > 0) {
1529                     sendEnableIntentLocked(p);
1530                     int[] appWidgetIds = getAppWidgetIds(p);
1531                     sendUpdateIntentLocked(p, appWidgetIds);
1532                     registerForBroadcastsLocked(p, appWidgetIds);
1533                 }
1534             }
1535         }
1536     }
1537 
1538     // only call from initialization -- it assumes that the data structures are all empty
loadStateLocked()1539     void loadStateLocked() {
1540         AtomicFile file = savedStateFile();
1541         try {
1542             FileInputStream stream = file.openRead();
1543             readStateFromFileLocked(stream);
1544 
1545             if (stream != null) {
1546                 try {
1547                     stream.close();
1548                 } catch (IOException e) {
1549                     Slog.w(TAG, "Failed to close state FileInputStream " + e);
1550                 }
1551             }
1552         } catch (FileNotFoundException e) {
1553             Slog.w(TAG, "Failed to read state: " + e);
1554         }
1555     }
1556 
saveStateLocked()1557     void saveStateLocked() {
1558         AtomicFile file = savedStateFile();
1559         FileOutputStream stream;
1560         try {
1561             stream = file.startWrite();
1562             if (writeStateToFileLocked(stream)) {
1563                 file.finishWrite(stream);
1564             } else {
1565                 file.failWrite(stream);
1566                 Slog.w(TAG, "Failed to save state, restoring backup.");
1567             }
1568         } catch (IOException e) {
1569             Slog.w(TAG, "Failed open state file for write: " + e);
1570         }
1571     }
1572 
writeStateToFileLocked(FileOutputStream stream)1573     boolean writeStateToFileLocked(FileOutputStream stream) {
1574         int N;
1575 
1576         try {
1577             XmlSerializer out = new FastXmlSerializer();
1578             out.setOutput(stream, "utf-8");
1579             out.startDocument(null, true);
1580             out.startTag(null, "gs");
1581 
1582             int providerIndex = 0;
1583             N = mInstalledProviders.size();
1584             for (int i = 0; i < N; i++) {
1585                 Provider p = mInstalledProviders.get(i);
1586                 if (p.instances.size() > 0) {
1587                     out.startTag(null, "p");
1588                     out.attribute(null, "pkg", p.info.provider.getPackageName());
1589                     out.attribute(null, "cl", p.info.provider.getClassName());
1590                     out.endTag(null, "p");
1591                     p.tag = providerIndex;
1592                     providerIndex++;
1593                 }
1594             }
1595 
1596             N = mHosts.size();
1597             for (int i = 0; i < N; i++) {
1598                 Host host = mHosts.get(i);
1599                 out.startTag(null, "h");
1600                 out.attribute(null, "pkg", host.packageName);
1601                 out.attribute(null, "id", Integer.toHexString(host.hostId));
1602                 out.endTag(null, "h");
1603                 host.tag = i;
1604             }
1605 
1606             N = mAppWidgetIds.size();
1607             for (int i = 0; i < N; i++) {
1608                 AppWidgetId id = mAppWidgetIds.get(i);
1609                 out.startTag(null, "g");
1610                 out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
1611                 out.attribute(null, "h", Integer.toHexString(id.host.tag));
1612                 if (id.provider != null) {
1613                     out.attribute(null, "p", Integer.toHexString(id.provider.tag));
1614                 }
1615                 if (id.options != null) {
1616                     out.attribute(null, "min_width", Integer.toHexString(id.options.getInt(
1617                             AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)));
1618                     out.attribute(null, "min_height", Integer.toHexString(id.options.getInt(
1619                             AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)));
1620                     out.attribute(null, "max_width", Integer.toHexString(id.options.getInt(
1621                             AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)));
1622                     out.attribute(null, "max_height", Integer.toHexString(id.options.getInt(
1623                             AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)));
1624                     out.attribute(null, "host_category", Integer.toHexString(id.options.getInt(
1625                             AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
1626                 }
1627                 out.endTag(null, "g");
1628             }
1629 
1630             Iterator<String> it = mPackagesWithBindWidgetPermission.iterator();
1631             while (it.hasNext()) {
1632                 out.startTag(null, "b");
1633                 out.attribute(null, "packageName", it.next());
1634                 out.endTag(null, "b");
1635             }
1636 
1637             out.endTag(null, "gs");
1638 
1639             out.endDocument();
1640             return true;
1641         } catch (IOException e) {
1642             Slog.w(TAG, "Failed to write state: " + e);
1643             return false;
1644         }
1645     }
1646 
1647     @SuppressWarnings("unused")
readStateFromFileLocked(FileInputStream stream)1648     void readStateFromFileLocked(FileInputStream stream) {
1649         boolean success = false;
1650         try {
1651             XmlPullParser parser = Xml.newPullParser();
1652             parser.setInput(stream, null);
1653 
1654             int type;
1655             int providerIndex = 0;
1656             HashMap<Integer, Provider> loadedProviders = new HashMap<Integer, Provider>();
1657             do {
1658                 type = parser.next();
1659                 if (type == XmlPullParser.START_TAG) {
1660                     String tag = parser.getName();
1661                     if ("p".equals(tag)) {
1662                         // TODO: do we need to check that this package has the same signature
1663                         // as before?
1664                         String pkg = parser.getAttributeValue(null, "pkg");
1665                         String cl = parser.getAttributeValue(null, "cl");
1666 
1667                         final IPackageManager packageManager = AppGlobals.getPackageManager();
1668                         try {
1669                             packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId);
1670                         } catch (RemoteException e) {
1671                             String[] pkgs = mContext.getPackageManager()
1672                                     .currentToCanonicalPackageNames(new String[] { pkg });
1673                             pkg = pkgs[0];
1674                         }
1675 
1676                         Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
1677                         if (p == null && mSafeMode) {
1678                             // if we're in safe mode, make a temporary one
1679                             p = new Provider();
1680                             p.info = new AppWidgetProviderInfo();
1681                             p.info.provider = new ComponentName(pkg, cl);
1682                             p.zombie = true;
1683                             mInstalledProviders.add(p);
1684                         }
1685                         if (p != null) {
1686                             // if it wasn't uninstalled or something
1687                             loadedProviders.put(providerIndex, p);
1688                         }
1689                         providerIndex++;
1690                     } else if ("h".equals(tag)) {
1691                         Host host = new Host();
1692 
1693                         // TODO: do we need to check that this package has the same signature
1694                         // as before?
1695                         host.packageName = parser.getAttributeValue(null, "pkg");
1696                         try {
1697                             host.uid = getUidForPackage(host.packageName);
1698                         } catch (PackageManager.NameNotFoundException ex) {
1699                             host.zombie = true;
1700                         }
1701                         if (!host.zombie || mSafeMode) {
1702                             // In safe mode, we don't discard the hosts we don't recognize
1703                             // so that they're not pruned from our list. Otherwise, we do.
1704                             host.hostId = Integer
1705                                     .parseInt(parser.getAttributeValue(null, "id"), 16);
1706                             mHosts.add(host);
1707                         }
1708                     } else if ("b".equals(tag)) {
1709                         String packageName = parser.getAttributeValue(null, "packageName");
1710                         if (packageName != null) {
1711                             mPackagesWithBindWidgetPermission.add(packageName);
1712                         }
1713                     } else if ("g".equals(tag)) {
1714                         AppWidgetId id = new AppWidgetId();
1715                         id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
1716                         if (id.appWidgetId >= mNextAppWidgetId) {
1717                             mNextAppWidgetId = id.appWidgetId + 1;
1718                         }
1719 
1720                         Bundle options = new Bundle();
1721                         String minWidthString = parser.getAttributeValue(null, "min_width");
1722                         if (minWidthString != null) {
1723                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
1724                                     Integer.parseInt(minWidthString, 16));
1725                         }
1726                         String minHeightString = parser.getAttributeValue(null, "min_height");
1727                         if (minHeightString != null) {
1728                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
1729                                     Integer.parseInt(minHeightString, 16));
1730                         }
1731                         String maxWidthString = parser.getAttributeValue(null, "max_width");
1732                         if (maxWidthString != null) {
1733                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
1734                                     Integer.parseInt(maxWidthString, 16));
1735                         }
1736                         String maxHeightString = parser.getAttributeValue(null, "max_height");
1737                         if (maxHeightString != null) {
1738                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
1739                                     Integer.parseInt(maxHeightString, 16));
1740                         }
1741                         String categoryString = parser.getAttributeValue(null, "host_category");
1742                         if (categoryString != null) {
1743                             options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
1744                                     Integer.parseInt(categoryString, 16));
1745                         }
1746                         id.options = options;
1747 
1748                         String providerString = parser.getAttributeValue(null, "p");
1749                         if (providerString != null) {
1750                             // there's no provider if it hasn't been bound yet.
1751                             // maybe we don't have to save this, but it brings the system
1752                             // to the state it was in.
1753                             int pIndex = Integer.parseInt(providerString, 16);
1754                             id.provider = loadedProviders.get(pIndex);
1755                             if (false) {
1756                                 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
1757                                         + pIndex + " which is " + id.provider);
1758                             }
1759                             if (id.provider == null) {
1760                                 // This provider is gone. We just let the host figure out
1761                                 // that this happened when it fails to load it.
1762                                 continue;
1763                             }
1764                         }
1765 
1766                         int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
1767                         id.host = mHosts.get(hIndex);
1768                         if (id.host == null) {
1769                             // This host is gone.
1770                             continue;
1771                         }
1772 
1773                         if (id.provider != null) {
1774                             id.provider.instances.add(id);
1775                         }
1776                         id.host.instances.add(id);
1777                         mAppWidgetIds.add(id);
1778                     }
1779                 }
1780             } while (type != XmlPullParser.END_DOCUMENT);
1781             success = true;
1782         } catch (NullPointerException e) {
1783             Slog.w(TAG, "failed parsing " + e);
1784         } catch (NumberFormatException e) {
1785             Slog.w(TAG, "failed parsing " + e);
1786         } catch (XmlPullParserException e) {
1787             Slog.w(TAG, "failed parsing " + e);
1788         } catch (IOException e) {
1789             Slog.w(TAG, "failed parsing " + e);
1790         } catch (IndexOutOfBoundsException e) {
1791             Slog.w(TAG, "failed parsing " + e);
1792         }
1793 
1794         if (success) {
1795             // delete any hosts that didn't manage to get connected (should happen)
1796             // if it matters, they'll be reconnected.
1797             for (int i = mHosts.size() - 1; i >= 0; i--) {
1798                 pruneHostLocked(mHosts.get(i));
1799             }
1800         } else {
1801             // failed reading, clean up
1802             Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
1803 
1804             mAppWidgetIds.clear();
1805             mHosts.clear();
1806             final int N = mInstalledProviders.size();
1807             for (int i = 0; i < N; i++) {
1808                 mInstalledProviders.get(i).instances.clear();
1809             }
1810         }
1811     }
1812 
getSettingsFile(int userId)1813     static File getSettingsFile(int userId) {
1814         return new File(Environment.getUserSystemDirectory(userId), SETTINGS_FILENAME);
1815     }
1816 
savedStateFile()1817     AtomicFile savedStateFile() {
1818         File dir = Environment.getUserSystemDirectory(mUserId);
1819         File settingsFile = getSettingsFile(mUserId);
1820         if (!settingsFile.exists() && mUserId == 0) {
1821             if (!dir.exists()) {
1822                 dir.mkdirs();
1823             }
1824             // Migrate old data
1825             File oldFile = new File("/data/system/" + SETTINGS_FILENAME);
1826             // Method doesn't throw an exception on failure. Ignore any errors
1827             // in moving the file (like non-existence)
1828             oldFile.renameTo(settingsFile);
1829         }
1830         return new AtomicFile(settingsFile);
1831     }
1832 
onUserStopping()1833     void onUserStopping() {
1834         // prune the ones we don't want to keep
1835         int N = mInstalledProviders.size();
1836         for (int i = N - 1; i >= 0; i--) {
1837             Provider p = mInstalledProviders.get(i);
1838             cancelBroadcasts(p);
1839         }
1840     }
1841 
onUserRemoved()1842     void onUserRemoved() {
1843         getSettingsFile(mUserId).delete();
1844     }
1845 
addProvidersForPackageLocked(String pkgName)1846     boolean addProvidersForPackageLocked(String pkgName) {
1847         boolean providersAdded = false;
1848         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1849         intent.setPackage(pkgName);
1850         List<ResolveInfo> broadcastReceivers;
1851         try {
1852             broadcastReceivers = mPm.queryIntentReceivers(intent,
1853                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
1854                     PackageManager.GET_META_DATA, mUserId);
1855         } catch (RemoteException re) {
1856             // Shouldn't happen, local call
1857             return false;
1858         }
1859         final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
1860         for (int i = 0; i < N; i++) {
1861             ResolveInfo ri = broadcastReceivers.get(i);
1862             ActivityInfo ai = ri.activityInfo;
1863             if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1864                 continue;
1865             }
1866             if (pkgName.equals(ai.packageName)) {
1867                 addProviderLocked(ri);
1868                 providersAdded = true;
1869             }
1870         }
1871 
1872         return providersAdded;
1873     }
1874 
1875     /**
1876      * Updates all providers with the specified package names, and records any providers that were
1877      * pruned.
1878      *
1879      * @return whether any providers were updated
1880      */
updateProvidersForPackageLocked(String pkgName, Set<ComponentName> removedProviders)1881     boolean updateProvidersForPackageLocked(String pkgName, Set<ComponentName> removedProviders) {
1882         boolean providersUpdated = false;
1883         HashSet<String> keep = new HashSet<String>();
1884         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1885         intent.setPackage(pkgName);
1886         List<ResolveInfo> broadcastReceivers;
1887         try {
1888             broadcastReceivers = mPm.queryIntentReceivers(intent,
1889                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
1890                 PackageManager.GET_META_DATA, mUserId);
1891         } catch (RemoteException re) {
1892             // Shouldn't happen, local call
1893             return false;
1894         }
1895 
1896         // add the missing ones and collect which ones to keep
1897         int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
1898         for (int i = 0; i < N; i++) {
1899             ResolveInfo ri = broadcastReceivers.get(i);
1900             ActivityInfo ai = ri.activityInfo;
1901             if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1902                 continue;
1903             }
1904             if (pkgName.equals(ai.packageName)) {
1905                 ComponentName component = new ComponentName(ai.packageName, ai.name);
1906                 Provider p = lookupProviderLocked(component);
1907                 if (p == null) {
1908                     if (addProviderLocked(ri)) {
1909                         keep.add(ai.name);
1910                         providersUpdated = true;
1911                     }
1912                 } else {
1913                     Provider parsed = parseProviderInfoXml(component, ri);
1914                     if (parsed != null) {
1915                         keep.add(ai.name);
1916                         // Use the new AppWidgetProviderInfo.
1917                         p.info = parsed.info;
1918                         // If it's enabled
1919                         final int M = p.instances.size();
1920                         if (M > 0) {
1921                             int[] appWidgetIds = getAppWidgetIds(p);
1922                             // Reschedule for the new updatePeriodMillis (don't worry about handling
1923                             // it specially if updatePeriodMillis didn't change because we just sent
1924                             // an update, and the next one will be updatePeriodMillis from now).
1925                             cancelBroadcasts(p);
1926                             registerForBroadcastsLocked(p, appWidgetIds);
1927                             // If it's currently showing, call back with the new
1928                             // AppWidgetProviderInfo.
1929                             for (int j = 0; j < M; j++) {
1930                                 AppWidgetId id = p.instances.get(j);
1931                                 id.views = null;
1932                                 if (id.host != null && id.host.callbacks != null) {
1933                                     try {
1934                                         id.host.callbacks.providerChanged(id.appWidgetId, p.info);
1935                                     } catch (RemoteException ex) {
1936                                         // It failed; remove the callback. No need to prune because
1937                                         // we know that this host is still referenced by this
1938                                         // instance.
1939                                         id.host.callbacks = null;
1940                                     }
1941                                 }
1942                             }
1943                             // Now that we've told the host, push out an update.
1944                             sendUpdateIntentLocked(p, appWidgetIds);
1945                             providersUpdated = true;
1946                         }
1947                     }
1948                 }
1949             }
1950         }
1951 
1952         // prune the ones we don't want to keep
1953         N = mInstalledProviders.size();
1954         for (int i = N - 1; i >= 0; i--) {
1955             Provider p = mInstalledProviders.get(i);
1956             if (pkgName.equals(p.info.provider.getPackageName())
1957                     && !keep.contains(p.info.provider.getClassName())) {
1958                 if (removedProviders != null) {
1959                     removedProviders.add(p.info.provider);
1960                 }
1961                 removeProviderLocked(i, p);
1962                 providersUpdated = true;
1963             }
1964         }
1965 
1966         return providersUpdated;
1967     }
1968 
removeProvidersForPackageLocked(String pkgName)1969     boolean removeProvidersForPackageLocked(String pkgName) {
1970         boolean providersRemoved = false;
1971         int N = mInstalledProviders.size();
1972         for (int i = N - 1; i >= 0; i--) {
1973             Provider p = mInstalledProviders.get(i);
1974             if (pkgName.equals(p.info.provider.getPackageName())) {
1975                 removeProviderLocked(i, p);
1976                 providersRemoved = true;
1977             }
1978         }
1979 
1980         // Delete the hosts for this package too
1981         //
1982         // By now, we have removed any AppWidgets that were in any hosts here,
1983         // so we don't need to worry about sending DISABLE broadcasts to them.
1984         N = mHosts.size();
1985         for (int i = N - 1; i >= 0; i--) {
1986             Host host = mHosts.get(i);
1987             if (pkgName.equals(host.packageName)) {
1988                 deleteHostLocked(host);
1989             }
1990         }
1991 
1992         return providersRemoved;
1993     }
1994 
notifyHostsForProvidersChangedLocked()1995     void notifyHostsForProvidersChangedLocked() {
1996         final int N = mHosts.size();
1997         for (int i = N - 1; i >= 0; i--) {
1998             Host host = mHosts.get(i);
1999             try {
2000                 if (host.callbacks != null) {
2001                     host.callbacks.providersChanged();
2002                 }
2003             } catch (RemoteException ex) {
2004                 // It failed; remove the callback. No need to prune because
2005                 // we know that this host is still referenced by this
2006                 // instance.
2007                 host.callbacks = null;
2008             }
2009         }
2010     }
2011 }
2012