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/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index f67a7ae..b56b13b 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -174,6 +174,11 @@
         packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         packageFilter.addDataScheme("package");
         context.registerReceiver(broadcastReceiver, packageFilter);
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(broadcastReceiver, sdFilter);
 
         // boot completed
         IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 18a5615..f330651 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -772,16 +772,33 @@
             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
             filter.addDataScheme("package");
             mContext.registerReceiver(this, filter);
+             // Register for events related to sdcard installation.
+            IntentFilter sdFilter = new IntentFilter();
+            sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+            mContext.registerReceiver(this, sdFilter);
         }
         
         @Override
         public void onReceive(Context context, Intent intent) {
             synchronized (mLock) {
-                Uri data = intent.getData();
-                if (data != null) {
-                    String pkg = data.getSchemeSpecificPart();
-                    removeLocked(pkg);
-                    mBroadcastStats.remove(pkg);
+                String action = intent.getAction();
+                String pkgList[] = null;
+                if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                } else {
+                    Uri data = intent.getData();
+                    if (data != null) {
+                        String pkg = data.getSchemeSpecificPart();
+                        if (pkg != null) {
+                            pkgList = new String[]{pkg};
+                        }
+                    }
+                }
+                if (pkgList != null && (pkgList.length > 0)) {
+                    for (String pkg : pkgList) {
+                        removeLocked(pkg);
+                        mBroadcastStats.remove(pkg);
+                    }
                 }
             }
         }
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index ec7c60b..684f117 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -145,6 +145,11 @@
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
     }
 
     @Override
@@ -1070,36 +1075,55 @@
                     }
                 }
             } else {
-                Uri uri = intent.getData();
-                if (uri == null) {
+                boolean added = false;
+                String pkgList[] = null;
+                if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) {
+                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                    added = true;
+                } if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                    added = false;
+                } else  {
+                    Uri uri = intent.getData();
+                    if (uri == null) {
+                        return;
+                    }
+                    String pkgName = uri.getSchemeSpecificPart();
+                    if (pkgName == null) {
+                        return;
+                    }
+                    pkgList = new String[] { pkgName };
+                    added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+                }
+                if (pkgList == null || pkgList.length == 0) {
                     return;
                 }
-                String pkgName = uri.getSchemeSpecificPart();
-                if (pkgName == null) {
-                    return;
-                }
-                
-                if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+                if (added) {
                     synchronized (mAppWidgetIds) {
                         Bundle extras = intent.getExtras();
                         if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
-                            // The package was just upgraded
-                            updateProvidersForPackageLocked(pkgName);
+                            for (String pkgName : pkgList) {
+                                // The package was just upgraded
+                                updateProvidersForPackageLocked(pkgName);
+                            }
                         } else {
                             // The package was just added
-                            addProvidersForPackageLocked(pkgName);
+                            for (String pkgName : pkgList) {
+                                addProvidersForPackageLocked(pkgName);
+                            }
                         }
                         saveStateLocked();
                     }
-                }
-                else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                } else {
                     Bundle extras = intent.getExtras();
                     if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
                         // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                     } else {
                         synchronized (mAppWidgetIds) {
-                            removeProvidersForPackageLocked(pkgName);
-                            saveStateLocked();
+                            for (String pkgName : pkgList) {
+                                removeProvidersForPackageLocked(pkgName);
+                                saveStateLocked();
+                            }
                         }
                     }
                 }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index ef184d2..0562c55 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -529,6 +529,11 @@
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
     }
 
     private void parseLeftoverJournals() {
@@ -665,35 +670,53 @@
         public void onReceive(Context context, Intent intent) {
             if (DEBUG) Log.d(TAG, "Received broadcast " + intent);
 
-            Uri uri = intent.getData();
-            if (uri == null) {
-                return;
-            }
-            String pkgName = uri.getSchemeSpecificPart();
-            if (pkgName == null) {
-                return;
-            }
-
             String action = intent.getAction();
-            if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+            boolean replacing = false;
+            boolean added = false;
+            Bundle extras = intent.getExtras();
+            String pkgList[] = null;
+            if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+                    Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                Uri uri = intent.getData();
+                if (uri == null) {
+                    return;
+                }
+                String pkgName = uri.getSchemeSpecificPart();
+                if (pkgName != null) {
+                    pkgList = new String[] { pkgName };
+                }
+                added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+                replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
+            } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) {
+                added = true;
+                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            } else if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                added = false;
+                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            }
+            if (pkgList == null || pkgList.length == 0) {
+                return;
+            }
+            if (added) {
                 synchronized (mBackupParticipants) {
-                    Bundle extras = intent.getExtras();
-                    if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
-                        // The package was just upgraded
-                        updatePackageParticipantsLocked(pkgName);
-                    } else {
-                        // The package was just added
-                        addPackageParticipantsLocked(pkgName);
+                    for (String pkgName : pkgList) {
+                        if (replacing) {
+                            // The package was just upgraded
+                            updatePackageParticipantsLocked(pkgName);
+                        } else {
+                            // The package was just added
+                            addPackageParticipantsLocked(pkgName);
+                        }
                     }
                 }
-            }
-            else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
-                Bundle extras = intent.getExtras();
-                if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+            } else {
+                if (replacing) {
                     // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
                 } else {
                     synchronized (mBackupParticipants) {
-                        removePackageParticipantsLocked(pkgName);
+                        for (String pkgName : pkgList) {
+                            removePackageParticipantsLocked(pkgName);
+                        }
                     }
                 }
             }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 405dc2e..dc942a2 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -335,6 +335,22 @@
     class PackageReceiver extends android.content.BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            String pkgList[] = null;
