Add new activity manager method to get list of running applications installed on sdcard.
Use new method in UsbStorageActivity.
Fix moving dex files.
moveDex should be suffixed with LI since it uses Installer

Change-Id: Id5ef0254578e84b9aae2c2ac44f722eb5a0fda1c
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e8ab51fd..b3223e5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
 import android.graphics.Bitmap;
@@ -859,6 +860,22 @@
     }
     
     /**
+     * Returns a list of application processes installed on external media
+     * that are running on the device.
+     *
+     * @return Returns a list of ApplicationInfo records, or null if none
+     * This list ordering is not specified.
+     * @hide
+     */
+    public List<ApplicationInfo> getRunningExternalApplications() {
+        try {
+            return ActivityManagerNative.getDefault().getRunningExternalApplications();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns a list of application processes that are running on the device.
      * 
      * @return Returns a list of RunningAppProcessInfo records, or null if there are no
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index adadfeb..f694285 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -491,6 +491,14 @@
             return true;
         }
 
+        case GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            List<ApplicationInfo> list = getRunningExternalApplications();
+            reply.writeNoException();
+            reply.writeTypedList(list);
+            return true;
+        }
+
         case MOVE_TASK_TO_FRONT_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int task = data.readInt();
@@ -1716,6 +1724,19 @@
         reply.recycle();
         return list;
     }
+    public List<ApplicationInfo> getRunningExternalApplications()
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION, data, reply, 0);
+        reply.readException();
+        ArrayList<ApplicationInfo> list
+        = reply.createTypedArrayList(ApplicationInfo.CREATOR);
+        data.recycle();
+        reply.recycle();
+        return list;
+    }
     public void moveTaskToFront(int task) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ea0e952..31f0a63 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -262,9 +262,13 @@
      * SIGUSR1 is delivered. All others are ignored.
      */
     public void signalPersistentProcesses(int signal) throws RemoteException;
-    // Retrieve running application processes in the system
+    // Retrieve info of applications installed on external media that are currently
+    // running.
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
             throws RemoteException;
+ // Retrieve running application processes in the system
+    public List<ApplicationInfo> getRunningExternalApplications()
+            throws RemoteException;
     // Get device configuration
     public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException;
     
@@ -508,4 +512,5 @@
     int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
     int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
     int START_ACTIVITY_WITH_CONFIG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+106;
