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