+            if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+                    Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                Uri uri = intent.getData();
+                String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+                if (pkg != null) {
+                    pkgList = new String[] { pkg };
+                }
+            } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) ||
+                    Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            }
+            if (pkgList == null || pkgList.length == 0) {
+                return;
+            }
             synchronized (mMethodMap) {
                 buildInputMethodListLocked(mMethodList, mMethodMap);
 
@@ -352,38 +368,45 @@
 
                 boolean changed = false;
 
-                Uri uri = intent.getData();
-                String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
-                if (curIm != null && curIm.getPackageName().equals(pkg)) {
-                    ServiceInfo si = null;
-                    try {
-                        si = mContext.getPackageManager().getServiceInfo(
-                                curIm.getComponent(), 0);
-                    } catch (PackageManager.NameNotFoundException ex) {
-                    }
-                    if (si == null) {
-                        // Uh oh, current input method is no longer around!
-                        // Pick another one...
-                        Log.i(TAG, "Current input method removed: " + curInputMethodId);
-                        if (!chooseNewDefaultIME()) {
-                            changed = true;
-                            curIm = null;
-                            curInputMethodId = "";
-                            Log.i(TAG, "Unsetting current input method");
-                            Settings.Secure.putString(mContext.getContentResolver(),
-                                    Settings.Secure.DEFAULT_INPUT_METHOD,
-                                    curInputMethodId);
+                if (curIm != null) {
+                    boolean foundPkg = false;
+                    for (String pkg : pkgList) {
+                        if (curIm.getPackageName().equals(pkg)) {
+                            foundPkg = true;
+                            break;
                         }
                     }
+                    if (foundPkg) {
+                        ServiceInfo si = null;
+                        try {
+                            si = mContext.getPackageManager().getServiceInfo(
+                                    curIm.getComponent(), 0);
+                        } catch (PackageManager.NameNotFoundException ex) {
+                        }
+                        if (si == null) {
+                            // Uh oh, current input method is no longer around!
+                            // Pick another one...
+                            Log.i(TAG, "Current input method removed: " + curInputMethodId);
+                            if (!chooseNewDefaultIME()) {
+                                changed = true;
+                                curIm = null;
+                                curInputMethodId = "";
+                                Log.i(TAG, "Unsetting current input method");
+                                Settings.Secure.putString(mContext.getContentResolver(),
+                                        Settings.Secure.DEFAULT_INPUT_METHOD,
+                                        curInputMethodId);
+                            }
+                        }
 
-                } else if (curIm == null) {
-                    // We currently don't have a default input method... is
-                    // one now available?
-                    changed = chooseNewDefaultIME();
-                }
+                    } else if (curIm == null) {
+                        // We currently don't have a default input method... is
+                        // one now available?
+                        changed = chooseNewDefaultIME();
+                    }
 
-                if (changed) {
-                    updateFromSettingsLocked();
+                    if (changed) {
+                        updateFromSettingsLocked();
+                    }
                 }
             }
         }
@@ -415,13 +438,19 @@
             }
         });
 
+        PackageReceiver mBroadcastReceiver = new PackageReceiver();
         IntentFilter packageFilt = new IntentFilter();
         packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
         packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
         packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
         packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         packageFilt.addDataScheme("package");
