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