Apps on sdcard: Add new broadcasts

Add new broadcasts ACTION_MEDIA_RESOURCES_AVAILABLE and
ACTION_MEDIA_RESOURCES_UNAVAILABLE that get broadcast by
PackageManagerService when sdcard gets mounted/unmounted
by MountService so that packages on sdcard get recognized by
various system services as being installed/available or
removed/unavailable by the system.
The broadcasts are sent before the actual package cleanup which includes
mounting/unmounting the packages and we force a gc right after so
that any lingering file references to resources on sdcard get
released.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b723dcd..5e6881c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1196,7 +1196,7 @@
                     int uid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
-                    forceStopPackageLocked(pkg, uid, restart);
+                    forceStopPackageLocked(pkg, uid, restart, false);
                 }
             } break;
             }
@@ -4998,7 +4998,7 @@
     }
 
     private void forceStopPackageLocked(final String packageName, int uid) {
-        forceStopPackageLocked(packageName, uid, false);
+        forceStopPackageLocked(packageName, uid, false, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         intent.putExtra(Intent.EXTRA_UID, uid);
@@ -5037,9 +5037,9 @@
             removeProcessLocked(procs.get(i), callerWillRestart);
         }
     }
-    
+
     private final void forceStopPackageLocked(String name, int uid,
-            boolean callerWillRestart) {
+            boolean callerWillRestart, boolean purgeCache) {
         int i, N;
 
         if (uid < 0) {
@@ -5091,6 +5091,12 @@
         }
         
         resumeTopActivityLocked(null);
+        if (purgeCache) {
+            AttributeCache ac = AttributeCache.instance();
+            if (ac != null) {
+                ac.removePackage(name);
+            }
+        }
     }
 
     private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
@@ -8054,7 +8060,7 @@
             mDebugTransient = !persistent;
             if (packageName != null) {
                 final long origId = Binder.clearCallingIdentity();
-                forceStopPackageLocked(packageName, -1, false);
+                forceStopPackageLocked(packageName, -1, false, false);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -11935,6 +11941,7 @@
                 intent.getAction());
         if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
                 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
+                || Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())
                 || uidRemoved) {
             if (checkComponentPermission(
                     android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
@@ -11951,15 +11958,22 @@
                         }
                     }
                 } else {
-                    Uri data = intent.getData();
-                    String ssp;
-                    if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
-                        if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
-                            forceStopPackageLocked(ssp,
-                                    intent.getIntExtra(Intent.EXTRA_UID, -1), false);
-                            AttributeCache ac = AttributeCache.instance();
-                            if (ac != null) {
-                                ac.removePackage(ssp);
+                    // If resources are unvailble just force stop all
+                    // those packages and flush the attribute cache as well.
+                    if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) {
+                        String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                        if (list != null && (list.length > 0)) {
+                            for (String pkg : list) {
+                                forceStopPackageLocked(pkg, -1, false, true);
+                            }
+                        }
+                    } else {
+                        Uri data = intent.getData();
+                        String ssp;
+                        if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
+                            if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
+                                forceStopPackageLocked(ssp,
+                                        intent.getIntExtra(Intent.EXTRA_UID, -1), false, true);
                             }
                         }
                     }
@@ -12121,25 +12135,32 @@
             // installed.  Maybe in the future we want to have a special install
             // broadcast or such for apps, but we'd like to deliberately make
             // this decision.
-            boolean skip = false;
-            if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
-                skip = true;
-            } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
-                skip = true;
-            } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
-                skip = true;
+            String skipPackages[] = null;
+            if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
+                    || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
+                    || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
+                Uri data = intent.getData();
+                if (data != null) {
+                    String pkgName = data.getSchemeSpecificPart();
+                    if (pkgName != null) {
+                        skipPackages = new String[] { pkgName };
+                    }
+                }
+            } else if (intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(intent.getAction())) {
+                skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
-            String skipPackage = (skip && intent.getData() != null)
-                    ? intent.getData().getSchemeSpecificPart()
-                    : null;
-            if (skipPackage != null && receivers != null) {
-                int NT = receivers.size();
-                for (int it=0; it<NT; it++) {
-                    ResolveInfo curt = (ResolveInfo)receivers.get(it);
-                    if (curt.activityInfo.packageName.equals(skipPackage)) {
-                        receivers.remove(it);
-                        it--;
-                        NT--;
+            if (skipPackages != null && (skipPackages.length > 0)) {
+                for (String skipPackage : skipPackages) {
+                    if (skipPackage != null) {
+                        int NT = receivers.size();
+                        for (int it=0; it<NT; it++) {
+                            ResolveInfo curt = (ResolveInfo)receivers.get(it);
+                            if (curt.activityInfo.packageName.equals(skipPackage)) {
+                                receivers.remove(it);
+                                it--;
+                                NT--;
+                            }
+                        }
                     }
                 }
             }
@@ -12923,7 +12944,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            forceStopPackageLocked(ii.targetPackage, -1, true);
+            forceStopPackageLocked(ii.targetPackage, -1, true, false);
             ProcessRecord app = addAppLocked(ai);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
@@ -12978,7 +12999,7 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        forceStopPackageLocked(app.processName, -1, false);
+        forceStopPackageLocked(app.processName, -1, false, false);
     }
 
     public void finishInstrumentation(IApplicationThread target,