Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.AppGlobals;
     21 import android.app.PendingIntent;
     22 import android.appwidget.AppWidgetManager;
     23 import android.appwidget.AppWidgetProviderInfo;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.Intent.FilterComparison;
     28 import android.content.ServiceConnection;
     29 import android.content.pm.ActivityInfo;
     30 import android.content.pm.ApplicationInfo;
     31 import android.content.pm.IPackageManager;
     32 import android.content.pm.PackageInfo;
     33 import android.content.pm.PackageManager;
     34 import android.content.pm.ResolveInfo;
     35 import android.content.pm.ServiceInfo;
     36 import android.content.res.Resources;
     37 import android.content.res.TypedArray;
     38 import android.content.res.XmlResourceParser;
     39 import android.graphics.Point;
     40 import android.net.Uri;
     41 import android.os.Binder;
     42 import android.os.Bundle;
     43 import android.os.Environment;
     44 import android.os.Handler;
     45 import android.os.HandlerThread;
     46 import android.os.IBinder;
     47 import android.os.Looper;
     48 import android.os.Process;
     49 import android.os.RemoteException;
     50 import android.os.SystemClock;
     51 import android.os.UserHandle;
     52 import android.util.AtomicFile;
     53 import android.util.AttributeSet;
     54 import android.util.Log;
     55 import android.util.Pair;
     56 import android.util.Slog;
     57 import android.util.TypedValue;
     58 import android.util.Xml;
     59 import android.view.Display;
     60 import android.view.WindowManager;
     61 import android.widget.RemoteViews;
     62 
     63 import com.android.internal.appwidget.IAppWidgetHost;
     64 import com.android.internal.util.FastXmlSerializer;
     65 import com.android.internal.widget.IRemoteViewsAdapterConnection;
     66 import com.android.internal.widget.IRemoteViewsFactory;
     67 
     68 import org.xmlpull.v1.XmlPullParser;
     69 import org.xmlpull.v1.XmlPullParserException;
     70 import org.xmlpull.v1.XmlSerializer;
     71 
     72 import java.io.File;
     73 import java.io.FileDescriptor;
     74 import java.io.FileInputStream;
     75 import java.io.FileNotFoundException;
     76 import java.io.FileOutputStream;
     77 import java.io.IOException;
     78 import java.io.PrintWriter;
     79 import java.util.ArrayList;
     80 import java.util.HashMap;
     81 import java.util.HashSet;
     82 import java.util.Iterator;
     83 import java.util.List;
     84 import java.util.Locale;
     85 import java.util.Set;
     86 
     87 class AppWidgetServiceImpl {
     88 
     89     private static final String 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