Rename media resource broadcasts
Add checks for fwdlocked and updated system apps
add more tests
remove duplicate adds
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index b56b13b..407983d 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -176,8 +176,8 @@
         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);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(broadcastReceiver, sdFilter);
 
         // boot completed
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index c28cf44..44cc0bb 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -782,7 +782,7 @@
             mContext.registerReceiver(this, filter);
              // Register for events related to sdcard installation.
             IntentFilter sdFilter = new IntentFilter();
-            sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
             mContext.registerReceiver(this, sdFilter);
         }
         
@@ -791,7 +791,7 @@
             synchronized (mLock) {
                 String action = intent.getAction();
                 String pkgList[] = null;
-                if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                 } else {
                     Uri data = intent.getData();
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 684f117..f336d1f 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -147,8 +147,8 @@
         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);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
     }
 
@@ -1077,10 +1077,10 @@
             } else {
                 boolean added = false;
                 String pkgList[] = null;
-                if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) {
+                if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                     added = true;
-                } if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+                } if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                     added = false;
                 } else  {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2f845e1..24187a5 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -565,8 +565,8 @@
         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);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
     }
 
@@ -724,10 +724,10 @@
                 }
                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
                 replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
-            } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) {
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
                 added = true;
                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-            } else if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                 added = false;
                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index dc942a2..5e96a2f 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -344,8 +344,8 @@
                 if (pkg != null) {
                     pkgList = new String[] { pkg };
                 }
-            } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) ||
-                    Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) {
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) ||
+                    Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
             if (pkgList == null || pkgList.length == 0) {
@@ -448,8 +448,8 @@
         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);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
 
         IntentFilter screenOnOffFilt = new IntentFilter();
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 3a42b37..990a77a 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -484,7 +484,7 @@
         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);
+        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
 
         // listen for settings changes
@@ -1552,10 +1552,10 @@
 
             if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
-                    || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                 synchronized (mLock) {
                     int uidList[] = null;
-                    if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                    if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
                     } else {
                         uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6382646..51abfc3 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -670,7 +670,6 @@
      */
     public int mountVolume(String path) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-
         int rc = MountServiceResultCode.OperationSucceeded;
 
         try {
@@ -721,10 +720,21 @@
     public int unmountVolume(String path) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
 
+        // Check if media has been mounted
+        String oldState = mLegacyState;
+        if (!oldState.equals(Environment.MEDIA_MOUNTED)) {
+            return VoldResponseCode.OpFailedVolNotMounted;
+        }
+        // Notify PackageManager of potential media removal and deal with
+        // return code later on. The caller of this api should be aware or have been
+        // notified that the applications installed on the media will be killed.
+        mPms.updateExternalMediaStatus(false);
         try {
             mConnector.doCommand(String.format("volume unmount %s", path));
             return MountServiceResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
+            // Don't worry about mismatch in PackageManager since the
+            // call back will handle the status changes any way.
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedVolNotMounted) {
                 return MountServiceResultCode.OperationFailedVolumeNotMounted;
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 02a0401..d989b6b 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -330,9 +330,9 @@
                 updateAdbNotification();
             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
-                    || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                 String pkgList[] = null;
-                if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) {
+                if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                 } else {
                     Uri uri = intent.getData();
@@ -440,7 +440,7 @@
         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);
+        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mIntentReceiver, sdFilter);
 
         SettingsObserver observer = new SettingsObserver(mHandler);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 387f139..f7e3cea 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4959,69 +4959,82 @@
         File tmpPackageFile = new File(args.getCodePath());
         boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
         boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0);
-        boolean replacingExistingPackage = false;
+        boolean replace = false;
         int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
                 | (newInstall ? SCAN_NEW_INSTALL : 0);
         // Result object to be returned
         res.returnCode = PackageManager.INSTALL_SUCCEEDED;
 
-        main_flow: try {
-            // Retrieve PackageSettings and parse package
-            int parseFlags = PackageParser.PARSE_CHATTY |
-                    (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
-                    (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
-            parseFlags |= mDefParseFlags;
-            PackageParser pp = new PackageParser(tmpPackageFile.getPath());
-            pp.setSeparateProcesses(mSeparateProcesses);
-            final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
-                    null, mMetrics, parseFlags);
-            if (pkg == null) {
-                res.returnCode = pp.getParseError();
-                break main_flow;
+        // Retrieve PackageSettings and parse package
+        int parseFlags = PackageParser.PARSE_CHATTY |
+        (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+        (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
+        parseFlags |= mDefParseFlags;
+        PackageParser pp = new PackageParser(tmpPackageFile.getPath());
+        pp.setSeparateProcesses(mSeparateProcesses);
+        final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
+                null, mMetrics, parseFlags);
+        if (pkg == null) {
+            res.returnCode = pp.getParseError();
+            return;
+        }
+        String pkgName = res.name = pkg.packageName;
+        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+            if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
+                res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
+                return;
             }
-            String pkgName = res.name = pkg.packageName;
-            if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
-                if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
-                    res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
-                    break main_flow;
+        }
+        if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
+            res.returnCode = pp.getParseError();
+            return;
+        }
+        // Some preinstall checks
+        if (forwardLocked && onSd) {
+            // Make sure forward locked apps can only be installed
+            // on internal storage
+            Log.w(TAG, "Cannot install protected apps on sdcard");
+            res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+            return;
+        }
+        // Get rid of all references to package scan path via parser.
+        pp = null;
+        String oldCodePath = null;
+        boolean systemApp = false;
+        synchronized (mPackages) {
+            // Check if installing already existing package
+            if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
+                    && mPackages.containsKey(pkgName)) {
+                replace = true;
+            }
+            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            if (ps != null) {
+                oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
+                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
+                    systemApp = (ps.pkg.applicationInfo.flags &
+                            ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
             }
-            if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
-                res.returnCode = pp.getParseError();
-                break main_flow;
-            }
+        }
 