-        mContext.registerReceiver(new PackageReceiver(), packageFilt);
+        mContext.registerReceiver(mBroadcastReceiver, packageFilt);
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
 
         IntentFilter screenOnOffFilt = new IntentFilter();
         screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 1c82c94..3a42b37 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -484,6 +484,8 @@
         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         mContext.registerReceiver(mBroadcastReceiver, intentFilter);
+        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
 
         // listen for settings changes
         ContentResolver resolver = mContext.getContentResolver();
@@ -1549,43 +1551,54 @@
             String action = intent.getAction();
 
             if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
-                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
+                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
+                    || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
                 synchronized (mLock) {
-                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
-                    if (uid >= 0) {
-                        ArrayList<Receiver> removedRecs = null;
-                        for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
-                            for (int j=i.size()-1; j>=0; j--) {
-                                UpdateRecord ur = i.get(j);
-                                if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
-                                    if (removedRecs == null) {
-                                        removedRecs = new ArrayList<Receiver>();
-                                    }
-                                    if (!removedRecs.contains(ur.mReceiver)) {
-                                        removedRecs.add(ur.mReceiver);
+                    int uidList[] = null;
+                    if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                        uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+                    } else {
+                        uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
+                    }
+                    if (uidList == null || uidList.length == 0) {
+                        return;
+                    }
+                    for (int uid : uidList) {
+                        if (uid >= 0) {
+                            ArrayList<Receiver> removedRecs = null;
+                            for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
+                                for (int j=i.size()-1; j>=0; j--) {
+                                    UpdateRecord ur = i.get(j);
+                                    if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
+                                        if (removedRecs == null) {
+                                            removedRecs = new ArrayList<Receiver>();
+                                        }
+                                        if (!removedRecs.contains(ur.mReceiver)) {
+                                            removedRecs.add(ur.mReceiver);
+                                        }
                                     }
                                 }
                             }
-                        }
-                        ArrayList<ProximityAlert> removedAlerts = null;
-                        for (ProximityAlert i : mProximityAlerts.values()) {
-                            if (i.mUid == uid) {
-                                if (removedAlerts == null) {
-                                    removedAlerts = new ArrayList<ProximityAlert>();
-                                }
-                                if (!removedAlerts.contains(i)) {
-                                    removedAlerts.add(i);
+                            ArrayList<ProximityAlert> removedAlerts = null;
+                            for (ProximityAlert i : mProximityAlerts.values()) {
+                                if (i.mUid == uid) {
+                                    if (removedAlerts == null) {
+                                        removedAlerts = new ArrayList<ProximityAlert>();
+                                    }
+                                    if (!removedAlerts.contains(i)) {
+                                        removedAlerts.add(i);
+                                    }
                                 }
                             }
-                        }
-                        if (removedRecs != null) {
-                            for (int i=removedRecs.size()-1; i>=0; i--) {
-                                removeUpdatesLocked(removedRecs.get(i));
+                            if (removedRecs != null) {
+                                for (int i=removedRecs.size()-1; i>=0; i--) {
+                                    removeUpdatesLocked(removedRecs.get(i));
+                                }
                             }
-                        }
-                        if (removedAlerts != null) {
-                            for (int i=removedAlerts.size()-1; i>=0; i--) {
-                                removeProximityAlertLocked(removedAlerts.get(i).mIntent);
+                            if (removedAlerts != null) {
+                                for (int i=removedAlerts.size()-1; i>=0; i--) {
+                                    removeProximityAlertLocked(removedAlerts.get(i).mIntent);
+                                }
                             }
                         }
                     }
@@ -1599,7 +1612,7 @@
                     mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
                 }
                 NetworkInfo info =
-                        (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+                    (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
 
                 // Notify location providers of current network state
                 synchronized (mLock) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index fc89ec8..02a0401 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -329,16 +329,27 @@
                 mUsbConnected = false;
                 updateAdbNotification();
             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
-                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
-                Uri uri = intent.getData();
-                if (uri == null) {
-                    return;
+                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
+                    || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                String pkgList[] = null;
+                if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                } else {
+                    Uri uri = intent.getData();
+                    if (uri == null) {
+                        return;
+                    }
+                    String pkgName = uri.getSchemeSpecificPart();
+                    if (pkgName == null) {
+                        return;
+                    }
+                    pkgList = new String[]{pkgName};
                 }
-                String pkgName = uri.getSchemeSpecificPart();
-                if (pkgName == null) {
-                    return;
+                if (pkgList != null && (pkgList.length > 0)) {
+                    for (String pkgName : pkgList) {
+                        cancelAllNotificationsInt(pkgName, 0, 0);
+                    }
                 }
-                cancelAllNotificationsInt(pkgName, 0, 0);
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 mScreenOn = true;
                 updateNotificationPulse();
@@ -429,6 +440,8 @@
         filter.addAction(Intent.ACTION_SCREEN_ON);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(mIntentReceiver, filter);
+        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+        mContext.registerReceiver(mIntentReceiver, sdFilter);
 
         SettingsObserver observer = new SettingsObserver(mHandler);
         observer.observe();
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 4801817..238403c 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -63,6 +63,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
@@ -2179,21 +2180,32 @@
             parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
         }
 
+        String codePath = null;
+        String resPath = null;
         if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) {
             if (ps != null && ps.resourcePathString != null) {
-                pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
+                resPath = ps.resourcePathString;
             } else {
                 // Should not happen at all. Just log an error.
                 Log.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
             }
         } else {
-            pkg.applicationInfo.publicSourceDir = pkg.mScanPath;
+            resPath = pkg.mScanPath;
         }
-        pkg.applicationInfo.sourceDir = pkg.mScanPath;
+        codePath = pkg.mScanPath;
+        // Set application objects path explicitly.
+        setApplicationInfoPaths(pkg, codePath, resPath);
         // Note that we invoke the following method only if we are about to unpack an application
         return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
     }
 
+    private static void setApplicationInfoPaths(PackageParser.Package pkg,
+            String destCodePath, String destResPath) {
+        pkg.mPath = pkg.mScanPath = destCodePath;
+        pkg.applicationInfo.sourceDir = destCodePath;
+        pkg.applicationInfo.publicSourceDir = destResPath;
+    }
+
     private static String fixProcessName(String defProcessName,
             String processName, int uid) {
         if (processName == null) {
@@ -4025,7 +4037,7 @@
                     if (res.removedInfo.args != null) {
                         // Remove the replaced package's older resources safely now
                         synchronized (mInstallLock) {
-                            res.removedInfo.args.cleanUpResourcesLI();
+                            res.removedInfo.args.doPostDeleteLI(true);
                         }
                     }
                 }
@@ -4051,13 +4063,14 @@
 
         abstract void createCopyFile();
         abstract int copyApk(IMediaContainerService imcs);
-        abstract void doPreInstall(int status);
+        abstract int doPreInstall(int status);
         abstract boolean doRename(int status, String pkgName, String oldCodePath);
-        abstract void doPostInstall(int status);
+        abstract int doPostInstall(int status);
         abstract String getCodePath();
         abstract String getResourcePath();
         // Need installer lock especially for dex file removal.
         abstract void cleanUpResourcesLI();
+        abstract boolean doPostDeleteLI(boolean delete);
     }
 
     class FileInstallArgs extends InstallArgs {
@@ -4114,10 +4127,11 @@
             return ret;
         }
 
-        void doPreInstall(int status) {
+        int doPreInstall(int status) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
             }
+            return status;
         }
 
         boolean doRename(int status, final String pkgName, String oldCodePath) {
@@ -4144,10 +4158,11 @@
             }
         }
 
-        void doPostInstall(int status) {
+        int doPostInstall(int status) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
             }
+            return status;
         }
 
         String getResourcePath() {
@@ -4220,6 +4235,11 @@
             }
             return true;
         }
