Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2007 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.PendingIntent;
     21 import android.appwidget.AppWidgetManager;
     22 import android.appwidget.AppWidgetProviderInfo;
     23 import android.content.BroadcastReceiver;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.pm.ActivityInfo;
     29 import android.content.pm.PackageManager;
     30 import android.content.pm.PackageInfo;
     31 import android.content.pm.ResolveInfo;
     32 import android.content.res.Resources;
     33 import android.content.res.TypedArray;
     34 import android.content.res.XmlResourceParser;
     35 import android.net.Uri;
     36 import android.os.Binder;
     37 import android.os.Bundle;
     38 import android.os.Process;
     39 import android.os.RemoteException;
     40 import android.os.SystemClock;
     41 import android.util.AttributeSet;
     42 import android.util.Slog;
     43 import android.util.TypedValue;
     44 import android.util.Xml;
     45 import android.widget.RemoteViews;
     46 
     47 import java.io.IOException;
     48 import java.io.File;
     49 import java.io.FileDescriptor;
     50 import java.io.FileInputStream;
     51 import java.io.FileOutputStream;
     52 import java.io.PrintWriter;
     53 import java.util.ArrayList;
     54 import java.util.List;
     55 import java.util.Locale;
     56 import java.util.HashMap;
     57 import java.util.HashSet;
     58 
     59 import com.android.internal.appwidget.IAppWidgetService;
     60 import com.android.internal.appwidget.IAppWidgetHost;
     61 import com.android.internal.util.FastXmlSerializer;
     62 
     63 import org.xmlpull.v1.XmlPullParser;
     64 import org.xmlpull.v1.XmlPullParserException;
     65 import org.xmlpull.v1.XmlSerializer;
     66 
     67 class AppWidgetService extends IAppWidgetService.Stub
     68 {
     69     private static final String TAG = "AppWidgetService";
     70 
     71     private static final String SETTINGS_FILENAME = "appwidgets.xml";
     72     private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
     73     private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
     74 
     75     /*
     76      * When identifying a Host or Provider based on the calling process, use the uid field.
     77      * When identifying a Host or Provider based on a package manager broadcast, use the
     78      * package given.
     79      */
     80 
     81     static class Provider {
     82         int uid;
     83         AppWidgetProviderInfo info;
     84         ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
     85         PendingIntent broadcast;
     86         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
     87 
     88         int tag;    // for use while saving state (the index)
     89     }
     90 
     91     static class Host {
     92         int uid;
     93         int hostId;
     94         String packageName;
     95         ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
     96         IAppWidgetHost callbacks;
     97         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
     98 
     99         int tag;    // for use while saving state (the index)
    100     }
    101 
    102     static class AppWidgetId {
    103         int appWidgetId;
    104         Provider provider;
    105         RemoteViews views;
    106         Host host;
    107     }
    108 
    109     Context mContext;
    110     Locale mLocale;
    111     PackageManager mPackageManager;
    112     AlarmManager mAlarmManager;
    113     ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
    114     int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
    115     final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
    116     ArrayList<Host> mHosts = new ArrayList<Host>();
    117     boolean mSafeMode;
    118 
    119     AppWidgetService(Context context) {
    120         mContext = context;
    121         mPackageManager = context.getPackageManager();
    122         mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
    123     }
    124 
    125     public void systemReady(boolean safeMode) {
    126         mSafeMode = safeMode;
    127 
    128         loadAppWidgetList();
    129         loadStateLocked();
    130 
    131         // Register for the boot completed broadcast, so we can send the
    132         // ENABLE broacasts.  If we try to send them now, they time out,
    133         // because the system isn't ready to handle them yet.
    134         mContext.registerReceiver(mBroadcastReceiver,
    135                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
    136 
    137         // Register for configuration changes so we can update the names
    138         // of the widgets when the locale changes.
    139         mContext.registerReceiver(mBroadcastReceiver,
    140                 new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
    141 
    142         // Register for broadcasts about package install, etc., so we can
    143         // update the provider list.
    144         IntentFilter filter = new IntentFilter();
    145         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
    146         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    147         filter.addDataScheme("package");
    148         mContext.registerReceiver(mBroadcastReceiver, filter);
    149         // Register for events related to sdcard installation.
    150         IntentFilter sdFilter = new IntentFilter();
    151         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
    152         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
    153         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
    154     }
    155 
    156     @Override
    157     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    158         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
    159                 != PackageManager.PERMISSION_GRANTED) {
    160             pw.println("Permission Denial: can't dump from from pid="
    161                     + Binder.getCallingPid()
    162                     + ", uid=" + Binder.getCallingUid());
    163             return;
    164         }
    165 
    166         synchronized (mAppWidgetIds) {
    167             int N = mInstalledProviders.size();
    168             pw.println("Providers:");
    169             for (int i=0; i<N; i++) {
    170                 Provider p = mInstalledProviders.get(i);
    171                 AppWidgetProviderInfo info = p.info;
    172                 pw.print("  ["); pw.print(i); pw.print("] provider ");
    173                         pw.print(info.provider.flattenToShortString());
    174                         pw.println(':');
    175                 pw.print("    min=("); pw.print(info.minWidth);
    176                         pw.print("x"); pw.print(info.minHeight);
    177                         pw.print(") updatePeriodMillis=");
    178                         pw.print(info.updatePeriodMillis);
    179                         pw.print(" initialLayout=#");
    180                         pw.print(Integer.toHexString(info.initialLayout));
    181                         pw.print(" zombie="); pw.println(p.zombie);
    182             }
    183 
    184             N = mAppWidgetIds.size();
    185             pw.println(" ");
    186             pw.println("AppWidgetIds:");
    187             for (int i=0; i<N; i++) {
    188                 AppWidgetId id = mAppWidgetIds.get(i);
    189                 pw.print("  ["); pw.print(i); pw.print("] id=");
    190                         pw.println(id.appWidgetId);
    191                 pw.print("    hostId=");
    192                         pw.print(id.host.hostId); pw.print(' ');
    193                         pw.print(id.host.packageName); pw.print('/');
    194                         pw.println(id.host.uid);
    195                 if (id.provider != null) {
    196                     pw.print("    provider=");
    197                             pw.println(id.provider.info.provider.flattenToShortString());
    198                 }
    199                 if (id.host != null) {
    200                     pw.print("    host.callbacks="); pw.println(id.host.callbacks);
    201                 }
    202                 if (id.views != null) {
    203                     pw.print("    views="); pw.println(id.views);
    204                 }
    205             }
    206 
    207             N = mHosts.size();
    208             pw.println(" ");
    209             pw.println("Hosts:");
    210             for (int i=0; i<N; i++) {
    211                 Host host = mHosts.get(i);
    212                 pw.print("  ["); pw.print(i); pw.print("] hostId=");
    213                         pw.print(host.hostId); pw.print(' ');
    214                         pw.print(host.packageName); pw.print('/');
    215                         pw.print(host.uid); pw.println(':');
    216                 pw.print("    callbacks="); pw.println(host.callbacks);
    217                 pw.print("    instances.size="); pw.print(host.instances.size());
    218                         pw.print(" zombie="); pw.println(host.zombie);
    219             }
    220         }
    221     }
    222 
    223     public int allocateAppWidgetId(String packageName, int hostId) {
    224         int callingUid = enforceCallingUid(packageName);
    225         synchronized (mAppWidgetIds) {
    226             int appWidgetId = mNextAppWidgetId++;
    227 
    228             Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
    229 
    230             AppWidgetId id = new AppWidgetId();
    231             id.appWidgetId = appWidgetId;
    232             id.host = host;
    233 
    234             host.instances.add(id);
    235             mAppWidgetIds.add(id);
    236 
    237             saveStateLocked();
    238 
    239             return appWidgetId;
    240         }
    241     }
    242 
    243     public void deleteAppWidgetId(int appWidgetId) {
    244         synchronized (mAppWidgetIds) {
    245             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
    246             if (id != null) {
    247                 deleteAppWidgetLocked(id);
    248                 saveStateLocked();
    249             }
    250         }
    251     }
    252 
    253     public void deleteHost(int hostId) {
    254         synchronized (mAppWidgetIds) {
    255             int callingUid = getCallingUid();
    256             Host host = lookupHostLocked(callingUid, hostId);
    257             if (host != null) {
    258                 deleteHostLocked(host);
    259                 saveStateLocked();
    260             }
    261         }
    262     }
    263 
    264     public void deleteAllHosts() {
    265         synchronized (mAppWidgetIds) {
    266             int callingUid = getCallingUid();
    267             final int N = mHosts.size();
    268             boolean changed = false;
    269             for (int i=N-1; i>=0; i--) {
    270                 Host host = mHosts.get(i);
    271                 if (host.uid == callingUid) {
    272                     deleteHostLocked(host);
    273                     changed = true;
    274                 }
    275             }
    276             if (changed) {
    277                 saveStateLocked();
    278             }
    279         }
    280     }
    281 
    282     void deleteHostLocked(Host host) {
    283         final int N = host.instances.size();
    284         for (int i=N-1; i>=0; i--) {
    285             AppWidgetId id = host.instances.get(i);
    286             deleteAppWidgetLocked(id);
    287         }
    288         host.instances.clear();
    289         mHosts.remove(host);
    290         // it's gone or going away, abruptly drop the callback connection
    291         host.callbacks = null;
    292     }
    293 
    294     void deleteAppWidgetLocked(AppWidgetId id) {
    295         Host host = id.host;
    296         host.instances.remove(id);
    297         pruneHostLocked(host);
    298 
    299         mAppWidgetIds.remove(id);
    300 
    301         Provider p = id.provider;
    302         if (p != null) {
    303             p.instances.remove(id);
    304             if (!p.zombie) {
    305                 // send the broacast saying that this appWidgetId has been deleted
    306                 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
    307                 intent.setComponent(p.info.provider);
    308                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
    309                 mContext.sendBroadcast(intent);
    310                 if (p.instances.size() == 0) {
    311                     // cancel the future updates
    312                     cancelBroadcasts(p);
    313 
    314                     // send the broacast saying that the provider is not in use any more
    315                     intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
    316                     intent.setComponent(p.info.provider);
    317                     mContext.sendBroadcast(intent);
    318                 }
    319             }
    320         }
    321     }
    322 
    323     void cancelBroadcasts(Provider p) {
    324         if (p.broadcast != null) {
    325             mAlarmManager.cancel(p.broadcast);
    326             long token = Binder.clearCallingIdentity();
    327             try {
    328                 p.broadcast.cancel();
    329             } finally {
    330                 Binder.restoreCallingIdentity(token);
    331             }
    332             p.broadcast = null;
    333         }
    334     }
    335 
    336     public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
    337         mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
    338                 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
    339         synchronized (mAppWidgetIds) {
    340             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
    341             if (id == null) {
    342                 throw new IllegalArgumentException("bad appWidgetId");
    343             }
    344             if (id.provider != null) {
    345                 throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
    346                         + id.provider.info.provider);
    347             }
    348             Provider p = lookupProviderLocked(provider);
    349             if (p == null) {
    350                 throw new IllegalArgumentException("not a appwidget provider: " + provider);
    351             }
    352             if (p.zombie) {
    353                 throw new IllegalArgumentException("can't bind to a 3rd party provider in"
    354                         + " safe mode: " + provider);
    355             }
    356 
    357             id.provider = p;
    358             p.instances.add(id);
    359             int instancesSize = p.instances.size();
    360             if (instancesSize == 1) {
    361                 // tell the provider that it's ready
    362                 sendEnableIntentLocked(p);
    363             }
    364 
    365             // send an update now -- We need this update now, and just for this appWidgetId.
    366             // It's less critical when the next one happens, so when we schdule the next one,
    367             // we add updatePeriodMillis to its start time.  That time will have some slop,
    368             // but that's okay.
    369             sendUpdateIntentLocked(p, new int[] { appWidgetId });
    370 
    371             // schedule the future updates
    372             registerForBroadcastsLocked(p, getAppWidgetIds(p));
    373             saveStateLocked();
    374         }
    375     }
    376 
    377     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
    378         synchronized (mAppWidgetIds) {
    379             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
    380             if (id != null && id.provider != null && !id.provider.zombie) {
    381                 return id.provider.info;
    382             }
    383             return null;
    384         }
    385     }
    386 
    387     public RemoteViews getAppWidgetViews(int appWidgetId) {
    388         synchronized (mAppWidgetIds) {
    389             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
    390             if (id != null) {
    391                 return id.views;
    392             }
    393             return null;
    394         }
    395     }
    396 
    397     public List<AppWidgetProviderInfo> getInstalledProviders() {
    398         synchronized (mAppWidgetIds) {
    399             final int N = mInstalledProviders.size();
    400             ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
    401             for (int i=0; i<N; i++) {
    402                 Provider p = mInstalledProviders.get(i);
    403                 if (!p.zombie) {
    404                     result.add(p.info);
    405                 }
    406             }
    407             return result;
    408         }
    409     }
    410 
    411     public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
    412         if (appWidgetIds == null) {
    413             return;
    414         }
    415         if (appWidgetIds.length == 0) {
    416             return;
    417         }
    418         final int N = appWidgetIds.length;
    419 
    420         synchronized (mAppWidgetIds) {
    421             for (int i=0; i<N; i++) {
    422                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
    423                 updateAppWidgetInstanceLocked(id, views);
    424             }
    425         }
    426     }
    427 
    428     public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
    429         synchronized (mAppWidgetIds) {
    430             Provider p = lookupProviderLocked(provider);
    431             if (p == null) {
    432                 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
    433                 return;
    434             }
    435             ArrayList<AppWidgetId> instances = p.instances;
    436             final int N = instances.size();
    437             for (int i=0; i<N; i++) {
    438                 AppWidgetId id = instances.get(i);
    439                 updateAppWidgetInstanceLocked(id, views);
    440             }
    441         }
    442     }
    443 
    444     void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
    445         // allow for stale appWidgetIds and other badness
    446         // lookup also checks that the calling process can access the appWidgetId
    447         // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
    448         if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
    449             id.views = views;
    450 
    451             // is anyone listening?
    452             if (id.host.callbacks != null) {
    453                 try {
    454                     // the lock is held, but this is a oneway call
    455                     id.host.callbacks.updateAppWidget(id.appWidgetId, views);
    456                 } catch (RemoteException e) {
    457                     // It failed; remove the callback. No need to prune because
    458                     // we know that this host is still referenced by this instance.
    459                     id.host.callbacks = null;
    460                 }
    461             }
    462         }
    463     }
    464 
    465     public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
    466             List<RemoteViews> updatedViews) {
    467         int callingUid = enforceCallingUid(packageName);
    468         synchronized (mAppWidgetIds) {
    469             Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
    470             host.callbacks = callbacks;
    471 
    472             updatedViews.clear();
    473 
    474             ArrayList<AppWidgetId> instances = host.instances;
    475             int N = instances.size();
    476             int[] updatedIds = new int[N];
    477             for (int i=0; i<N; i++) {
    478                 AppWidgetId id = instances.get(i);
    479                 updatedIds[i] = id.appWidgetId;
    480                 updatedViews.add(id.views);
    481             }
    482             return updatedIds;
    483         }
    484     }
    485 
    486     public void stopListening(int hostId) {
    487         synchronized (mAppWidgetIds) {
    488             Host host = lookupHostLocked(getCallingUid(), hostId);
    489             if (host != null) {
    490                 host.callbacks = null;
    491                 pruneHostLocked(host);
    492             }
    493         }
    494     }
    495 
    496     boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
    497         if (id.host.uid == callingUid) {
    498             // Apps hosting the AppWidget have access to it.
    499             return true;
    500         }
    501         if (id.provider != null && id.provider.uid == callingUid) {
    502             // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
    503             return true;
    504         }
    505         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET)
    506                 == PackageManager.PERMISSION_GRANTED) {
    507             // Apps that can bind have access to all appWidgetIds.
    508             return true;
    509         }
    510         // Nobody else can access it.
    511         return false;
    512     }
    513 
    514    AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
    515         int callingUid = getCallingUid();
    516         final int N = mAppWidgetIds.size();
    517         for (int i=0; i<N; i++) {
    518             AppWidgetId id = mAppWidgetIds.get(i);
    519             if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
    520                 return id;
    521             }
    522         }
    523         return null;
    524     }
    525 
    526     Provider lookupProviderLocked(ComponentName provider) {
    527         final String className = provider.getClassName();
    528         final int N = mInstalledProviders.size();
    529         for (int i=0; i<N; i++) {
    530             Provider p = mInstalledProviders.get(i);
    531             if (p.info.provider.equals(provider) || className.equals(p.info.oldName)) {
    532                 return p;
    533             }
    534         }
    535         return null;
    536     }
    537 
    538     Host lookupHostLocked(int uid, int hostId) {
    539         final int N = mHosts.size();
    540         for (int i=0; i<N; i++) {
    541             Host h = mHosts.get(i);
    542             if (h.uid == uid && h.hostId == hostId) {
    543                 return h;
    544             }
    545         }
    546         return null;
    547     }
    548 
    549     Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
    550         final int N = mHosts.size();
    551         for (int i=0; i<N; i++) {
    552             Host h = mHosts.get(i);
    553             if (h.hostId == hostId && h.packageName.equals(packageName)) {
    554                 return h;
    555             }
    556         }
    557         Host host = new Host();
    558         host.packageName = packageName;
    559         host.uid = uid;
    560         host.hostId = hostId;
    561         mHosts.add(host);
    562         return host;
    563     }
    564 
    565     void pruneHostLocked(Host host) {
    566         if (host.instances.size() == 0 && host.callbacks == null) {
    567             mHosts.remove(host);
    568         }
    569     }
    570 
    571     void loadAppWidgetList() {
    572         PackageManager pm = mPackageManager;
    573 
    574         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    575         List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
    576                 PackageManager.GET_META_DATA);
    577 
    578         final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
    579         for (int i=0; i<N; i++) {
    580             ResolveInfo ri = broadcastReceivers.get(i);
    581             addProviderLocked(ri);
    582         }
    583     }
    584 
    585     boolean addProviderLocked(ResolveInfo ri) {
    586         Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
    587                     ri.activityInfo.name), ri);
    588         if (p != null) {
    589             mInstalledProviders.add(p);
    590             return true;
    591         } else {
    592             return false;
    593         }
    594     }
    595 
    596     void removeProviderLocked(int index, Provider p) {
    597         int N = p.instances.size();
    598         for (int i=0; i<N; i++) {
    599             AppWidgetId id = p.instances.get(i);
    600             // Call back with empty RemoteViews
    601             updateAppWidgetInstanceLocked(id, null);
    602             // Stop telling the host about updates for this from now on
    603             cancelBroadcasts(p);
    604             // clear out references to this appWidgetId
    605             id.host.instances.remove(id);
    606             mAppWidgetIds.remove(id);
    607             id.provider = null;
    608             pruneHostLocked(id.host);
    609             id.host = null;
    610         }
    611         p.instances.clear();
    612         mInstalledProviders.remove(index);
    613         // no need to send the DISABLE broadcast, since the receiver is gone anyway
    614         cancelBroadcasts(p);
    615     }
    616 
    617     void sendEnableIntentLocked(Provider p) {
    618         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
    619         intent.setComponent(p.info.provider);
    620         mContext.sendBroadcast(intent);
    621     }
    622 
    623     void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
    624         if (appWidgetIds != null && appWidgetIds.length > 0) {
    625             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    626             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    627             intent.setComponent(p.info.provider);
    628             mContext.sendBroadcast(intent);
    629         }
    630     }
    631 
    632     void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
    633         if (p.info.updatePeriodMillis > 0) {
    634             // if this is the first instance, set the alarm.  otherwise,
    635             // rely on the fact that we've already set it and that
    636             // PendingIntent.getBroadcast will update the extras.
    637             boolean alreadyRegistered = p.broadcast != null;
    638             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    639             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    640             intent.setComponent(p.info.provider);
    641             long token = Binder.clearCallingIdentity();
    642             try {
    643                 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
    644                         PendingIntent.FLAG_UPDATE_CURRENT);
    645             } finally {
    646                 Binder.restoreCallingIdentity(token);
    647             }
    648             if (!alreadyRegistered) {
    649                 long period = p.info.updatePeriodMillis;
    650                 if (period < MIN_UPDATE_PERIOD) {
    651                     period = MIN_UPDATE_PERIOD;
    652                 }
    653                 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    654                         SystemClock.elapsedRealtime() + period, period, p.broadcast);
    655             }
    656         }
    657     }
    658 
    659     static int[] getAppWidgetIds(Provider p) {
    660         int instancesSize = p.instances.size();
    661         int appWidgetIds[] = new int[instancesSize];
    662         for (int i=0; i<instancesSize; i++) {
    663             appWidgetIds[i] = p.instances.get(i).appWidgetId;
    664         }
    665         return appWidgetIds;
    666     }
    667 
    668     public int[] getAppWidgetIds(ComponentName provider) {
    669         synchronized (mAppWidgetIds) {
    670             Provider p = lookupProviderLocked(provider);
    671             if (p != null && getCallingUid() == p.uid) {
    672                 return getAppWidgetIds(p);
    673             } else {
    674                 return new int[0];
    675             }
    676         }
    677     }
    678 
    679     private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
    680         Provider p = null;
    681 
    682         ActivityInfo activityInfo = ri.activityInfo;
    683         XmlResourceParser parser = null;
    684         try {
    685             parser = activityInfo.loadXmlMetaData(mPackageManager,
    686                     AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
    687             if (parser == null) {
    688                 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
    689                         + "AppWidget provider '" + component + '\'');
    690                 return null;
    691             }
    692 
    693             AttributeSet attrs = Xml.asAttributeSet(parser);
    694 
    695             int type;
    696             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    697                     && type != XmlPullParser.START_TAG) {
    698                 // drain whitespace, comments, etc.
    699             }
    700 
    701             String nodeName = parser.getName();
    702             if (!"appwidget-provider".equals(nodeName)) {
    703                 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
    704                         + " AppWidget provider '" + component + '\'');
    705                 return null;
    706             }
    707 
    708             p = new Provider();
    709             AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
    710             // If metaData was null, we would have returned earlier when getting
    711             // the parser No need to do the check here
    712             info.oldName = activityInfo.metaData.getString(
    713                     AppWidgetManager.META_DATA_APPWIDGET_OLD_NAME);
    714 
    715             info.provider = component;
    716             p.uid = activityInfo.applicationInfo.uid;
    717 
    718             Resources res = mPackageManager.getResourcesForApplication(
    719                     activityInfo.applicationInfo);
    720 
    721             TypedArray sa = res.obtainAttributes(attrs,
    722                     com.android.internal.R.styleable.AppWidgetProviderInfo);
    723 
    724             // These dimensions has to be resolved in the application's context.
    725             // We simply send back the raw complex data, which will be
    726             // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
    727             TypedValue value = sa.peekValue(
    728                     com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
    729             info.minWidth = value != null ? value.data : 0;
    730             value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
    731             info.minHeight = value != null ? value.data : 0;
    732 
    733             info.updatePeriodMillis = sa.getInt(
    734                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
    735             info.initialLayout = sa.getResourceId(
    736                     com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
    737             String className = sa.getString(
    738                     com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
    739             if (className != null) {
    740                 info.configure = new ComponentName(component.getPackageName(), className);
    741             }
    742             info.label = activityInfo.loadLabel(mPackageManager).toString();
    743             info.icon = ri.getIconResource();
    744             sa.recycle();
    745         } catch (Exception e) {
    746             // Ok to catch Exception here, because anything going wrong because
    747             // of what a client process passes to us should not be fatal for the
    748             // system process.
    749             Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
    750             return null;
    751         } finally {
    752             if (parser != null) parser.close();
    753         }
    754         return p;
    755     }
    756 
    757     int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
    758         PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
    759         if (pkgInfo == null || pkgInfo.applicationInfo == null) {
    760             throw new PackageManager.NameNotFoundException();
    761         }
    762         return pkgInfo.applicationInfo.uid;
    763     }
    764 
    765     int enforceCallingUid(String packageName) throws IllegalArgumentException {
    766         int callingUid = getCallingUid();
    767         int packageUid;
    768         try {
    769             packageUid = getUidForPackage(packageName);
    770         } catch (PackageManager.NameNotFoundException ex) {
    771             throw new IllegalArgumentException("packageName and uid don't match packageName="
    772                     + packageName);
    773         }
    774         if (callingUid != packageUid && Process.supportsProcesses()) {
    775             throw new IllegalArgumentException("packageName and uid don't match packageName="
    776                     + packageName);
    777         }
    778         return callingUid;
    779     }
    780 
    781     void sendInitialBroadcasts() {
    782         synchronized (mAppWidgetIds) {
    783             final int N = mInstalledProviders.size();
    784             for (int i=0; i<N; i++) {
    785                 Provider p = mInstalledProviders.get(i);
    786                 if (p.instances.size() > 0) {
    787                     sendEnableIntentLocked(p);
    788                     int[] appWidgetIds = getAppWidgetIds(p);
    789                     sendUpdateIntentLocked(p, appWidgetIds);
    790                     registerForBroadcastsLocked(p, appWidgetIds);
    791                 }
    792             }
    793         }
    794     }
    795 
    796     // only call from initialization -- it assumes that the data structures are all empty
    797     void loadStateLocked() {
    798         File temp = savedStateTempFile();
    799         File real = savedStateRealFile();
    800 
    801         // prefer the real file.  If it doesn't exist, use the temp one, and then copy it to the
    802         // real one.  if there is both a real file and a temp one, assume that the temp one isn't
    803         // fully written and delete it.
    804         if (real.exists()) {
    805             readStateFromFileLocked(real);
    806             if (temp.exists()) {
    807                 //noinspection ResultOfMethodCallIgnored
    808                 temp.delete();
    809             }
    810         } else if (temp.exists()) {
    811             readStateFromFileLocked(temp);
    812             //noinspection ResultOfMethodCallIgnored
    813             temp.renameTo(real);
    814         }
    815     }
    816 
    817     void saveStateLocked() {
    818         File temp = savedStateTempFile();
    819         File real = savedStateRealFile();
    820 
    821         if (!real.exists()) {
    822             // If the real one doesn't exist, it's either because this is the first time
    823             // or because something went wrong while copying them.  In this case, we can't
    824             // trust anything that's in temp.  In order to have the loadState code not
    825             // use the temporary one until it's fully written, create an empty file
    826             // for real, which will we'll shortly delete.
    827             try {
    828                 //noinspection ResultOfMethodCallIgnored
    829                 real.createNewFile();
    830             } catch (IOException e) {
    831                 // Ignore
    832             }
    833         }
    834 
    835         if (temp.exists()) {
    836             //noinspection ResultOfMethodCallIgnored
    837             temp.delete();
    838         }
    839 
    840         if (!writeStateToFileLocked(temp)) {
    841             Slog.w(TAG, "Failed to persist new settings");
    842             return;
    843         }
    844 
    845         //noinspection ResultOfMethodCallIgnored
    846         real.delete();
    847         //noinspection ResultOfMethodCallIgnored
    848         temp.renameTo(real);
    849     }
    850 
    851     boolean writeStateToFileLocked(File file) {
    852         FileOutputStream stream = null;
    853         int N;
    854 
    855         try {
    856             stream = new FileOutputStream(file, false);
    857             XmlSerializer out = new FastXmlSerializer();
    858             out.setOutput(stream, "utf-8");
    859             out.startDocument(null, true);
    860 
    861 
    862             out.startTag(null, "gs");
    863 
    864             int providerIndex = 0;
    865             N = mInstalledProviders.size();
    866             for (int i=0; i<N; i++) {
    867                 Provider p = mInstalledProviders.get(i);
    868                 if (p.instances.size() > 0) {
    869                     out.startTag(null, "p");
    870                     out.attribute(null, "pkg", p.info.provider.getPackageName());
    871                     out.attribute(null, "cl", p.info.provider.getClassName());
    872                     out.endTag(null, "h");
    873                     p.tag = providerIndex;
    874                     providerIndex++;
    875                 }
    876             }
    877 
    878             N = mHosts.size();
    879             for (int i=0; i<N; i++) {
    880                 Host host = mHosts.get(i);
    881                 out.startTag(null, "h");
    882                 out.attribute(null, "pkg", host.packageName);
    883                 out.attribute(null, "id", Integer.toHexString(host.hostId));
    884                 out.endTag(null, "h");
    885                 host.tag = i;
    886             }
    887 
    888             N = mAppWidgetIds.size();
    889             for (int i=0; i<N; i++) {
    890                 AppWidgetId id = mAppWidgetIds.get(i);
    891                 out.startTag(null, "g");
    892                 out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
    893                 out.attribute(null, "h", Integer.toHexString(id.host.tag));
    894                 if (id.provider != null) {
    895                     out.attribute(null, "p", Integer.toHexString(id.provider.tag));
    896                 }
    897                 out.endTag(null, "g");
    898             }
    899 
    900             out.endTag(null, "gs");
    901 
    902             out.endDocument();
    903             stream.close();
    904             return true;
    905         } catch (IOException e) {
    906             try {
    907                 if (stream != null) {
    908                     stream.close();
    909                 }
    910             } catch (IOException ex) {
    911                 // Ignore
    912             }
    913             if (file.exists()) {
    914                 //noinspection ResultOfMethodCallIgnored
    915                 file.delete();
    916             }
    917             return false;
    918         }
    919     }
    920 
    921     void readStateFromFileLocked(File file) {
    922         FileInputStream stream = null;
    923 
    924         boolean success = false;
    925 
    926         try {
    927             stream = new FileInputStream(file);
    928             XmlPullParser parser = Xml.newPullParser();
    929             parser.setInput(stream, null);
    930 
    931             int type;
    932             int providerIndex = 0;
    933             HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>();
    934             do {
    935                 type = parser.next();
    936                 if (type == XmlPullParser.START_TAG) {
    937                     String tag = parser.getName();
    938                     if ("p".equals(tag)) {
    939                         // TODO: do we need to check that this package has the same signature
    940                         // as before?
    941                         String pkg = parser.getAttributeValue(null, "pkg");
    942                         String cl = parser.getAttributeValue(null, "cl");
    943 
    944                         final PackageManager packageManager = mContext.getPackageManager();
    945                         try {
    946                             packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
    947                         } catch (PackageManager.NameNotFoundException e) {
    948                             String[] pkgs = packageManager.currentToCanonicalPackageNames(
    949                                     new String[] { pkg });
    950                             pkg = pkgs[0];
    951                         }
    952 
    953                         Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
    954                         if (p == null && mSafeMode) {
    955                             // if we're in safe mode, make a temporary one
    956                             p = new Provider();
    957                             p.info = new AppWidgetProviderInfo();
    958                             p.info.provider = new ComponentName(pkg, cl);
    959                             p.zombie = true;
    960                             mInstalledProviders.add(p);
    961                         }
    962                         if (p != null) {
    963                             // if it wasn't uninstalled or something
    964                             loadedProviders.put(providerIndex, p);
    965                         }
    966                         providerIndex++;
    967                     }
    968                     else if ("h".equals(tag)) {
    969                         Host host = new Host();
    970 
    971                         // TODO: do we need to check that this package has the same signature
    972                         // as before?
    973                         host.packageName = parser.getAttributeValue(null, "pkg");
    974                         try {
    975                             host.uid = getUidForPackage(host.packageName);
    976                         } catch (PackageManager.NameNotFoundException ex) {
    977                             host.zombie = true;
    978                         }
    979                         if (!host.zombie || mSafeMode) {
    980                             // In safe mode, we don't discard the hosts we don't recognize
    981                             // so that they're not pruned from our list.  Otherwise, we do.
    982                             host.hostId = Integer.parseInt(
    983                                     parser.getAttributeValue(null, "id"), 16);
    984                             mHosts.add(host);
    985                         }
    986                     }
    987                     else if ("g".equals(tag)) {
    988                         AppWidgetId id = new AppWidgetId();
    989                         id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
    990                         if (id.appWidgetId >= mNextAppWidgetId) {
    991                             mNextAppWidgetId = id.appWidgetId + 1;
    992                         }
    993 
    994                         String providerString = parser.getAttributeValue(null, "p");
    995                         if (providerString != null) {
    996                             // there's no provider if it hasn't been bound yet.
    997                             // maybe we don't have to save this, but it brings the system
    998                             // to the state it was in.
    999                             int pIndex = Integer.parseInt(providerString, 16);
   1000                             id.provider = loadedProviders.get(pIndex);
   1001                             if (false) {
   1002                                 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
   1003                                         + pIndex + " which is " + id.provider);
   1004                             }
   1005                             if (id.provider == null) {
   1006                                 // This provider is gone.  We just let the host figure out
   1007                                 // that this happened when it fails to load it.
   1008                                 continue;
   1009                             }
   1010                         }
   1011 
   1012                         int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
   1013                         id.host = mHosts.get(hIndex);
   1014                         if (id.host == null) {
   1015                             // This host is gone.
   1016                             continue;
   1017                         }
   1018 
   1019                         if (id.provider != null) {
   1020                             id.provider.instances.add(id);
   1021                         }
   1022                         id.host.instances.add(id);
   1023                         mAppWidgetIds.add(id);
   1024                     }
   1025                 }
   1026             } while (type != XmlPullParser.END_DOCUMENT);
   1027             success = true;
   1028         } catch (NullPointerException e) {
   1029             Slog.w(TAG, "failed parsing " + file, e);
   1030         } catch (NumberFormatException e) {
   1031             Slog.w(TAG, "failed parsing " + file, e);
   1032         } catch (XmlPullParserException e) {
   1033             Slog.w(TAG, "failed parsing " + file, e);
   1034         } catch (IOException e) {
   1035             Slog.w(TAG, "failed parsing " + file, e);
   1036         } catch (IndexOutOfBoundsException e) {
   1037             Slog.w(TAG, "failed parsing " + file, e);
   1038         }
   1039         try {
   1040             if (stream != null) {
   1041                 stream.close();
   1042             }
   1043         } catch (IOException e) {
   1044             // Ignore
   1045         }
   1046 
   1047         if (success) {
   1048             // delete any hosts that didn't manage to get connected (should happen)
   1049             // if it matters, they'll be reconnected.
   1050             for (int i=mHosts.size()-1; i>=0; i--) {
   1051                 pruneHostLocked(mHosts.get(i));
   1052             }
   1053         } else {
   1054             // failed reading, clean up
   1055             mAppWidgetIds.clear();
   1056             mHosts.clear();
   1057             final int N = mInstalledProviders.size();
   1058             for (int i=0; i<N; i++) {
   1059                 mInstalledProviders.get(i).instances.clear();
   1060             }
   1061         }
   1062     }
   1063 
   1064     File savedStateTempFile() {
   1065         return new File("/data/system/" + SETTINGS_TMP_FILENAME);
   1066         //return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
   1067     }
   1068 
   1069     File savedStateRealFile() {
   1070         return new File("/data/system/" + SETTINGS_FILENAME);
   1071         //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
   1072     }
   1073 
   1074     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
   1075         public void onReceive(Context context, Intent intent) {
   1076             String action = intent.getAction();
   1077             //Slog.d(TAG, "received " + action);
   1078             if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
   1079                 sendInitialBroadcasts();
   1080             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
   1081                 Locale revised = Locale.getDefault();
   1082                 if (revised == null || mLocale == null ||
   1083                     !(revised.equals(mLocale))) {
   1084                     mLocale = revised;
   1085 
   1086                     synchronized (mAppWidgetIds) {
   1087                         int N = mInstalledProviders.size();
   1088                         for (int i=N-1; i>=0; i--) {
   1089                             Provider p = mInstalledProviders.get(i);
   1090                             String pkgName = p.info.provider.getPackageName();
   1091                             updateProvidersForPackageLocked(pkgName);
   1092                         }
   1093                         saveStateLocked();
   1094                     }
   1095                 }
   1096             } else {
   1097                 boolean added = false;
   1098                 String pkgList[] = null;
   1099                 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
   1100                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1101                     added = true;
   1102                 } if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
   1103                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
   1104                     added = false;
   1105                 } else  {
   1106                     Uri uri = intent.getData();
   1107                     if (uri == null) {
   1108                         return;
   1109                     }
   1110                     String pkgName = uri.getSchemeSpecificPart();
   1111                     if (pkgName == null) {
   1112                         return;
   1113                     }
   1114                     pkgList = new String[] { pkgName };
   1115                     added = Intent.ACTION_PACKAGE_ADDED.equals(action);
   1116                 }
   1117                 if (pkgList == null || pkgList.length == 0) {
   1118                     return;
   1119                 }
   1120                 if (added) {
   1121                     synchronized (mAppWidgetIds) {
   1122                         Bundle extras = intent.getExtras();
   1123                         if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
   1124                             for (String pkgName : pkgList) {
   1125                                 // The package was just upgraded
   1126                                 updateProvidersForPackageLocked(pkgName);
   1127                             }
   1128                         } else {
   1129                             // The package was just added
   1130                             for (String pkgName : pkgList) {
   1131                                 addProvidersForPackageLocked(pkgName);
   1132                             }
   1133                         }
   1134                         saveStateLocked();
   1135                     }
   1136                 } else {
   1137                     Bundle extras = intent.getExtras();
   1138                     if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
   1139                         // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
   1140                     } else {
   1141                         synchronized (mAppWidgetIds) {
   1142                             for (String pkgName : pkgList) {
   1143                                 removeProvidersForPackageLocked(pkgName);
   1144                                 saveStateLocked();
   1145                             }
   1146                         }
   1147                     }
   1148                 }
   1149             }
   1150         }
   1151     };
   1152 
   1153     void addProvidersForPackageLocked(String pkgName) {
   1154         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
   1155         intent.setPackage(pkgName);
   1156         List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
   1157                 PackageManager.GET_META_DATA);
   1158 
   1159         final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
   1160         for (int i=0; i<N; i++) {
   1161             ResolveInfo ri = broadcastReceivers.get(i);
   1162             ActivityInfo ai = ri.activityInfo;
   1163 
   1164             if (pkgName.equals(ai.packageName)) {
   1165                 addProviderLocked(ri);
   1166             }
   1167         }
   1168     }
   1169 
   1170     void updateProvidersForPackageLocked(String pkgName) {
   1171         HashSet<String> keep = new HashSet<String>();
   1172         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
   1173         intent.setPackage(pkgName);
   1174         List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
   1175                 PackageManager.GET_META_DATA);
   1176 
   1177         // add the missing ones and collect which ones to keep
   1178         int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
   1179         for (int i=0; i<N; i++) {
   1180             ResolveInfo ri = broadcastReceivers.get(i);
   1181             ActivityInfo ai = ri.activityInfo;
   1182             if (pkgName.equals(ai.packageName)) {
   1183                 ComponentName component = new ComponentName(ai.packageName, ai.name);
   1184                 Provider p = lookupProviderLocked(component);
   1185                 if (p == null) {
   1186                     if (addProviderLocked(ri)) {
   1187                         keep.add(ai.name);
   1188                     }
   1189                 } else {
   1190                     Provider parsed = parseProviderInfoXml(component, ri);
   1191                     if (parsed != null) {
   1192                         keep.add(ai.name);
   1193                         // Use the new AppWidgetProviderInfo.
   1194                         p.info = parsed.info;
   1195                         // If it's enabled
   1196                         final int M = p.instances.size();
   1197                         if (M > 0) {
   1198                             int[] appWidgetIds = getAppWidgetIds(p);
   1199                             // Reschedule for the new updatePeriodMillis (don't worry about handling
   1200                             // it specially if updatePeriodMillis didn't change because we just sent
   1201                             // an update, and the next one will be updatePeriodMillis from now).
   1202                             cancelBroadcasts(p);
   1203                             registerForBroadcastsLocked(p, appWidgetIds);
   1204                             // If it's currently showing, call back with the new AppWidgetProviderInfo.
   1205                             for (int j=0; j<M; j++) {
   1206                                 AppWidgetId id = p.instances.get(j);
   1207                                 if (id.host != null && id.host.callbacks != null) {
   1208                                     try {
   1209                                         id.host.callbacks.providerChanged(id.appWidgetId, p.info);
   1210                                     } catch (RemoteException ex) {
   1211                                         // It failed; remove the callback. No need to prune because
   1212                                         // we know that this host is still referenced by this
   1213                                         // instance.
   1214                                         id.host.callbacks = null;
   1215                                     }
   1216                                 }
   1217                             }
   1218                             // Now that we've told the host, push out an update.
   1219                             sendUpdateIntentLocked(p, appWidgetIds);
   1220                         }
   1221                     }
   1222                 }
   1223             }
   1224         }
   1225 
   1226         // prune the ones we don't want to keep
   1227         N = mInstalledProviders.size();
   1228         for (int i=N-1; i>=0; i--) {
   1229             Provider p = mInstalledProviders.get(i);
   1230             if (pkgName.equals(p.info.provider.getPackageName())
   1231                     && !keep.contains(p.info.provider.getClassName())) {
   1232                 removeProviderLocked(i, p);
   1233             }
   1234         }
   1235     }
   1236 
   1237     void removeProvidersForPackageLocked(String pkgName) {
   1238         int N = mInstalledProviders.size();
   1239         for (int i=N-1; i>=0; i--) {
   1240             Provider p = mInstalledProviders.get(i);
   1241             if (pkgName.equals(p.info.provider.getPackageName())) {
   1242                 removeProviderLocked(i, p);
   1243             }
   1244         }
   1245 
   1246         // Delete the hosts for this package too
   1247         //
   1248         // By now, we have removed any AppWidgets that were in any hosts here,
   1249         // so we don't need to worry about sending DISABLE broadcasts to them.
   1250         N = mHosts.size();
   1251         for (int i=N-1; i>=0; i--) {
   1252             Host host = mHosts.get(i);
   1253             if (pkgName.equals(host.packageName)) {
   1254                 deleteHostLocked(host);
   1255             }
   1256         }
   1257     }
   1258 }
   1259 
   1260