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