+    int GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+107;
 }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 53415c7..4d7b393 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5258,7 +5258,7 @@
             String sourceFile = getCodePath();
             // Remove dex file
             if (mInstaller != null) {
-                int retCode = mInstaller.rmdex(sourceFile.toString());
+                int retCode = mInstaller.rmdex(sourceFile);
                 if (retCode < 0) {
                     Slog.w(TAG, "Couldn't remove dex file for package: "
                             + " at location "
@@ -5613,7 +5613,7 @@
     }
 
     // Utility method used to move dex files during install.
-    private int moveDexFiles(PackageParser.Package newPackage) {
+    private int moveDexFilesLI(PackageParser.Package newPackage) {
         int retCode;
         if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
@@ -5636,7 +5636,7 @@
             mSettings.writeLP();
         }
 
-        if ((res.returnCode = moveDexFiles(newPackage))
+        if ((res.returnCode = moveDexFilesLI(newPackage))
                 != PackageManager.INSTALL_SUCCEEDED) {
             // Discontinue if moving dex files failed.
             return;
@@ -9697,41 +9697,43 @@
                    sendResourcesChangedBroadcast(false, pkgList, uidArr);
 
                    // Update package code and resource paths
-                   synchronized (mPackages) {
-                       PackageParser.Package pkg = mPackages.get(mp.packageName);
-                       if (pkg != null) {
-                           String oldCodePath = pkg.mPath;
-                           String newCodePath = mp.targetArgs.getCodePath();
-                           String newResPath = mp.targetArgs.getResourcePath();
-                           pkg.mPath = newCodePath;
-                           // Move dex files around
-                           if (moveDexFiles(pkg)
-                                   != PackageManager.INSTALL_SUCCEEDED) {
-                               // Moving of dex files failed. Set
-                               // error code and abort move.
-                               pkg.mPath = pkg.mScanPath;
-                               returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
-                               moveSucceeded = false;
-                           } else {
-                               pkg.mScanPath = newCodePath;
-                               pkg.applicationInfo.sourceDir = newCodePath;
-                               pkg.applicationInfo.publicSourceDir = newResPath;
-                               PackageSetting ps = (PackageSetting) pkg.mExtras;
-                               ps.codePath = new File(pkg.applicationInfo.sourceDir);
-                               ps.codePathString = ps.codePath.getPath();
-                               ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
-                               ps.resourcePathString = ps.resourcePath.getPath();
-                               // Set the application info flag correctly.
-                               if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
-                                   pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+                   synchronized (mInstallLock) {
+                       synchronized (mPackages) {
+                           PackageParser.Package pkg = mPackages.get(mp.packageName);
+                           if (pkg != null) {
+                               String oldCodePath = pkg.mPath;
+                               String newCodePath = mp.targetArgs.getCodePath();
+                               String newResPath = mp.targetArgs.getResourcePath();
+                               pkg.mPath = newCodePath;
+                               // Move dex files around
+                               if (moveDexFilesLI(pkg)
+                                       != PackageManager.INSTALL_SUCCEEDED) {
+                                   // Moving of dex files failed. Set
+                                   // error code and abort move.
+                                   pkg.mPath = pkg.mScanPath;
+                                   returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+                                   moveSucceeded = false;
                                } else {
-                                   pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+                                   pkg.mScanPath = newCodePath;
+                                   pkg.applicationInfo.sourceDir = newCodePath;
+                                   pkg.applicationInfo.publicSourceDir = newResPath;
+                                   PackageSetting ps = (PackageSetting) pkg.mExtras;
+                                   ps.codePath = new File(pkg.applicationInfo.sourceDir);
+                                   ps.codePathString = ps.codePath.getPath();
+                                   ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
+                                   ps.resourcePathString = ps.resourcePath.getPath();
+                                   // Set the application info flag correctly.
+                                   if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+                                       pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+                                   } else {
+                                       pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+                                   }
+                                   ps.setFlags(pkg.applicationInfo.flags);
+                                   mAppDirs.remove(oldCodePath);
+                                   mAppDirs.put(newCodePath, pkg);
+                                   // Persist settings
+                                   mSettings.writeLP();
                                }
-                               ps.setFlags(pkg.applicationInfo.flags);
-                               mAppDirs.remove(oldCodePath);
-                               mAppDirs.put(newCodePath, pkg);
-                               // Persist settings
-                               mSettings.writeLP();
                            }
                        }
                    }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f734053..d1edc35 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -69,6 +69,7 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -122,6 +123,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 
 public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
     static final String TAG = "ActivityManager";
@@ -9352,6 +9354,32 @@
         return runList;
     }
 
+    public List<ApplicationInfo> getRunningExternalApplications() {
+        List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
+        List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
+        if (runningApps != null && runningApps.size() > 0) {
+            Set<String> extList = new HashSet<String>();
+            for (ActivityManager.RunningAppProcessInfo app : runningApps) {
+                if (app.pkgList != null) {
+                    for (String pkg : app.pkgList) {
+                        extList.add(pkg);
+                    }
+                }
+            }
+            IPackageManager pm = ActivityThread.getPackageManager();
+            for (String pkg : extList) {
+                try {
+                    ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
+                    if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+                        retList.add(info);
+                    }
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        return retList;
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (checkCallingPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java
index b3ee257..e8631c5 100644
--- a/services/java/com/android/server/status/UsbStorageActivity.java
+++ b/services/java/com/android/server/status/UsbStorageActivity.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
@@ -26,6 +27,9 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -43,6 +47,8 @@
 import android.view.Window;
 import android.util.Log;
 
+import java.util.List;
+
 /**
  * This activity is shown to the user for him/her to enable USB mass storage
  * on-demand (that is, when the USB cable is connected). It uses the alert
@@ -175,7 +181,7 @@
                     .setTitle(R.string.dlg_confirm_kill_storage_users_title)
                     .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
-                            mStorageManager.enableUsbMassStorage();
+                            switchUsbMassStorageAsync(true);
                         }})
                     .setNegativeButton(R.string.cancel, null)
                     .setMessage(R.string.dlg_confirm_kill_storage_users_text)
@@ -222,15 +228,25 @@
             // Display error dialog
             showDialogInner(DLG_ERROR_SHARING);
         }
-        String path = Environment.getExternalStorageDirectory().getPath();
-        int stUsers[] = null;
+        String extStoragePath = Environment.getExternalStorageDirectory().toString();
+        boolean showDialog = false;
         try {
-            if (localLOGV) Log.i(TAG, "Checking getStorageUsers");
-            stUsers = ims.getStorageUsers(path);
+            int[] stUsers = ims.getStorageUsers(extStoragePath);
+            if (stUsers != null && stUsers.length > 0) {
+                showDialog = true;
+            } else {
+                // List of applications on sdcard.
+                ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+                List<ApplicationInfo> infoList = am.getRunningExternalApplications();
+                if (infoList != null && infoList.size() > 0) {
+                    showDialog = true;
+                }
+            }
         } catch (RemoteException e) {
+            // Display error dialog
             showDialogInner(DLG_ERROR_SHARING);
         }
-        if (stUsers != null && stUsers.length > 0) {
+        if (showDialog) {
             // Display dialog to user
             showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS);
         } else {