+
+        boolean doPostDeleteLI(boolean delete) {
+            cleanUpResourcesLI();
+            return true;
+        }
     }
 
     class SdInstallArgs extends InstallArgs {
@@ -4234,7 +4254,7 @@
         }
 
         SdInstallArgs(String fullCodePath, String fullResourcePath) {
-            super(null, null, 0, null);
+            super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null);
             // Extract cid from fullCodePath
             int eidx = fullCodePath.lastIndexOf("/");
             String subStr1 = fullCodePath.substring(0, eidx);
@@ -4243,6 +4263,11 @@
             cachePath = subStr1;
         }
 
+        SdInstallArgs(String cid) {
+            super(null, null,  ApplicationInfo.FLAG_ON_SDCARD, null);
+            this.cid = cid;
+        }
+
         void createCopyFile() {
             cid = getTempContainerId();
         }
@@ -4254,16 +4279,8 @@
                         getEncryptKey(), RES_FILE_NAME);
             } catch (RemoteException e) {
             }
-
-            if (cachePath != null) {
-                // Mount container once its created with system_uid
-                cachePath = mountSdDir(cid, Process.SYSTEM_UID);
-            }
-            if (cachePath == null) {
-                return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
-            } else {
-                return PackageManager.INSTALL_SUCCEEDED;
-            }
+            return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR :
+                PackageManager.INSTALL_SUCCEEDED;
         }
 
         @Override