-            // Get rid of all references to package scan path via parser.
-            pp = null;
-            String oldCodePath = null;
-            synchronized (mPackages) {
-                //check if installing already existing package
-                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;
-                }
-            }
-
-            if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
-                res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                break main_flow;
-            }
-            // Set application objects path explicitly after the rename
-            setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
-            if(replacingExistingPackage) {
-                replacePackageLI(pkg, parseFlags, scanMode,
-                        installerPackageName, res);
-            } else {
-                installNewPackageLI(pkg, parseFlags, scanMode,
-                        installerPackageName,res);
-            }
-        } finally {
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-            }
+        if (systemApp && onSd) {
+            // Disable updates to system apps on sdcard
+            Log.w(TAG, "Cannot install updates to system apps on sdcard");
+            res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+            return;
+        }
+        if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
+            res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            return;
+        }
+        // Set application objects path explicitly after the rename
+        setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+        if(replace) {
+            replacePackageLI(pkg, parseFlags, scanMode,
+                    installerPackageName, res);
+        } else {
+            installNewPackageLI(pkg, parseFlags, scanMode,
+                    installerPackageName,res);
         }
     }
 
@@ -8409,8 +8422,8 @@
    }
 
    public void updateExternalMediaStatus(final boolean mediaStatus) {
-       final boolean DEBUG = true;
-       if (DEBUG) Log.i(TAG, "updateExterMediaStatus::");
+       if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
+               mediaStatus+", mMediaMounted=" + mMediaMounted);
        if (mediaStatus == mMediaMounted) {
            return;
        }
@@ -8432,9 +8445,6 @@
        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) {
@@ -8456,24 +8466,34 @@
                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++;
-                   }
+                   uidList[num++] = uid;
                }
            }
        }
-       int uidArr[] = uidList;
-       if ((num > 0) && (num < uidList.length)) {
+       int uidArr[] = null;
+       if (num > 0) {
+           // Sort uid list
+           Arrays.sort(uidList, 0, num);
+           // Throw away duplicates
            uidArr = new int[num];
-           for (int i = 0; i < num; i++) {
-               uidArr[i] = uidList[i];
+           uidArr[0] = uidList[0];
+           int di = 0;
+           for (int i = 1; i < num; i++) {
+               if (uidList[i-1] != uidList[i]) {
+                   uidArr[di++] = uidList[i];
+               }
+           }
+           if (true) {
+               for (int j = 0; j < num; j++) {
+                   Log.i(TAG, "uidArr[" + j + "]=" + uidArr[j]);
+               }
            }
        }
        if (mediaStatus) {
+           if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
            loadMediaPackages(processCids, uidArr);
        } else {
+           if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
            unloadMediaPackages(processCids, uidArr);
        }
    }
@@ -8486,9 +8506,11 @@
            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;
+           if (uidArr != null) {
+               extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
+           }
+           String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+                   : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
            sendPackageBroadcast(action, null, extras);
        }
    }
@@ -8497,10 +8519,11 @@
        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 (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install pkg : "
+                   + args.cid + " from " + args.cachePath);
            if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
-               Log.i(TAG, "Failed to install package: " + codePath + " from sdcard");
+               Log.e(TAG, "Failed to install package: " + codePath + " from sdcard");
                continue;
            }
            // Parse package
@@ -8511,7 +8534,8 @@
            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");
+               Log.e(TAG, "Trying to install pkg : "
+                       + args.cid + " from " + args.cachePath);
                continue;
            }
            setApplicationInfoPaths(pkg, codePath, codePath);
@@ -8532,22 +8556,24 @@
                }
            }
            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?
+       if (pkgList.size() > 0) {
+           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[]) {
+       if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
        ArrayList<String> pkgList = new ArrayList<String>();
+       ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
        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
+           if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName);
            // Delete package internally
            PackageRemovedInfo outInfo = new PackageRemovedInfo();
            synchronized (mInstallLock) {
@@ -8557,14 +8583,17 @@
                    pkgList.add(pkgName);
                } else {
                    Log.e(TAG, "Failed to delete pkg  from sdcard : " + pkgName);
+                   failedList.add(args);
                }
            }
        }
        // Send broadcasts
-       sendResourcesChangedBroadcast(false, pkgList, uidArr);
-       Runtime.getRuntime().gc();
+       if (pkgList.size() > 0) {
+           sendResourcesChangedBroadcast(false, pkgList, uidArr);
+           Runtime.getRuntime().gc();
+       }
        // Do clean up. Just unmount
-       for (SdInstallArgs args : keys) {
+       for (SdInstallArgs args : failedList) {
            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 5e6881c..98ded37 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -11941,7 +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())
+                || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
                 || uidRemoved) {
             if (checkComponentPermission(
                     android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
@@ -11960,7 +11960,7 @@
                 } else {
                     // 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())) {
+                    if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
                         String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                         if (list != null && (list.length > 0)) {
                             for (String pkg : list) {
@@ -12146,7 +12146,7 @@
                         skipPackages = new String[] { pkgName };
                     }
                 }
-            } else if (intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(intent.getAction())) {
+            } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
                 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             }
             if (skipPackages != null && (skipPackages.length > 0)) {
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 55041fb..c7c3335 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -1813,14 +1813,14 @@
             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
             filter.addDataScheme("package");
             mContext.registerReceiver(this, filter);
-            IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE);
+            IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
             mContext.registerReceiver(this, sdFilter);
         }
         
         @Override
         public void onReceive(Context context, Intent intent) {
             String pkgList[] = null;
-            if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) {
+            if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             } else {
                 Uri data = intent.getData();