Fixing index-out-of-bounds in AppWidgetService. (Bug 6717459)

Change-Id: I9d676fbb2110f01eb1d36adc59437a6a5ec97cc2
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 7bc6a88..8156856 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -208,11 +208,19 @@
 
             synchronized (mAppWidgetIds) {
                 ensureStateLoadedLocked();
-                int N = mInstalledProviders.size();
+                // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the
+                // list of installed providers and skip providers that we don't need to update.
+                // Also note that remove the provider does not clear the Provider component data.
+                ArrayList<Provider> installedProviders =
+                        new ArrayList<Provider>(mInstalledProviders);
+                HashSet<ComponentName> removedProviders = new HashSet<ComponentName>();
+                int N = installedProviders.size();
                 for (int i = N - 1; i >= 0; i--) {
-                    Provider p = mInstalledProviders.get(i);
-                    String pkgName = p.info.provider.getPackageName();
-                    updateProvidersForPackageLocked(pkgName);
+                    Provider p = installedProviders.get(i);
+                    ComponentName cn = p.info.provider;
+                    if (!removedProviders.contains(cn)) {
+                        updateProvidersForPackageLocked(cn.getPackageName(), removedProviders);
+                    }
                 }
                 saveStateLocked();
             }
@@ -255,7 +263,7 @@
                         || (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
                     for (String pkgName : pkgList) {
                         // The package was just upgraded
-                        providersModified |= updateProvidersForPackageLocked(pkgName);
+                        providersModified |= updateProvidersForPackageLocked(pkgName, null);
                     }
                 } else {
                     // The package was just added
@@ -1675,7 +1683,13 @@
         return providersAdded;
     }
 
-    boolean updateProvidersForPackageLocked(String pkgName) {
+    /**
+     * Updates all providers with the specified package names, and records any providers that were
+     * pruned.
+     *
+     * @return whether any providers were updated
+     */
+    boolean updateProvidersForPackageLocked(String pkgName, Set<ComponentName> removedProviders) {
         boolean providersUpdated = false;
         HashSet<String> keep = new HashSet<String>();
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
@@ -1752,6 +1766,9 @@
             Provider p = mInstalledProviders.get(i);
             if (pkgName.equals(p.info.provider.getPackageName())
                     && !keep.contains(p.info.provider.getClassName())) {
+                if (removedProviders != null) {
+                    removedProviders.add(p.info.provider);
+                }
                 removeProviderLocked(i, p);
                 providersUpdated = true;
             }