@@ -4276,25 +4293,81 @@
             return cachePath + "/" + RES_FILE_NAME;
         }
 
-        void doPreInstall(int status) {
+        int doPreInstall(int status) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 // Destroy container
                 destroySdDir(cid);
+            } else {
+                // STOPSHIP Remove once new api is added in MountService
+                //boolean mounted = isContainerMounted(cid);
+                boolean mounted = false;
+                if (!mounted) {
+                    cachePath = mountSdDir(cid, Process.SYSTEM_UID);
+                    if (cachePath == null) {
+                        return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+                    }
+                }
             }
+            return status;
         }
 
         boolean doRename(int status, final String pkgName,
                 String oldCodePath) {
             String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
+            String newCachePath = null;
+            /*final int RENAME_FAILED = 1;
+            final int MOUNT_FAILED = 2;
+            final int DESTROY_FAILED = 3;
+            final int PASS = 4;
+            int errCode = RENAME_FAILED;
+            if (mounted) {
+                // Unmount the container
+                if (!unMountSdDir(cid)) {
+                    Log.i(TAG, "Failed to unmount " + cid + " before renaming");
+                    return false;
+                }
+                mounted = false;
+            }
+            if (renameSdDir(cid, newCacheId)) {
+                errCode = MOUNT_FAILED;
+                if ((newCachePath = mountSdDir(newCacheId, Process.SYSTEM_UID)) != null) {
+                    errCode = PASS;
+                }
+            }
+            String errMsg = "";
+            switch (errCode) {
+                case RENAME_FAILED:
+                    errMsg = "RENAME_FAILED";
+                    break;
+                case MOUNT_FAILED:
+                    errMsg = "MOUNT_FAILED";
+                    break;
+                case DESTROY_FAILED:
+                    errMsg = "DESTROY_FAILED";
+                    break;
+                default:
+                    errMsg = "PASS";
+                break;
+            }
+            Log.i(TAG, "Status: " + errMsg);
+            if (errCode != PASS) {
+                return false;
+            }
+            Log.i(TAG, "Succesfully renamed " + cid + " to " +newCacheId +
+                    " at path: " + cachePath + " to new path: " + newCachePath);
+            cid = newCacheId;
+            cachePath = newCachePath;
+            return true;
+            */
             // STOPSHIP TEMPORARY HACK FOR RENAME
             // Create new container at newCachePath
             String codePath = getCodePath();
-            String newCachePath = null;
             final int CREATE_FAILED = 1;
             final int COPY_FAILED = 3;
             final int FINALIZE_FAILED = 5;
             final int PASS = 7;
             int errCode = CREATE_FAILED;
+
             if ((newCachePath = createSdDir(new File(codePath), newCacheId)) != null) {
                 errCode = COPY_FAILED;
                 // Copy file from codePath
@@ -4335,13 +4408,18 @@
             return true;
         }
 
-        void doPostInstall(int status) {
+        int doPostInstall(int status) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
             } else {
-                // Unmount container
-                // Rename and remount based on package name and new uid
+                // STOP SHIP Change this once new api is added.
+                //boolean mounted = isContainerMounted(cid);
+                boolean mounted = false;
+                if (!mounted) {
+                    mountSdDir(cid, Process.SYSTEM_UID);
+                }
             }
+            return status;
         }
 
         private void cleanUp() {
@@ -4363,32 +4441,66 @@
             }
             cleanUp();
         }
