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