Fix issue #2541849: System crash when an app with active notifications...

...in status bar is installed on sdcard and device is powered down.

Don't do the GC until everyone has had a chance to take care of external
storage going away.

This is more correct, but doesn't completely fix the problem that
appears when shutting down.

Change-Id: I24b19337ba6262cfd8d010645dbf67e76ea03058
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 0a30816..e6663d4 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -33,6 +33,7 @@
 import android.app.backup.IBackupManager;
 import android.content.Context;
 import android.content.ComponentName;
+import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -583,11 +584,11 @@
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras);
+                                    extras, null);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras);
+                                        extras, null);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -4472,7 +4473,8 @@
         }
     };
 
-    private static final void sendPackageBroadcast(String action, String pkg, Bundle extras) {
+    private static final void sendPackageBroadcast(String action, String pkg,
+            Bundle extras, IIntentReceiver finishedReceiver) {
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
@@ -4482,9 +4484,8 @@
                     intent.putExtras(extras);
                 }
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                am.broadcastIntent(
-                    null, intent,
-                            null, null, 0, null, null, null, false, false);
+                am.broadcastIntent(null, intent, null, finishedReceiver,
+                        0, null, null, null, finishedReceiver != null, false);
             } catch (RemoteException ex) {
             }
         }
@@ -4606,12 +4607,14 @@
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
+                        extras, null);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
+                        extras, null);
             }
         }
 
@@ -6053,8 +6056,8 @@
                 extras.putInt(Intent.EXTRA_UID, info.removedUid >= 0 ? info.removedUid : info.uid);
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
 
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras);
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, extras, null);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras, null);
             }
         }
         // Force a gc here.
@@ -6085,10 +6088,10 @@
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
             }
             if (removedPackage != null) {
-                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
+                sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null);
             }
             if (removedUid >= 0) {
-                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras);
+                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null);
             }
         }
     }
@@ -6790,7 +6793,7 @@
         extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
-        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras);
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null);
     }
 
     public String getInstallerPackageName(String packageName) {
@@ -9513,7 +9516,7 @@
    }
 
    private void sendResourcesChangedBroadcast(boolean mediaStatus,
-           ArrayList<String> pkgList, int uidArr[]) {
+           ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
        int size = pkgList.size();
        if (size > 0) {
            // Send broadcasts here
@@ -9525,7 +9528,7 @@
            }
            String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                    : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
-           sendPackageBroadcast(action, null, extras);
+           sendPackageBroadcast(action, null, extras, finishedReceiver);
        }
    }
 
@@ -9612,7 +9615,7 @@
        }
        // Send a broadcast to let everyone know we are done processing
        if (pkgList.size() > 0) {
-           sendResourcesChangedBroadcast(true, pkgList, uidArr);
+           sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
        }
        if (doGc) {
            Runtime.getRuntime().gc();
@@ -9650,10 +9653,15 @@
        }
        // Send broadcasts
        if (pkgList.size() > 0) {
-           sendResourcesChangedBroadcast(false, pkgList, uidArr);
+           sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
+               public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+                       boolean ordered, boolean sticky) throws RemoteException {
+                   // Force gc now that everyone is done cleaning up, to release
+                   // references on assets.
+                   Runtime.getRuntime().gc();
+               }
+           });
        }
-       // Force gc
-       Runtime.getRuntime().gc();
        // Just unmount all valid containers.
        for (SdInstallArgs args : keys) {
            synchronized (mInstallLock) {
@@ -9743,7 +9751,7 @@
                    }
                    if (returnCode == PackageManager.MOVE_SUCCEEDED) {
                        // Send resources unavailable broadcast
-                       sendResourcesChangedBroadcast(false, pkgList, uidArr);
+                       sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
                        // Update package code and resource paths
                        synchronized (mInstallLock) {
                            synchronized (mPackages) {
@@ -9794,7 +9802,7 @@
                                }
                            }
                            // Send resources available broadcast
-                           sendResourcesChangedBroadcast(true, pkgList, uidArr);
+                           sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
                        }
                    }
                }