+
+        boolean matchContainer(String app) {
+            if (cid.startsWith(app)) {
+                return true;
+            }
+            return false;
+        }
+
+        String getPackageName() {
+            int idx = cid.lastIndexOf("-");
+            if (idx == -1) {
+                return cid;
+            }
+            return cid.substring(0, idx);
+        }
+
+        boolean doPostDeleteLI(boolean delete) {
+            boolean ret = false;
+            boolean mounted = isContainerMounted(cid);
+            if (mounted) {
+                // Unmount first
+                ret = unMountSdDir(cid);
+            }
+            if (ret && delete) {
+                cleanUpResourcesLI();
+            }
+            return ret;
+        }
     };
 
     // Utility method used to create code paths based on package name and available index.
     private static String getNextCodePath(String oldCodePath, String prefix, String suffix) {
         String idxStr = "";
         int idx = 1;
+        // Fall back to default value of idx=1 if prefix is not
+        // part of oldCodePath
         if (oldCodePath != null) {
             String subStr = oldCodePath;
-            if (subStr.startsWith(prefix)) {
-                subStr = subStr.substring(prefix.length());
-            }
+            // Drop the suffix right away
             if (subStr.endsWith(suffix)) {
                 subStr = subStr.substring(0, subStr.length() - suffix.length());
             }
-            if (subStr != null) {
-                if (subStr.startsWith("-")) {
-                    subStr = subStr.substring(1);
-                }
-                try {
-                    idx = Integer.parseInt(subStr);
-                    if (idx <= 1) {
-                        idx++;
-                    } else {
-                        idx--;
+            // If oldCodePath already contains prefix find out the
+            // ending index to either increment or decrement.
+            int sidx = subStr.lastIndexOf(prefix);
+            if (sidx != -1) {
+                subStr = subStr.substring(sidx + prefix.length());
+                if (subStr != null) {
+                    if (subStr.startsWith("-")) {
+                        subStr = subStr.substring(1);
                     }
-                } catch(NumberFormatException e) {
+                    try {
+                        idx = Integer.parseInt(subStr);
+                        if (idx <= 1) {
+                            idx++;
+                        } else {
+                            idx--;
+                        }
+                    } catch(NumberFormatException e) {
+                    }
                 }
             }
         }
@@ -4753,6 +4865,9 @@
                 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
                         && mPackages.containsKey(pkgName)) {
                     replacingExistingPackage = true;
+                }
+                PackageSetting ps = mSettings.mPackages.get(pkgName);
+                if (ps != null) {
                     oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
                 }
             }
@@ -4761,9 +4876,8 @@
                 res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                 break main_flow;
             }
-            // TODO rename  pkg.mScanPath In scanPackageLI let it just set values based on mScanPath
-            pkg.applicationInfo.sourceDir = pkg.mScanPath= pkg.mPath = args.getCodePath();
-            pkg.applicationInfo.publicSourceDir = args.getResourcePath();
+            // Set application objects path explicitly after the rename
+            setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
             if(replacingExistingPackage) {
                 replacePackageLI(pkg, parseFlags, scanMode,
                         installerPackageName, res);
@@ -4977,9 +5091,9 @@
         }
         // Delete the resources here after sending the broadcast to let
         // other processes clean up before deleting resources.
-        synchronized (mInstallLock) {
-            if (info.args != null) {
-                info.args.cleanUpResourcesLI();
+        if (info.args != null) {
+            synchronized (mInstallLock) {
+                info.args.doPostDeleteLI(deleteCodeAndResources);
             }
         }
         return res;
@@ -6948,6 +7062,17 @@
             }
         }
 
+        private Set<String> findPackagesWithFlag(int flag) {
+            Set<String> ret = new HashSet<String>();
+            for (PackageSetting ps : mPackages.values()) {
+                // Has to match atleast all the flag bits set on flag
+                if ((ps.pkgFlags & flag) == flag) {
+                    ret.add(ps.name);
+                }
+            }
+            return ret;
+        }
+
         private void removeUserIdLP(int uid) {
             if (uid >= FIRST_APPLICATION_UID) {
                 int N = mUserIds.size();
@@ -7992,9 +8117,20 @@
        return true;
    }
 
-    private String getSdDir(String pkgName) {
-        return getMountService().getSecureContainerPath(pkgName);
-    }
+   private boolean renameSdDir(String oldId, String newId) {
+       try {
+           getMountService().renameSecureContainer(oldId, newId);
+           return true;
+       } catch (IllegalStateException e) {
+           Log.i(TAG, "Failed ot rename  " + oldId + " to " + newId +
+                   " with exception : " + e);
+       }
+       return false;
+   }
+
+   private String getSdDir(String pkgName) {
+       return getMountService().getSecureContainerPath(pkgName);
+   }
 
     private boolean finalizeSdDir(String pkgName) {
         int rc = getMountService().finalizeSecureContainer(pkgName);
@@ -8019,6 +8155,16 @@
         return list.length == 0 ? null : list;
     }
 
+   static boolean isContainerMounted(String cid) {
+       // STOPSHIP
+       // New api from MountService
+       try {
+           return (getMountService().getSecureContainerPath(cid) != null);
+       } catch (IllegalStateException e) {
+       }
+       return false;
+   }
+
    static String getTempContainerId() {
        String prefix = "smdl1tmp";
        int tmpIdx = 1;
@@ -8063,6 +8209,8 @@
    }
 
    public void updateExternalMediaStatus(final boolean mediaStatus) {
+       final boolean DEBUG = true;
+       if (DEBUG) Log.i(TAG, "updateExterMediaStatus::");
        if (mediaStatus == mMediaMounted) {
            return;
        }
@@ -8071,54 +8219,155 @@
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
-               final String list[] = getSecureContainerList();
-               if (list == null || list.length == 0) {
-                   return;
+               updateExternalMediaStatusInner(mediaStatus);
+           }
+       });
+   }
+
+   void updateExternalMediaStatusInner(boolean mediaStatus) {
+       final String list[] = getSecureContainerList();
+       if (list == null || list.length == 0) {
+           return;
+       }
+       HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+       int uidList[] = new int[list.length];
+       int num = 0;
+       for (int i = 0; i < uidList.length; i++) {
+           uidList[i] = Process.LAST_APPLICATION_UID;
+       }
+       synchronized (mPackages) {
+           Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
+           for (String cid : list) {
+               SdInstallArgs args = new SdInstallArgs(cid);
+               String removeEntry = null;
+               for (String app : appList) {
+                   if (args.matchContainer(app)) {
+                       removeEntry = app;
+                       break;
+                   }
                }
-               for (int i = 0; i < list.length; i++) {
-                   String mountPkg = list[i];
-                   // TODO compare with default package
-                   synchronized (mPackages) {
-                       PackageSetting ps = mSettings.mPackages.get(mountPkg);
-                       if (ps != null && (ps.pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) != 0) {
-                           if (mediaStatus) {
-                               String pkgPath = getSdDir(mountPkg);
-                               if (pkgPath == null) {
-                                   continue;
-                               }
-                               pkgPath = ps.codePathString;
-                               int parseFlags = PackageParser.PARSE_CHATTY |
-                               PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
-                               PackageParser pp = new PackageParser(pkgPath);
-                               pp.setSeparateProcesses(mSeparateProcesses);
-                               final PackageParser.Package pkg = pp.parsePackage(new File(pkgPath),
-                                       null, mMetrics, parseFlags);
-                               if (pkg == null) {
-                                   Log.w(TAG, "Failed to install package : " + mountPkg + " from sd card");
-                                   continue;
-                               }
-                               int scanMode = SCAN_MONITOR;
-                               // Scan the package
-                               if (scanPackageLI(pkg, parseFlags, scanMode) != null) {
-                                   // Grant permissions
-                                   grantPermissionsLP(pkg, false);
-                                   // Persist settings
-                                   mSettings.writeLP();
-                               } else {
-                                   Log.i(TAG, "Failed to install package: " + mountPkg + " from sdcard");
-                               }
-                           } else {
-                               // Delete package
-                               PackageRemovedInfo outInfo = new PackageRemovedInfo();
-                               boolean res = deletePackageLI(mountPkg, false, PackageManager.DONT_DELETE_DATA, outInfo);
-                               if (!res) {
-                                   Log.e(TAG, "Failed to delete pkg  from sdcard : " + mountPkg);
-                               }
-                           }
-                       }
+               if (removeEntry == null) {
+                   // No matching app on device. Skip entry or may be cleanup?
+                   // Ignore default package
+                   continue;
+               }
+               appList.remove(removeEntry);
+               PackageSetting ps = mSettings.mPackages.get(removeEntry);
+               processCids.put(args, ps.codePathString);
+               int uid = ps.userId;
+               if (uid != -1) {
+                   int idx = Arrays.binarySearch(uidList, uid);
+                   if (idx < 0) {
+                       uidList[-idx] = uid;
+                       num++;
                    }
                }
            }
-       });
+       }
+       int uidArr[] = uidList;
+       if ((num > 0) && (num < uidList.length)) {
+           uidArr = new int[num];
+           for (int i = 0; i < num; i++) {
+               uidArr[i] = uidList[i];
+           }
+       }
+       if (mediaStatus) {
+           loadMediaPackages(processCids, uidArr);
+       } else {
+           unloadMediaPackages(processCids, uidArr);
+       }
+   }
+
+   private void sendResourcesChangedBroadcast(boolean mediaStatus,
+           ArrayList<String> pkgList, int uidArr[]) {
+       int size = pkgList.size();
+       if (size > 0) {
+           // Send broadcasts here
+           Bundle extras = new Bundle();
+           extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+                   pkgList.toArray(new String[size]));
+           extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+           String action = mediaStatus ? Intent.ACTION_MEDIA_RESOURCES_AVAILABLE
+                   : Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE;
+           sendPackageBroadcast(action, null, extras);
+       }
+   }
+
+   void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+       ArrayList<String> pkgList = new ArrayList<String>();
+       Set<SdInstallArgs> keys = processCids.keySet();
+       for (SdInstallArgs args : keys) {
+           String cid = args.cid;
+           String codePath = processCids.get(args);
+           if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
+               Log.i(TAG, "Failed to install package: " + codePath + " from sdcard");
+               continue;
+           }
+           // Parse package
+           int parseFlags = PackageParser.PARSE_CHATTY |
+           PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+           PackageParser pp = new PackageParser(codePath);
+           pp.setSeparateProcesses(mSeparateProcesses);
+           final PackageParser.Package pkg = pp.parsePackage(new File(codePath),
+                   codePath, mMetrics, parseFlags);
+           if (pkg == null) {
+               Log.w(TAG, "Failed to install package : " + cid + " from sd card");
+               continue;
+           }
+           setApplicationInfoPaths(pkg, codePath, codePath);
+           int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+           synchronized (mInstallLock) {
+               // Scan the package
+               if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) {
+                   synchronized (mPackages) {
+                       // Grant permissions
+                       grantPermissionsLP(pkg, false);
+                       // Persist settings
+                       mSettings.writeLP();
+                       retCode = PackageManager.INSTALL_SUCCEEDED;
+                       pkgList.add(pkg.packageName);
+                   }
+               } else {
+                   Log.i(TAG, "Failed to install package: " + pkg.packageName + " from sdcard");
+               }
+           }
+           args.doPostInstall(retCode);
+           pkgList.add(pkg.packageName);
+       }
+       // Send broadcasts first
+       sendResourcesChangedBroadcast(true, pkgList, uidArr);
+       Runtime.getRuntime().gc();
+       // If something failed do we clean up here or next install?
+   }
+
+   void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+       ArrayList<String> pkgList = new ArrayList<String>();
+       Set<SdInstallArgs> keys = processCids.keySet();
+       for (SdInstallArgs args : keys) {
+           String cid = args.cid;
+           String pkgName = args.getPackageName();
+           // STOPSHIP Send broadcast to apps to remove references
+           // STOPSHIP Unmount package
+           // Delete package internally
+           PackageRemovedInfo outInfo = new PackageRemovedInfo();
+           synchronized (mInstallLock) {
+               boolean res = deletePackageLI(pkgName, false,
+                       PackageManager.DONT_DELETE_DATA, outInfo);
+               if (res) {
+                   pkgList.add(pkgName);
+               } else {
+                   Log.e(TAG, "Failed to delete pkg  from sdcard : " + pkgName);
+               }
+           }
+       }
+       // Send broadcasts
+       sendResourcesChangedBroadcast(false, pkgList, uidArr);
+       Runtime.getRuntime().gc();
+       // Do clean up. Just unmount
+       for (SdInstallArgs args : keys) {
+           synchronized (mInstallLock) {
+               args.doPostDeleteLI(false);
+           }
+       }
    }
 }
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,
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 2d0f254..7b722a5 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -1807,16 +1807,30 @@
             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
             filter.addDataScheme("package");
             mContext.registerReceiver(this, filter);
+            IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+            mContext.registerReceiver(this, sdFilter);
         }
         
         @Override
         public void onReceive(Context context, Intent intent) {
-            ArrayList<StatusBarNotification> list = null;
-            synchronized (StatusBarService.this) {
+            String pkgList[] = null;
+            if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) {
+                pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            } else {
                 Uri data = intent.getData();
                 if (data != null) {
                     String pkg = data.getSchemeSpecificPart();
-                    list = mNotificationData.notificationsForPackage(pkg);
+                    if (pkg != null) {
+                        pkgList = new String[]{pkg};
+                    }
+                }
+            }
+            ArrayList<StatusBarNotification> list = null;
+            if (pkgList != null) {
+                synchronized (StatusBarService.this) {
+                    for (String pkg : pkgList) {
+                        list = mNotificationData.notificationsForPackage(pkg);
+                    }
                 }
             }