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