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