Framework: Clean up / Refactor Mount APIs

 - Move android.storage.* -> android.os.storage.* and refactor users
 - Refactor generic shares back to explicit ums enable/disable/isEnabled
 - Remove media insert/removed event callbacks (not ready for Froyo)
 - Remove 'label' from volume state change callbacks
 - Add public API functions for enabling/disabling USB mass storage (permissions enforced
   in MountSevice)
 - Remove some stray un-needed import lines
 - Move android.os.IMountService / android.os.IMountServiceListener -> android.os.storage
 - Improve code comments

Updated:
  MountService: Add dup state check and move debugging behind a conditional
  UsbStorageActivity: Fix review comments + a TODO
  StorageNotification: Add @Override tags
  StorageManager: Don't use a static Listener list
  MountService: Reduce bloat and fix == where I meant .equals()
  PackageManagerTests: Update for new API

Signed-off-by: San Mehat <san@google.com>
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 0e44858..6de2eff 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -23,9 +23,9 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.net.Uri;
-import android.os.IMountService;
-import android.os.IMountServiceListener;
-import android.os.MountServiceResultCode;
+import android.os.storage.IMountService;
+import android.os.storage.IMountServiceListener;
+import android.os.storage.StorageResultCode;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Environment;
@@ -42,11 +42,14 @@
 import java.io.FileReader;
 
 /**
- * MountService implements an to the mount service daemon
- * @hide
+ * MountService implements back-end services for platform storage
+ * management.
+ * @hide - Applications should use android.os.storage.StorageManager
+ * to access the MountService.
  */
 class MountService extends IMountService.Stub
         implements INativeDaemonConnectorCallbacks {
+    private static final boolean LOCAL_LOGD = false;
     
     private static final String TAG = "MountService";
 
@@ -135,7 +138,7 @@
                 String path = Environment.getExternalStorageDirectory().getPath();
                 if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) {
                     int rc = doMountVolume(path);
-                    if (rc != MountServiceResultCode.OperationSucceeded) {
+                    if (rc != StorageResultCode.OperationSucceeded) {
                         Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
                     }
                 }
@@ -152,7 +155,7 @@
         }
 
         public void binderDied() {
-            Log.d(TAG, "An IMountServiceListener has died!");
+            if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!");
             synchronized(mListeners) {
                 mListeners.remove(this);
                 mListener.asBinder().unlinkToDeath(this, 0);
@@ -173,9 +176,9 @@
          */
         String vs = getVolumeState(path);
         if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
-            mUmsEnabling = enable; // Supress unmounted events
+            mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
             doUnmountVolume(path);
-            mUmsEnabling = false; // Unsupress unmounted events
+            mUmsEnabling = false; // Clear override
         }
 
         try {
@@ -183,14 +186,14 @@
                     "volume %sshare %s %s", (enable ? "" : "un"), path, method));
         } catch (NativeDaemonConnectorException e) {
             Log.e(TAG, "Failed to share/unshare", e);
-            return MountServiceResultCode.OperationFailedInternalError;
+            return StorageResultCode.OperationFailedInternalError;
         }
 
         /*
          * If we disabled UMS then mount the volume
          */
         if (!enable) {
-            if (doMountVolume(path) != MountServiceResultCode.OperationSucceeded) {
+            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format(
                         "Failed to remount %s after disabling share method %s", path, method));
                 /*
@@ -201,7 +204,7 @@
             }
         }
 
-        return MountServiceResultCode.OperationSucceeded;
+        return StorageResultCode.OperationSucceeded;
     }
 
     private void updatePublicVolumeState(String path, String state) {
@@ -209,7 +212,11 @@
             Log.w(TAG, "Multiple volumes not currently supported");
             return;
         }
-        Log.i(TAG, "State for {" + path + "} = {" + state + "}");
+
+        if (mLegacyState.equals(state)) {
+            Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
+            return;
+        }
 
         String oldState = mLegacyState;
         mLegacyState = state;
@@ -218,7 +225,7 @@
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
                 try {
-                    bl.mListener.onVolumeStateChanged("", path, oldState, state);
+                    bl.mListener.onStorageStateChanged(path, oldState, state);
                 } catch (RemoteException rex) {
                     Log.e(TAG, "Listener dead");
                     mListeners.remove(i);
@@ -296,13 +303,11 @@
     }
 
     /**
-     *
      * Callback from NativeDaemonConnector
      */
     public boolean onEvent(int code, String raw, String[] cooked) {
         Intent in = null;
 
-        // Log.d(TAG, "event {" + raw + "}");
         if (code == VoldResponseCode.VolumeStateChange) {
             /*
              * One of the volumes we're managing has changed state.
@@ -339,34 +344,12 @@
                 Log.e(TAG, "Failed to parse major/minor", ex);
             }
 
-            synchronized (mListeners) {
-                for (int i = mListeners.size() -1; i >= 0; i--) {
-                    MountServiceBinderListener bl = mListeners.get(i);
-                    try {
-                        if (code == VoldResponseCode.VolumeDiskInserted) {
-                            bl.mListener.onMediaInserted(label, path, major, minor);
-                        } else if (code == VoldResponseCode.VolumeDiskRemoved) {
-                            bl.mListener.onMediaRemoved(label, path, major, minor, true);
-                        } else if (code == VoldResponseCode.VolumeBadRemoval) {
-                            bl.mListener.onMediaRemoved(label, path, major, minor, false);
-                        } else {
-                            Log.e(TAG, String.format("Unknown code {%d}", code));
-                        }
-                    } catch (RemoteException rex) {
-                        Log.e(TAG, "Listener dead");
-                        mListeners.remove(i);
-                    } catch (Exception ex) {
-                        Log.e(TAG, "Listener failed", ex);
-                    }
-                }
-            }
-
             if (code == VoldResponseCode.VolumeDiskInserted) {
                 new Thread() {
                     public void run() {
                         try {
                             int rc;
-                            if ((rc = doMountVolume(path)) != MountServiceResultCode.OperationSucceeded) {
+                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
                                 Log.w(TAG, String.format("Insertion mount failed (%d)", rc));
                             }
                         } catch (Exception ex) {
@@ -489,7 +472,7 @@
     }
 
     private int doMountVolume(String path) {
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
 
         try {
             mConnector.doCommand(String.format("volume mount %s", path));
@@ -503,23 +486,23 @@
                 /*
                  * Attempt to mount but no media inserted
                  */
-                rc = MountServiceResultCode.OperationFailedNoMedia;
+                rc = StorageResultCode.OperationFailedNoMedia;
             } else if (code == VoldResponseCode.OpFailedMediaBlank) {
                 /*
                  * Media is blank or does not contain a supported filesystem
                  */
                 updatePublicVolumeState(path, Environment.MEDIA_NOFS);
                 in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
-                rc = MountServiceResultCode.OperationFailedMediaBlank;
+                rc = StorageResultCode.OperationFailedMediaBlank;
             } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
                 /*
                  * Volume consistency check failed
                  */
                 updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
                 in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
-                rc = MountServiceResultCode.OperationFailedMediaCorrupt;
+                rc = StorageResultCode.OperationFailedMediaCorrupt;
             } else {
-                rc = MountServiceResultCode.OperationFailedInternalError;
+                rc = StorageResultCode.OperationFailedInternalError;
             }
 
             /*
@@ -544,15 +527,15 @@
         mPms.updateExternalMediaStatus(false);
         try {
             mConnector.doCommand(String.format("volume unmount %s", path));
-            return MountServiceResultCode.OperationSucceeded;
+            return StorageResultCode.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;
+                return StorageResultCode.OperationFailedVolumeNotMounted;
             } else {
-                return MountServiceResultCode.OperationFailedInternalError;
+                return StorageResultCode.OperationFailedInternalError;
             }
         }
     }
@@ -561,19 +544,45 @@
         try {
             String cmd = String.format("volume format %s", path);
             mConnector.doCommand(cmd);
-            return MountServiceResultCode.OperationSucceeded;
+            return StorageResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedNoMedia) {
-                return MountServiceResultCode.OperationFailedNoMedia;
+                return StorageResultCode.OperationFailedNoMedia;
             } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
-                return MountServiceResultCode.OperationFailedMediaCorrupt;
+                return StorageResultCode.OperationFailedMediaCorrupt;
             } else {
-                return MountServiceResultCode.OperationFailedInternalError;
+                return StorageResultCode.OperationFailedInternalError;
             }
         }
     }
 
+    private boolean doGetVolumeShared(String path, String method) {
+        String cmd = String.format("volume shared %s %s", path, method);
+        ArrayList<String> rsp = mConnector.doCommand(cmd);
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code;
+            try {
+                code = Integer.parseInt(tok[0]);
+            } catch (NumberFormatException nfe) {
+                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
+                return false;
+            }
+            if (code == VoldResponseCode.ShareEnabledResult) {
+                if (tok[2].equals("enabled"))
+                    return true;
+                return false;
+            } else {
+                Log.e(TAG, String.format("Unexpected response code %d", code));
+                return false;
+            }
+        }
+        Log.e(TAG, "Got an empty response");
+        return false;
+    }
+
     private void notifyShareAvailabilityChange(String method, final boolean avail) {
         if (!method.equals("ums")) {
            Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
@@ -584,7 +593,7 @@
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
                 try {
-                    bl.mListener.onShareAvailabilityChanged(method, avail);
+                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
                 } catch (RemoteException rex) {
                     Log.e(TAG, "Listener dead");
                     mListeners.remove(i);
@@ -685,7 +694,7 @@
              * the UMS host could have dirty FAT cache entries
              * yet to flush.
              */
-            if (unshareVolume(path, "ums") != MountServiceResultCode.OperationSucceeded) {
+            if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, "UMS disable on shutdown failed");
             }
         } else if (state.equals(Environment.MEDIA_CHECKING)) {
@@ -713,58 +722,30 @@
             /*
              * If the media is mounted, then gracefully unmount it.
              */
-            if (doUnmountVolume(path) != MountServiceResultCode.OperationSucceeded) {
+            if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, "Failed to unmount media for shutdown");
             }
         }
     }
 
