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