-    public String[] getShareMethodList() {
-        String[] rdata = new String[1];
-        rdata[0] = "ums";
-        return rdata;
-    }
-
-    public boolean getShareMethodAvailable(String method) {
+    public boolean isUsbMassStorageConnected() {
         waitForReady();
-        return doGetShareMethodAvailable(method);
-    }
 
-    public int shareVolume(String path, String method) {
-        waitForReady();
-        return doShareUnshareVolume(path, method, true);
-    }
-
-    public int unshareVolume(String path, String method) {
-        waitForReady();
-        return doShareUnshareVolume(path, method, false);
-    }
-
-    public boolean getVolumeShared(String path, String method) {
-        waitForReady();
-        String cmd = String.format("volume shared %s %s", path, method);
-        ArrayList<String> rsp = mConnector.doCommand(cmd);
-
-        for (String line : rsp) {
-            String []tok = line.split(" ");
-            int code;
-            try {
-                code = Integer.parseInt(tok[0]);
-            } catch (NumberFormatException nfe) {
-                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
-                return false;
-            }
-            if (code == VoldResponseCode.ShareEnabledResult) {
-                if (tok[2].equals("enabled"))
-                    return true;
-                return false;
-            } else {
-                Log.e(TAG, String.format("Unexpected response code %d", code));
-                return false;
-            }
+        if (mUmsEnabling) {
+            return true;
         }
-        Log.e(TAG, "Got an empty response");
-        return false;
+        return doGetShareMethodAvailable("ums");
+    }
+
+    public int setUsbMassStorageEnabled(boolean enable) {
+        waitForReady();
+
+        return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable);
+    }
+
+    public boolean isUsbMassStorageEnabled() {
+        waitForReady();
+        return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
     }
     
     /**
@@ -804,12 +785,16 @@
         return doFormatVolume(path);
     }
 
+    private void warnOnNotMounted() {
+        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            Log.w(TAG, "getSecureContainerList() called when storage not mounted");
+        }
+    }
+
     public String[] getSecureContainerList() {
         validatePermission(android.Manifest.permission.ASEC_ACCESS);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "getSecureContainerList() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
         try {
             return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
@@ -822,31 +807,27 @@
                                     String key, int ownerUid) {
         validatePermission(android.Manifest.permission.ASEC_CREATE);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "createSecureContainer() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
 
     public int finalizeSecureContainer(String id) {
         validatePermission(android.Manifest.permission.ASEC_CREATE);
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "finalizeSecureContainer() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         try {
             mConnector.doCommand(String.format("asec finalize %s", id));
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
@@ -854,15 +835,13 @@
     public int destroySecureContainer(String id) {
         validatePermission(android.Manifest.permission.ASEC_DESTROY);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "destroySecureContainer() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         try {
             mConnector.doCommand(String.format("asec destroy %s", id));
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
@@ -870,16 +849,14 @@
     public int mountSecureContainer(String id, String key, int ownerUid) {
         validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "mountSecureContainer() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
@@ -887,16 +864,14 @@
     public int unmountSecureContainer(String id) {
         validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "unmountSecureContainer() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec unmount %s", id);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
@@ -904,16 +879,14 @@
     public int renameSecureContainer(String oldId, String newId) {
         validatePermission(android.Manifest.permission.ASEC_RENAME);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "renameSecureContainer() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec rename %s %s", oldId, newId);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
@@ -921,9 +894,7 @@
     public String getSecureContainerPath(String id) {
         validatePermission(android.Manifest.permission.ASEC_ACCESS);
         waitForReady();
-        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
-            Log.w(TAG, "getSecureContainerPath() called when storage not mounted");
-        }
+        warnOnNotMounted();
 
         ArrayList<String> rsp = mConnector.doCommand("asec path " + id);