Merge "Properly advertise the content length of the HTTP stream if available."
diff --git a/Android.mk b/Android.mk
index f225ecd8..682f286 100644
--- a/Android.mk
+++ b/Android.mk
@@ -112,7 +112,7 @@
 	core/java/android/os/ICheckinService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/IMountService.aidl \
-	core/java/android/os/IMountServiceObserver.aidl \
+	core/java/android/os/IMountServiceListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/INetStatService.aidl \
 	core/java/android/os/IParentalControlCallback.aidl \
diff --git a/api/8.xml b/api/8.xml
index d5e5fc9..a07537c 100644
--- a/api/8.xml
+++ b/api/8.xml
@@ -173386,573 +173386,6 @@
 </parameter>
 </method>
 </class>
-<class name="CallbackProxy"
- extends="android.os.Handler"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility=""
->
-<constructor name="CallbackProxy"
- type="android.webkit.CallbackProxy"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="w" type="android.webkit.WebView">
-</parameter>
-</constructor>
-<method name="addMessageToConsole"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="message" type="java.lang.String">
-</parameter>
-<parameter name="lineNumber" type="int">
-</parameter>
-<parameter name="sourceID" type="java.lang.String">
-</parameter>
-</method>
-<method name="createWindow"
- return="android.webkit.WebView"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dialog" type="boolean">
-</parameter>
-<parameter name="userGesture" type="boolean">
-</parameter>
-</method>
-<method name="doUpdateVisitedHistory"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="isReload" type="boolean">
-</parameter>
-</method>
-<method name="getBackForwardList"
- return="android.webkit.WebBackForwardList"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getProgress"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getVisitedHistory"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.String[]&gt;">
-</parameter>
-</method>
-<method name="getWebChromeClient"
- return="android.webkit.WebChromeClient"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onCloseWindow"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="window" type="android.webkit.WebView">
-</parameter>
-</method>
-<method name="onDownloadStart"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="userAgent" type="java.lang.String">
-</parameter>
-<parameter name="contentDisposition" type="java.lang.String">
-</parameter>
-<parameter name="mimetype" type="java.lang.String">
-</parameter>
-<parameter name="contentLength" type="long">
-</parameter>
-</method>
-<method name="onExceededDatabaseQuota"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="databaseIdentifier" type="java.lang.String">
-</parameter>
-<parameter name="currentQuota" type="long">
-</parameter>
-<parameter name="estimatedSize" type="long">
-</parameter>
-<parameter name="totalUsedQuota" type="long">
-</parameter>
-<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
-</parameter>
-</method>
-<method name="onFormResubmission"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dontResend" type="android.os.Message">
-</parameter>
-<parameter name="resend" type="android.os.Message">
-</parameter>
-</method>
-<method name="onGeolocationPermissionsHidePrompt"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onGeolocationPermissionsShowPrompt"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="origin" type="java.lang.String">
-</parameter>
-<parameter name="callback" type="android.webkit.GeolocationPermissions.Callback">
-</parameter>
-</method>
-<method name="onJsAlert"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsBeforeUnload"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsConfirm"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsPrompt"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-<parameter name="defaultValue" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsTimeout"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onLoadResource"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="onPageFinished"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="onPageStarted"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="favicon" type="android.graphics.Bitmap">
-</parameter>
-</method>
-<method name="onProgressChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="newProgress" type="int">
-</parameter>
-</method>
-<method name="onReachedMaxAppCacheSize"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="spaceNeeded" type="long">
-</parameter>
-<parameter name="totalUsedQuota" type="long">
-</parameter>
-<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
-</parameter>
-</method>
-<method name="onReceivedError"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="errorCode" type="int">
-</parameter>
-<parameter name="description" type="java.lang.String">
-</parameter>
-<parameter name="failingUrl" type="java.lang.String">
-</parameter>
-</method>
-<method name="onReceivedHttpAuthRequest"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="handler" type="android.webkit.HttpAuthHandler">
-</parameter>
-<parameter name="hostName" type="java.lang.String">
-</parameter>
-<parameter name="realmName" type="java.lang.String">
-</parameter>
-</method>
-<method name="onReceivedIcon"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
-</method>
-<method name="onReceivedTitle"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="title" type="java.lang.String">
-</parameter>
-</method>
-<method name="onRequestFocus"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onSavePassword"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="schemePlusHost" type="java.lang.String">
-</parameter>
-<parameter name="username" type="java.lang.String">
-</parameter>
-<parameter name="password" type="java.lang.String">
-</parameter>
-<parameter name="resumeMsg" type="android.os.Message">
-</parameter>
-</method>
-<method name="onScaleChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="oldScale" type="float">
-</parameter>
-<parameter name="newScale" type="float">
-</parameter>
-</method>
-<method name="onTooManyRedirects"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="cancelMsg" type="android.os.Message">
-</parameter>
-<parameter name="continueMsg" type="android.os.Message">
-</parameter>
-</method>
-<method name="onUnhandledKeyEvent"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="event" type="android.view.KeyEvent">
-</parameter>
-</method>
-<method name="setDownloadListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="client" type="android.webkit.DownloadListener">
-</parameter>
-</method>
-<method name="setWebChromeClient"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="client" type="android.webkit.WebChromeClient">
-</parameter>
-</method>
-<method name="setWebViewClient"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="client" type="android.webkit.WebViewClient">
-</parameter>
-</method>
-<method name="shouldOverrideUrlLoading"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="uiOverrideKeyEvent"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="event" type="android.view.KeyEvent">
-</parameter>
-</method>
-<method name="uiOverrideUrlLoading"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="overrideUrl" type="java.lang.String">
-</parameter>
-</method>
-</class>
 <class name="CookieManager"
  extends="java.lang.Object"
  abstract="false"
@@ -174438,16 +173871,6 @@
  visibility="protected"
 >
 </method>
-<field name="mProxy"
- type="android.webkit.CallbackProxy"
- transient="false"
- volatile="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="protected"
->
-</field>
 <field name="mResult"
  type="boolean"
  transient="false"
diff --git a/api/current.xml b/api/current.xml
index 9bd5c01..65aa5b6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -33641,6 +33641,17 @@
  visibility="public"
 >
 </field>
+<field name="STORAGE_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;storage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TELEPHONY_SERVICE"
  type="java.lang.String"
  transient="false"
@@ -117383,6 +117394,123 @@
 </parameter>
 </method>
 </class>
+<interface name="StorageEventListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onMediaInserted"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="label" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="major" type="int">
+</parameter>
+<parameter name="minor" type="int">
+</parameter>
+</method>
+<method name="onMediaRemoved"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="label" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="major" type="int">
+</parameter>
+<parameter name="minor" type="int">
+</parameter>
+<parameter name="clean" type="boolean">
+</parameter>
+</method>
+<method name="onShareAvailabilityChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="method" type="java.lang.String">
+</parameter>
+<parameter name="available" type="boolean">
+</parameter>
+</method>
+<method name="onVolumeStateChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="label" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="oldState" type="java.lang.String">
+</parameter>
+<parameter name="newState" type="java.lang.String">
+</parameter>
+</method>
+</interface>
+<class name="StorageManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="registerListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.StorageEventListener">
+</parameter>
+</method>
+<method name="unregisterListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.StorageEventListener">
+</parameter>
+</method>
+</class>
 <class name="SystemClock"
  extends="java.lang.Object"
  abstract="false"
@@ -185890,573 +186018,6 @@
 </parameter>
 </method>
 </class>
-<class name="CallbackProxy"
- extends="android.os.Handler"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility=""
->
-<constructor name="CallbackProxy"
- type="android.webkit.CallbackProxy"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="w" type="android.webkit.WebView">
-</parameter>
-</constructor>
-<method name="addMessageToConsole"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="message" type="java.lang.String">
-</parameter>
-<parameter name="lineNumber" type="int">
-</parameter>
-<parameter name="sourceID" type="java.lang.String">
-</parameter>
-</method>
-<method name="createWindow"
- return="android.webkit.WebView"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dialog" type="boolean">
-</parameter>
-<parameter name="userGesture" type="boolean">
-</parameter>
-</method>
-<method name="doUpdateVisitedHistory"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="isReload" type="boolean">
-</parameter>
-</method>
-<method name="getBackForwardList"
- return="android.webkit.WebBackForwardList"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getProgress"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getVisitedHistory"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.webkit.ValueCallback&lt;java.lang.String[]&gt;">
-</parameter>
-</method>
-<method name="getWebChromeClient"
- return="android.webkit.WebChromeClient"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onCloseWindow"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="window" type="android.webkit.WebView">
-</parameter>
-</method>
-<method name="onDownloadStart"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="userAgent" type="java.lang.String">
-</parameter>
-<parameter name="contentDisposition" type="java.lang.String">
-</parameter>
-<parameter name="mimetype" type="java.lang.String">
-</parameter>
-<parameter name="contentLength" type="long">
-</parameter>
-</method>
-<method name="onExceededDatabaseQuota"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="databaseIdentifier" type="java.lang.String">
-</parameter>
-<parameter name="currentQuota" type="long">
-</parameter>
-<parameter name="estimatedSize" type="long">
-</parameter>
-<parameter name="totalUsedQuota" type="long">
-</parameter>
-<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
-</parameter>
-</method>
-<method name="onFormResubmission"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="dontResend" type="android.os.Message">
-</parameter>
-<parameter name="resend" type="android.os.Message">
-</parameter>
-</method>
-<method name="onGeolocationPermissionsHidePrompt"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onGeolocationPermissionsShowPrompt"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="origin" type="java.lang.String">
-</parameter>
-<parameter name="callback" type="android.webkit.GeolocationPermissions.Callback">
-</parameter>
-</method>
-<method name="onJsAlert"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsBeforeUnload"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsConfirm"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsPrompt"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="message" type="java.lang.String">
-</parameter>
-<parameter name="defaultValue" type="java.lang.String">
-</parameter>
-</method>
-<method name="onJsTimeout"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onLoadResource"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="onPageFinished"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="onPageStarted"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-<parameter name="favicon" type="android.graphics.Bitmap">
-</parameter>
-</method>
-<method name="onProgressChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="newProgress" type="int">
-</parameter>
-</method>
-<method name="onReachedMaxAppCacheSize"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="spaceNeeded" type="long">
-</parameter>
-<parameter name="totalUsedQuota" type="long">
-</parameter>
-<parameter name="quotaUpdater" type="android.webkit.WebStorage.QuotaUpdater">
-</parameter>
-</method>
-<method name="onReceivedError"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="errorCode" type="int">
-</parameter>
-<parameter name="description" type="java.lang.String">
-</parameter>
-<parameter name="failingUrl" type="java.lang.String">
-</parameter>
-</method>
-<method name="onReceivedHttpAuthRequest"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="handler" type="android.webkit.HttpAuthHandler">
-</parameter>
-<parameter name="hostName" type="java.lang.String">
-</parameter>
-<parameter name="realmName" type="java.lang.String">
-</parameter>
-</method>
-<method name="onReceivedIcon"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="icon" type="android.graphics.Bitmap">
-</parameter>
-</method>
-<method name="onReceivedTitle"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="title" type="java.lang.String">
-</parameter>
-</method>
-<method name="onRequestFocus"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onSavePassword"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="schemePlusHost" type="java.lang.String">
-</parameter>
-<parameter name="username" type="java.lang.String">
-</parameter>
-<parameter name="password" type="java.lang.String">
-</parameter>
-<parameter name="resumeMsg" type="android.os.Message">
-</parameter>
-</method>
-<method name="onScaleChanged"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="oldScale" type="float">
-</parameter>
-<parameter name="newScale" type="float">
-</parameter>
-</method>
-<method name="onTooManyRedirects"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="cancelMsg" type="android.os.Message">
-</parameter>
-<parameter name="continueMsg" type="android.os.Message">
-</parameter>
-</method>
-<method name="onUnhandledKeyEvent"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="event" type="android.view.KeyEvent">
-</parameter>
-</method>
-<method name="setDownloadListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="client" type="android.webkit.DownloadListener">
-</parameter>
-</method>
-<method name="setWebChromeClient"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="client" type="android.webkit.WebChromeClient">
-</parameter>
-</method>
-<method name="setWebViewClient"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="client" type="android.webkit.WebViewClient">
-</parameter>
-</method>
-<method name="shouldOverrideUrlLoading"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="url" type="java.lang.String">
-</parameter>
-</method>
-<method name="uiOverrideKeyEvent"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="event" type="android.view.KeyEvent">
-</parameter>
-</method>
-<method name="uiOverrideUrlLoading"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="overrideUrl" type="java.lang.String">
-</parameter>
-</method>
-</class>
 <class name="CookieManager"
  extends="java.lang.Object"
  abstract="false"
@@ -186942,16 +186503,6 @@
  visibility="protected"
 >
 </method>
-<field name="mProxy"
- type="android.webkit.CallbackProxy"
- transient="false"
- volatile="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="protected"
->
-</field>
 <field name="mResult"
  type="boolean"
  transient="false"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 6c65bd8..88a2b48 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -81,6 +81,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.StorageManager;
 import android.os.StatFs;
 import android.os.Vibrator;
 import android.os.FileUtils.FileStatus;
@@ -180,6 +181,7 @@
     private Context mReceiverRestrictedContext = null;
     private SearchManager mSearchManager = null;
     private SensorManager mSensorManager = null;
+    private StorageManager mStorageManager = null;
     private Vibrator mVibrator = null;
     private LayoutInflater mLayoutInflater = null;
     private StatusBarManager mStatusBarManager = null;
@@ -879,6 +881,8 @@
             return getSearchManager();
         } else if (SENSOR_SERVICE.equals(name)) {
             return getSensorManager();
+        } else if (STORAGE_SERVICE.equals(name)) {
+            return getStorageManager();
         } else if (VIBRATOR_SERVICE.equals(name)) {
             return getVibrator();
         } else if (STATUS_BAR_SERVICE.equals(name)) {
@@ -1041,6 +1045,20 @@
         return mSensorManager;
     }
 
+    private StorageManager getStorageManager() {
+        synchronized (mSync) {
+            if (mStorageManager == null) {
+                try {
+                    mStorageManager = new StorageManager(mMainThread.getHandler().getLooper());
+                } catch (RemoteException rex) {
+                    Log.e(TAG, "Failed to create StorageManager", rex);
+                    mStorageManager = null;
+                }
+            }
+        }
+        return mStorageManager;
+    }
+
     private Vibrator getVibrator() {
         synchronized (mSync) {
             if (mVibrator == null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 321ba5c..dae8e37 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1109,6 +1109,8 @@
      * @see android.app.SearchManager
      * @see #SENSOR_SERVICE
      * @see android.hardware.SensorManager
+     * @see #STORAGE_SERVICE
+     * @see android.os.StorageManager
      * @see #VIBRATOR_SERVICE
      * @see android.os.Vibrator
      * @see #CONNECTIVITY_SERVICE
@@ -1240,6 +1242,16 @@
     public static final String SENSOR_SERVICE = "sensor";
     
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.os.StorageManager} for accesssing system storage
+     * functions.
+     *
+     * @see #getSystemService
+     * @see android.os.StorageManager
+     */
+    public static final String STORAGE_SERVICE = "storage";
+
+    /**
      * Use with {@link #getSystemService} to retrieve a
      * com.android.server.WallpaperService for accessing wallpapers.
      *
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index e3c25ec..e4b0191 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -290,6 +290,10 @@
     @Override
     protected void onAllReferencesReleased() {
         if (isOpen()) {
+            if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+                Log.d(TAG, "captured_sql|" + mPath + "|DETACH DATABASE " +
+                        getDatabaseName(mPath) + ";");
+            }
             if (SQLiteDebug.DEBUG_SQL_CACHE) {
                 mTimeClosed = getTime();
             }
@@ -1648,6 +1652,9 @@
      */
     public void execSQL(String sql) throws SQLException {
         long timeStart = Debug.threadCpuTimeNanos();
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            Log.v(TAG, SQLiteDebug.captureSql(this.getPath(), sql, null));
+        }
         lock();
         try {
             native_execSQL(sql);
@@ -1673,7 +1680,9 @@
         if (bindArgs == null) {
             throw new IllegalArgumentException("Empty bindArgs");
         }
-
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            Log.v(TAG, SQLiteDebug.captureSql(this.getPath(), sql, bindArgs));
+        }
         long timeStart = Debug.threadCpuTimeNanos();
         lock();
         SQLiteStatement statement = null;
@@ -1732,6 +1741,10 @@
         mLeakedException = new IllegalStateException(path +
             " SQLiteDatabase created and never closed");
         mFactory = factory;
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            Log.d(TAG, "captured_sql|" + mPath + "|ATTACH DATABASE '" + mPath +
+                    "' as " + getDatabaseName(mPath) + ";");
+        }
         dbopen(mPath, mFlags);
         if (SQLiteDebug.DEBUG_SQL_CACHE) {
             mTimeOpened = getTime();
@@ -1741,6 +1754,10 @@
             setLocale(Locale.getDefault());
         } catch (RuntimeException e) {
             Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
+            if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+                Log.d(TAG, "captured_sql|" + mPath + "|DETACH DATABASE " +
+                        getDatabaseName(mPath) + ";");
+            }
             dbclose();
             if (SQLiteDebug.DEBUG_SQL_CACHE) {
                 mTimeClosed = getTime();
@@ -1753,6 +1770,20 @@
         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis());
     }
 
+    private String getDatabaseName(String path) {
+        if (path == null || path.trim().length() == 0) {
+            return "db not specified?";
+        }
+
+        if (path.equalsIgnoreCase(":memory:")) {
+            return "memorydb";
+        }
+        String[] tokens = path.split("/");
+        String[] lastNodeTokens = tokens[tokens.length - 1].split("\\.", 2);
+        return (lastNodeTokens.length == 1) ? lastNodeTokens[0]
+                : lastNodeTokens[0] + lastNodeTokens[1];
+    }
+
     /**
      * return whether the DB is opened as read only.
      * @return true if DB is opened as read only
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index d4d3059..b12034a 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -16,12 +16,11 @@
 
 package android.database.sqlite;
 
-import android.util.Config;
 import android.util.Log;
 
 /**
  * Provides debugging info about all SQLite databases running in the current process.
- * 
+ *
  * {@hide}
  */
 public final class SQLiteDebug {
@@ -38,6 +37,13 @@
             Log.isLoggable("SQLiteCompiledSql", Log.VERBOSE);
 
     /**
+     * Controls the capturing and printing of complete sql statement including the bind args and
+     * the database name.
+     */
+    public static final boolean DEBUG_CAPTURE_SQL =
+            Log.isLoggable("SQLiteCaptureSql", Log.VERBOSE);
+
+    /**
      * Controls the stack trace reporting of active cursors being
      * finalized.
      */
@@ -45,20 +51,20 @@
             Log.isLoggable("SQLiteCursorClosing", Log.VERBOSE);
 
     /**
-     * Controls the tracking of time spent holding the database lock. 
+     * Controls the tracking of time spent holding the database lock.
      */
     public static final boolean DEBUG_LOCK_TIME_TRACKING =
             Log.isLoggable("SQLiteLockTime", Log.VERBOSE);
 
     /**
-     * Controls the printing of stack traces when tracking the time spent holding the database lock. 
+     * Controls the printing of stack traces when tracking the time spent holding the database lock.
      */
     public static final boolean DEBUG_LOCK_TIME_TRACKING_STACK_TRACE =
             Log.isLoggable("SQLiteLockStackTrace", Log.VERBOSE);
 
     /**
      * Contains statistics about the active pagers in the current process.
-     * 
+     *
      * @see #getPagerStats(PagerStats)
      */
     public static class PagerStats {
@@ -82,13 +88,13 @@
      * @return The size of the SQLite heap in bytes.
      */
     public static native long getHeapSize();
-    
+
     /**
      * Returns the amount of allocated memory in the SQLite heap.
      * @return The allocated size in bytes.
      */
     public static native long getHeapAllocatedSize();
-    
+
     /**
      * Returns the amount of free memory in the SQLite heap.
      * @return The freed size in bytes.
@@ -115,4 +121,62 @@
     static synchronized void notifyActiveCursorFinalized() {
         sNumActiveCursorsFinalized++;
     }
+
+    /**
+     * returns a  message containing the given database name (path) and the string built by
+     * replacing "?" characters in the given sql string with the corresponding
+     * positional values from the given param bindArgs.
+     *
+     * @param path the database name
+     * @param sql sql string with possibly "?" for bindargs
+     * @param bindArgs args for "?"s in the above string
+     * @return the String to be logged
+     */
+    /* package */ static String captureSql(String path, String sql, Object[] bindArgs) {
+        // how many bindargs in sql
+        sql = sql.trim();
+        String args[] = sql.split("\\?");
+        // how many "?"s in the given sql string?
+        int varArgsInSql = (sql.endsWith("?")) ? args.length : args.length - 1;
+
+        // how many bind args do we have in the given input param bindArgs
+        int bindArgsLen = (bindArgs == null) ? 0 : bindArgs.length;
+        if (varArgsInSql < bindArgsLen) {
+            return "too many bindArgs provided. " +
+                    "# of bindArgs = " + bindArgsLen + ", # of varargs = " + varArgsInSql +
+                    "; sql = " + sql;
+        }
+
+        // if there are no bindArgs, we are done. log the sql as is.
+        if (bindArgsLen == 0 && varArgsInSql == 0) {
+            return logSql(path, sql);
+        }
+
+        StringBuilder buf = new StringBuilder();
+
+        // take the supplied bindArgs and plug them into sql
+        for (int i = 0; i < bindArgsLen; i++) {
+            buf.append(args[i]);
+            buf.append(bindArgs[i]);
+        }
+
+        // does given sql have more varArgs than the supplied bindArgs
+        // if so, assign nulls to the extra varArgs in sql
+        for (int i = bindArgsLen; i < varArgsInSql; i ++) {
+            buf.append(args[i]);
+            buf.append("null");
+        }
+
+        // if there are any characters left in the given sql string AFTER the last "?"
+        // log them also. for example, if the given sql = "select * from test where a=? and b=1
+        // then the following code appends " and b=1" string to buf.
+        if (varArgsInSql < args.length) {
+            buf.append(args[varArgsInSql]);
+        }
+        return logSql(path, buf.toString());
+    }
+
+    private static String logSql(String path, String sql) {
+        return "captured_sql|" + path + "|" + sql + ";";
+    }
 }
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 00b0a86..1159c1d 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,6 +16,12 @@
 
 package android.database.sqlite;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
 import android.util.Log;
 
 /**
@@ -47,6 +53,11 @@
      */
     protected int nStatement = 0;
 
+    /**
+     * stores all bindargs for debugging purposes
+     */
+    private Map<Integer, String> mBindArgs = null;
+
     /* package */ SQLiteProgram(SQLiteDatabase db, String sql) {
         if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
             Log.d(TAG, "processing sql: " + sql);
@@ -127,6 +138,9 @@
      * @param index The 1-based index to the parameter to bind null to
      */
     public void bindNull(int index) {
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            addToBindArgs(index, "null");
+        }
         acquireReference();
         try {
             native_bind_null(index);
@@ -143,6 +157,9 @@
      * @param value The value to bind
      */
     public void bindLong(int index, long value) {
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            addToBindArgs(index, value + "");
+        }
         acquireReference();
         try {
             native_bind_long(index, value);
@@ -159,6 +176,9 @@
      * @param value The value to bind
      */
     public void bindDouble(int index, double value) {
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            addToBindArgs(index, value + "");
+        }
         acquireReference();
         try {
             native_bind_double(index, value);
@@ -175,6 +195,9 @@
      * @param value The value to bind
      */
     public void bindString(int index, String value) {
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            addToBindArgs(index, "'" + value + "'");
+        }
         if (value == null) {
             throw new IllegalArgumentException("the bind value at index " + index + " is null");
         }
@@ -194,6 +217,9 @@
      * @param value The value to bind
      */
     public void bindBlob(int index, byte[] value) {
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            addToBindArgs(index, "blob");
+        }
         if (value == null) {
             throw new IllegalArgumentException("the bind value at index " + index + " is null");
         }
@@ -209,6 +235,9 @@
      * Clears all existing bindings. Unset bindings are treated as NULL.
      */
     public void clearBindings() {
+        if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+            mBindArgs = null;
+        }
         acquireReference();
         try {
             native_clear_bindings();
@@ -230,6 +259,39 @@
     }
 
     /**
+     * this method is called under the debug flag {@link SQLiteDebug.DEBUG_CAPTURE_SQL} only.
+     * it collects the bindargs as they are called by the callers the bind... methods in this
+     * class.
+     */
+    private void addToBindArgs(int index, String obj) {
+        if (mBindArgs == null) {
+            mBindArgs = new HashMap<Integer, String>();
+        }
+        mBindArgs.put(index, obj);
+    }
+
+    /**
+     * constructs all the bindargs in sequence and returns a String Array of the values.
+     * it uses the HashMap built up by the above method.
+     *
+     * @return the string array of bindArgs with the args arranged in sequence
+     */
+    /* package */ String[] getBindArgs() {
+        if (mBindArgs == null) {
+            return null;
+        }
+        Set<Integer> indexSet = mBindArgs.keySet();
+        ArrayList<Integer> indexList = new ArrayList<Integer>(indexSet);
+        Collections.sort(indexList);
+        int len = indexList.size();
+        String[] bindObjs = new String[len];
+        for (int i = 0; i < len; i++) {
+            bindObjs[i] = mBindArgs.get(indexList.get(i));
+        }
+        return bindObjs;
+    }
+
+    /**
      * Compiles SQL into a SQLite program.
      *
      * <P>The database lock must be held when calling this method.
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index cc714ee..0cee3c5 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -17,7 +17,6 @@
 package android.database.sqlite;
 
 import android.os.Debug;
-import android.os.SystemClock;
 import android.util.Log;
 
 /**
@@ -56,6 +55,9 @@
             if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
                 Log.v(TAG, "execute() for [" + mSql + "]");
             }
+            if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+                Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
+            }
             native_execute();
             mDatabase.logTimeStat(mSql, timeStart);
         } finally {
@@ -83,6 +85,9 @@
             if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
                 Log.v(TAG, "executeInsert() for [" + mSql + "]");
             }
+            if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+                Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
+            }
             native_execute();
             mDatabase.logTimeStat(mSql, timeStart);
             return mDatabase.lastInsertRow();
@@ -109,6 +114,9 @@
             if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
                 Log.v(TAG, "simpleQueryForLong() for [" + mSql + "]");
             }
+            if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+                Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
+            }
             long retValue = native_1x1_long();
             mDatabase.logTimeStat(mSql, timeStart);
             return retValue;
@@ -135,6 +143,9 @@
             if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
                 Log.v(TAG, "simpleQueryForString() for [" + mSql + "]");
             }
+            if (SQLiteDebug.DEBUG_CAPTURE_SQL) {
+                Log.v(TAG, SQLiteDebug.captureSql(mDatabase.getPath(), mSql, getBindArgs()));
+            }
             String retValue = native_1x1_string();
             mDatabase.logTimeStat(mSql, timeStart);
             return retValue;
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 2124e85..a5828f6 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -17,6 +17,8 @@
 
 package android.os;
 
+import android.os.IMountServiceListener;
+
 /** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
  * In particular, the ordering of the methods below must match the 
  * _TRANSACTION enum in IMountService.cpp
@@ -25,44 +27,60 @@
 interface IMountService
 {
     /**
-     * Is mass storage support enabled?
+     * Registers an IMountServiceListener for receiving async
+     * notifications.
      */
-    boolean getMassStorageEnabled();
+    void registerListener(IMountServiceListener listener);
 
     /**
-     * Enable or disable mass storage support.
+     * Unregisters an IMountServiceListener
      */
-    void setMassStorageEnabled(boolean enabled);
+    void unregisterListener(IMountServiceListener listener);
 
     /**
-     * Is mass storage connected?
+     * Gets an Array of supported share methods
      */
-    boolean getMassStorageConnected();
-    
+    String[] getShareMethodList();
+
+    /**
+     * Returns true if the share method is available
+     */
+    boolean getShareMethodAvailable(String method);
+
+    /**
+     * Shares a volume via the specified method
+     * Returns an int consistent with MountServiceResultCode
+     */
+    int shareVolume(String path, String method);
+
+    /**
+     * Unshares a volume via the specified method
+     * Returns an int consistent with MountServiceResultCode
+     */
+    int unshareVolume(String path, String method);
+
+    /**
+     * Returns true if the volume is shared via the specified method.
+     */
+    boolean getVolumeShared(String path, String method);
+
     /**
      * Mount external storage at given mount point.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void mountVolume(String mountPoint);
+    int mountVolume(String mountPoint);
 
     /**
      * Safely unmount external storage at given mount point.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void unmountVolume(String mountPoint);
+    int unmountVolume(String mountPoint);
 
     /**
      * Format external storage given a mount point.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void formatVolume(String mountPoint);
-
-    /**
-     * Returns true if media notification sounds are enabled.
-     */
-    boolean getPlayNotificationSounds();
-
-    /**
-     * Sets whether or not media notification sounds are played.
-     */
-    void setPlayNotificationSounds(boolean value);
+    int formatVolume(String mountPoint);
 
     /**
      * Gets the state of an volume via it's mountpoint.
@@ -71,37 +89,41 @@
 
     /*
      * Creates a secure container with the specified parameters.
-     * On success, the filesystem container-path is returned.
+     * Returns an int consistent with MountServiceResultCode
      */
-    String createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid);
+    int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid);
 
     /*
      * Finalize a container which has just been created and populated.
      * After finalization, the container is immutable.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void finalizeSecureContainer(String id);
+    int finalizeSecureContainer(String id);
 
     /*
      * Destroy a secure container, and free up all resources associated with it.
      * NOTE: Ensure all references are released prior to deleting.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void destroySecureContainer(String id);
+     int destroySecureContainer(String id);
 
     /*
      * Mount a secure container with the specified key and owner UID.
-     * On success, the filesystem container-path is returned.
+     * Returns an int consistent with MountServiceResultCode
      */
-    String mountSecureContainer(String id, String key, int ownerUid);
+    int mountSecureContainer(String id, String key, int ownerUid);
 
     /*
      * Unount a secure container.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void unmountSecureContainer(String id);
+    int unmountSecureContainer(String id);
 
     /*
      * Rename an unmounted secure container.
+     * Returns an int consistent with MountServiceResultCode
      */
-    void renameSecureContainer(String oldId, String newId);
+    int renameSecureContainer(String oldId, String newId);
 
     /*
      * Returns the filesystem path of a mounted secure container.
diff --git a/core/java/android/os/IMountServiceObserver.aidl b/core/java/android/os/IMountServiceListener.aidl
similarity index 83%
rename from core/java/android/os/IMountServiceObserver.aidl
rename to core/java/android/os/IMountServiceListener.aidl
index f753649..3df64b2 100644
--- a/core/java/android/os/IMountServiceObserver.aidl
+++ b/core/java/android/os/IMountServiceListener.aidl
@@ -21,14 +21,14 @@
  *
  * @hide
  */
-interface IMountServiceObserver {
+interface IMountServiceListener {
     /**
      * A sharing method has changed availability state.
      *
      * @param method The share method which has changed.
      * @param available The share availability state.
      */
-    void shareAvailabilityChange(String method, boolean available);
+    void onShareAvailabilityChanged(String method, boolean available);
 
     /**
      * Media has been inserted
@@ -38,7 +38,7 @@
      * @param major The backing device major number.
      * @param minor The backing device minor number.
      */
-    void mediaInserted(String label, String path, int major, int minor);
+    void onMediaInserted(String label, String path, int major, int minor);
 
     /**
      * Media has been removed
@@ -49,7 +49,7 @@
      * @param minor The backing device minor number.
      * @param clean Indicates if the removal was clean (unmounted first).
      */
-    void mediaRemoved(String label, String path, int major, int minor, boolean clean);
+    void onMediaRemoved(String label, String path, int major, int minor, boolean clean);
 
     /**
      *  Volume state has changed.
@@ -61,6 +61,6 @@
      *
      * Note: State is one of the values returned by Environment.getExternalStorageState()
      */
-    void volumeStateChange(String label, String path, String oldState, String newState);
+    void onVolumeStateChanged(String label, String path, String oldState, String newState);
 
 }
diff --git a/core/java/android/os/MountServiceObserver.java b/core/java/android/os/MountServiceListener.java
similarity index 97%
rename from core/java/android/os/MountServiceObserver.java
rename to core/java/android/os/MountServiceListener.java
index 3020562..a68f464 100644
--- a/core/java/android/os/MountServiceObserver.java
+++ b/core/java/android/os/MountServiceListener.java
@@ -21,7 +21,7 @@
  * methods will all be called on your application's main thread.
  * @hide
  */
-public abstract class MountServiceObserver {
+public abstract class MountServiceListener {
     /**
      * A sharing method has changed availability state.
      *
diff --git a/core/java/android/os/MountServiceResultCode.java b/core/java/android/os/MountServiceResultCode.java
new file mode 100644
index 0000000..e71dbf4
--- /dev/null
+++ b/core/java/android/os/MountServiceResultCode.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import java.io.IOException;
+
+/**
+ * Class that provides access to constants returned from MountService APIs
+ *
+ * {@hide}
+ */
+public class MountServiceResultCode
+{
+    public static final int OperationSucceeded               =  0;
+    public static final int OperationFailedInternalError     = -1;
+    public static final int OperationFailedNoMedia           = -2;
+    public static final int OperationFailedMediaBlank        = -3;
+    public static final int OperationFailedMediaCorrupt      = -4;
+    public static final int OperationFailedVolumeNotMounted  = -5;
+}
diff --git a/core/java/android/os/StorageEventListener.java b/core/java/android/os/StorageEventListener.java
new file mode 100644
index 0000000..f852f42
--- /dev/null
+++ b/core/java/android/os/StorageEventListener.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Used for receiving notifications from the StorageManager
+ */
+public interface StorageEventListener {
+    /**
+     * Called when the ability to share a volume has changed.
+     * @param method the share-method which has changed.
+     * @param available true if the share is available.
+     */
+    public void onShareAvailabilityChanged(String method, boolean available);
+
+    /**
+     * Called when media has been inserted
+     * @param label the system defined label for the volume.
+     * @param path the filesystem path for the volume.
+     * @param major the major number of the device.
+     * @param minor the minor number of the device.
+     */
+    public void onMediaInserted(String label, String path, int major, int minor);
+
+    /**
+     * Called when media has been removed
+     * @param label the system defined label for the volume.
+     * @param path the filesystem path for the volume.
+     * @param major the major number of the device.
+     * @param minor the minor number of the device.
+     * @param clean the media was removed cleanly.
+     */
+    public void onMediaRemoved(String label, String path, int major, int minor, boolean clean);
+
+    /**
+     * Called when a volume has changed state
+     * @param label the system defined label for the volume.
+     * @param path the filesystem path for the volume.
+     * @param oldState the old state as returned by {@link android.os.Environment.getExternalStorageState()}.
+     * @param newState the old state as returned by {@link android.os.Environment.getExternalStorageState()}.
+     */
+    public void onVolumeStateChanged(String label, String path, String oldState, String newState);
+}
diff --git a/core/java/android/os/StorageManager.java b/core/java/android/os/StorageManager.java
new file mode 100644
index 0000000..764abe0
--- /dev/null
+++ b/core/java/android/os/StorageManager.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.IMountService;
+import android.os.IMountServiceListener;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Class that lets you access the device's storage management functions. Get an instance of this
+ * class by calling {@link android.content.Context#getSystemService(java.lang.String)
+ * Context.getSystemService()} with an argument of {@link android.content.Context#STORAGE_SERVICE}.
+ */
+public class StorageManager
+{
+    private static final String TAG = "StorageManager";
+
+    /*
+     * Our internal MountService binder reference
+     */
+    private IMountService mMountService;
+
+    /*
+     * The looper target for callbacks
+     */
+    Looper mTgtLooper;
+
+    /*
+     * Target listener for binder callbacks
+     */
+    private MountServiceBinderListener mBinderListener;
+
+    /*
+     * *static* list of our listeners
+     */
+    static final ArrayList<ListenerDelegate> sListeners = new ArrayList<ListenerDelegate>();
+
+    private class MountServiceBinderListener extends IMountServiceListener.Stub {
+        public void onShareAvailabilityChanged(String method, boolean available) {
+            final int size = sListeners.size();
+            for (int i = 0; i < size; i++) {
+                sListeners.get(i).sendShareAvailabilityChanged(method, available);
+            }
+        }
+
+        public void onMediaInserted(String label, String path, int major, int minor) {
+            final int size = sListeners.size();
+            for (int i = 0; i < size; i++) {
+                sListeners.get(i).sendMediaInserted(label, path, major, minor);
+            }
+        }
+
+        public void onMediaRemoved(String label, String path, int major, int minor, boolean clean) {
+            final int size = sListeners.size();
+            for (int i = 0; i < size; i++) {
+                sListeners.get(i).sendMediaRemoved(label, path, major, minor, clean);
+            }
+        }
+
+        public void onVolumeStateChanged(String label, String path, String oldState, String newState) {
+            final int size = sListeners.size();
+            for (int i = 0; i < size; i++) {
+                sListeners.get(i).sendVolumeStateChanged(label, path, oldState, newState);
+            }
+        }
+    }
+
+    /**
+     * Private base class for messages sent between the callback thread
+     * and the target looper handler
+     */
+    private class StorageEvent {
+        public static final int EVENT_SHARE_AVAILABILITY_CHANGED = 1;
+        public static final int EVENT_MEDIA_INSERTED             = 2;
+        public static final int EVENT_MEDIA_REMOVED              = 3;
+        public static final int EVENT_VOLUME_STATE_CHANGED       = 4;
+
+        private Message mMessage;
+
+        public StorageEvent(int what) {
+            mMessage = Message.obtain();
+            mMessage.what = what;
+            mMessage.obj = this;
+        }
+
+        public Message getMessage() {
+            return mMessage;
+        }
+    }
+
+    /**
+     * Message sent on a share availability change.
+     */
+    private class ShareAvailabilityChangedStorageEvent extends StorageEvent {
+        public String method;
+        public boolean available;
+
+        public ShareAvailabilityChangedStorageEvent(String m, boolean a) {
+            super(EVENT_SHARE_AVAILABILITY_CHANGED);
+            method = m;
+            available = a;
+        }
+    }
+
+    /**
+     * Message sent on media insertion
+     */
+    private class MediaInsertedStorageEvent extends StorageEvent {
+        public String label;
+        public String path;
+        public int major;
+        public int minor;
+
+        public MediaInsertedStorageEvent(String l, String p, int maj, int min) {
+            super(EVENT_MEDIA_INSERTED);
+            label = l;
+            path = p;
+            major = maj;
+            minor = min;
+        }
+    }
+
+    /**
+     * Message sent on media removal
+     */
+    private class MediaRemovedStorageEvent extends StorageEvent {
+        public String label;
+        public String path;
+        public int major;
+        public int minor;
+        public boolean clean;
+
+        public MediaRemovedStorageEvent(String l, String p, int maj, int min, boolean c) {
+            super(EVENT_MEDIA_REMOVED);
+            label = l;
+            path = p;
+            major = maj;
+            minor = min;
+            clean = c;
+        }
+    }
+
+    /**
+     * Message sent on volume state change
+     */
+    private class VolumeStateChangedStorageEvent extends StorageEvent {
+        public String label;
+        public String path;
+        public String oldState;
+        public String newState;
+
+        public VolumeStateChangedStorageEvent(String l, String p, String oldS, String newS) {
+            super(EVENT_VOLUME_STATE_CHANGED);
+            label = l;
+            path = p;
+            oldState = oldS;
+            newState = newS;
+        }
+    }
+
+    /**
+     * Private class containing sender and receiver code for StorageEvents
+     */
+    private class ListenerDelegate {
+        final StorageEventListener mStorageEventListener;
+        private final Handler mHandler;
+
+        ListenerDelegate(StorageEventListener listener) {
+            mStorageEventListener = listener;
+            mHandler = new Handler(mTgtLooper) {
+                @Override
+                public void handleMessage(Message msg) {
+                    StorageEvent e = (StorageEvent) msg.obj;
+
+                    if (msg.what == StorageEvent.EVENT_SHARE_AVAILABILITY_CHANGED) {
+                        ShareAvailabilityChangedStorageEvent ev = (ShareAvailabilityChangedStorageEvent) e;
+                        mStorageEventListener.onShareAvailabilityChanged(ev.method, ev.available);
+                    } else if (msg.what == StorageEvent.EVENT_MEDIA_INSERTED) {
+                        MediaInsertedStorageEvent ev = (MediaInsertedStorageEvent) e;
+                        mStorageEventListener.onMediaInserted(ev.label, ev.path, ev.major, ev.minor);
+                    } else if (msg.what == StorageEvent.EVENT_MEDIA_REMOVED) {
+                        MediaRemovedStorageEvent ev = (MediaRemovedStorageEvent) e;
+                        mStorageEventListener.onMediaRemoved(ev.label, ev.path, ev.major, ev.minor, ev.clean);
+                    } else if (msg.what == StorageEvent.EVENT_VOLUME_STATE_CHANGED) {
+                        VolumeStateChangedStorageEvent ev = (VolumeStateChangedStorageEvent) e;
+                        mStorageEventListener.onVolumeStateChanged(ev.label, ev.path, ev.oldState, ev.newState);
+                    } else {
+                        Log.e(TAG, "Unsupported event " + msg.what);
+                    }
+                }
+            };
+        }
+
+        StorageEventListener getListener() {
+            return mStorageEventListener;
+        }
+
+        void sendShareAvailabilityChanged(String method, boolean available) {
+            ShareAvailabilityChangedStorageEvent e = new ShareAvailabilityChangedStorageEvent(method, available);
+            mHandler.sendMessage(e.getMessage());
+        }
+
+        void sendMediaInserted(String label, String path, int major, int minor) {
+            MediaInsertedStorageEvent e = new MediaInsertedStorageEvent(label, path, major, minor);
+            mHandler.sendMessage(e.getMessage());
+        }
+
+        void sendMediaRemoved(String label, String path, int major, int minor, boolean clean) {
+            MediaRemovedStorageEvent e = new MediaRemovedStorageEvent(label, path, major, minor, clean);
+            mHandler.sendMessage(e.getMessage());
+        }
+
+        void sendVolumeStateChanged(String label, String path, String oldState, String newState) {
+            VolumeStateChangedStorageEvent e = new VolumeStateChangedStorageEvent(label, path, oldState, newState);
+            mHandler.sendMessage(e.getMessage());
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public StorageManager(Looper tgtLooper) throws RemoteException {
+        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+        mTgtLooper = tgtLooper;
+        mBinderListener = new MountServiceBinderListener();
+        mMountService.registerListener(mBinderListener);
+    }
+
+
+    /**
+     * Registers a {@link android.os.StorageEventListener StorageEventListener}.
+     *
+     * @param listener A {@link android.os.StorageEventListener StorageEventListener} object.
+     *
+     */
+    public void registerListener(StorageEventListener listener) {
+        if (listener == null) {
+            return;
+        }
+
+        synchronized (sListeners) {
+            sListeners.add(new ListenerDelegate(listener));
+        }
+    }
+
+    /**
+     * Unregisters a {@link android.os.StorageEventListener StorageEventListener}.
+     *
+     * @param listener A {@link android.os.StorageEventListener StorageEventListener} object.
+     *
+     */
+    public void unregisterListener(StorageEventListener listener) {
+        if (listener == null) {
+            return;
+        }
+        synchronized (sListeners) {
+            final int size = sListeners.size();
+            for (int i=0 ; i<size ; i++) {
+                ListenerDelegate l = sListeners.get(i);
+                if (l.getListener() == listener) {
+                    sListeners.remove(i);
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 22dca3a..213eaa5 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -52,6 +52,7 @@
     private static final String NO_STORE = "no-store";
     private static final String NO_CACHE = "no-cache";
     private static final String MAX_AGE = "max-age";
+    private static final String MANIFEST_MIME = "text/cache-manifest";
 
     private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
     private static long CACHE_TRIM_AMOUNT = 2 * 1024 * 1024;
@@ -658,6 +659,15 @@
         // if the contentLength is already larger than CACHE_MAX_SIZE, skip it
         if (headers.getContentLength() > CACHE_MAX_SIZE) return null;
 
+        // The HTML 5 spec, section 6.9.4, step 7.3 of the application cache
+        // process states that HTTP caching rules are ignored for the
+        // purposes of the application cache download process.
+        // At this point we can't tell that if a file is part of this process,
+        // except for the manifest, which has its own mimeType.
+        // TODO: work out a way to distinguish all responses that are part of
+        // the application download process and skip them.
+        if (MANIFEST_MIME.equals(mimeType)) return null;
+
         // TODO: if authenticated or secure, return null
         CacheResult ret = new CacheResult();
         ret.httpStatusCode = statusCode;
diff --git a/core/java/android/webkit/ContentLoader.java b/core/java/android/webkit/ContentLoader.java
index 19aa087..5eb54b0 100644
--- a/core/java/android/webkit/ContentLoader.java
+++ b/core/java/android/webkit/ContentLoader.java
@@ -31,7 +31,6 @@
 class ContentLoader extends StreamLoader {
 
     private String mUrl;
-    private Context mContext;
     private String mContentType;
 
     /**
@@ -40,11 +39,9 @@
      * @param rawUrl "content:" url pointing to content to be loaded. This url
      *               is the same url passed in to the WebView.
      * @param loadListener LoadListener to pass the content to
-     * @param context Context to use to access the asset.
      */
-    ContentLoader(String rawUrl, LoadListener loadListener, Context context) {
+    ContentLoader(String rawUrl, LoadListener loadListener) {
         super(loadListener);
-        mContext = context;
 
         /* strip off mimetype */
         int mimeIndex = rawUrl.lastIndexOf('?');
@@ -81,7 +78,7 @@
 
         try {
             mDataStream = mContext.getContentResolver().openInputStream(uri);
-            mHandler.status(1, 1, 0, "OK");
+            mHandler.status(1, 1, 200, "OK");
         } catch (java.io.FileNotFoundException ex) {
             mHandler.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex));
             return false;
@@ -112,11 +109,9 @@
      *
      * @param url "content:" url pointing to content to be loaded
      * @param loadListener LoadListener to pass the content to
-     * @param context Context to use to access the asset.
      */
-    public static void requestUrl(String url, LoadListener loadListener,
-            Context context) {
-        ContentLoader loader = new ContentLoader(url, loadListener, context);
+    public static void requestUrl(String url, LoadListener loadListener) {
+        ContentLoader loader = new ContentLoader(url, loadListener);
         loader.load();
     }
 
diff --git a/core/java/android/webkit/DataLoader.java b/core/java/android/webkit/DataLoader.java
index 6c5d10d..2a68a5d 100644
--- a/core/java/android/webkit/DataLoader.java
+++ b/core/java/android/webkit/DataLoader.java
@@ -16,6 +16,10 @@
 
 package android.webkit;
 
+import android.net.http.EventHandler;
+
+import com.android.internal.R;
+
 import java.io.ByteArrayInputStream;
 
 import org.apache.harmony.luni.util.Base64;
@@ -49,14 +53,22 @@
         } else {
             data = url.getBytes();
         }
-        mDataStream = new ByteArrayInputStream(data);
-        mContentLength = data.length;
+        if (data != null) {
+            mDataStream = new ByteArrayInputStream(data);
+            mContentLength = data.length;
+        }
     }
 
     @Override
     protected boolean setupStreamAndSendStatus() {
-        mHandler.status(1, 1, 0, "OK");
-        return true;
+        if (mDataStream != null) {
+            mHandler.status(1, 1, 200, "OK");
+            return true;
+        } else {
+            mHandler.error(EventHandler.ERROR,
+                    mContext.getString(R.string.httpError));
+            return false;
+        }
     }
 
     @Override
diff --git a/core/java/android/webkit/FileLoader.java b/core/java/android/webkit/FileLoader.java
index 974ccbf..e856cde 100644
--- a/core/java/android/webkit/FileLoader.java
+++ b/core/java/android/webkit/FileLoader.java
@@ -38,7 +38,6 @@
 class FileLoader extends StreamLoader {
 
     private String mPath;  // Full path to the file to load
-    private Context mContext;  // Application context, used for asset/res loads
     private int mType;  // Indicates the type of the load
     private boolean mAllowFileAccess; // Allow/block file system access
 
@@ -57,16 +56,14 @@
      *
      * @param url Full file url pointing to content to be loaded
      * @param loadListener LoadListener to pass the content to
-     * @param context Context to use to access the asset.
      * @param asset true if url points to an asset.
      * @param allowFileAccess true if this WebView is allowed to access files
      *                        on the file system.
      */
-    FileLoader(String url, LoadListener loadListener, Context context,
-            int type, boolean allowFileAccess) {
+    FileLoader(String url, LoadListener loadListener, int type,
+            boolean allowFileAccess) {
         super(loadListener);
         mType = type;
-        mContext = context;
         mAllowFileAccess = allowFileAccess;
 
         // clean the Url
@@ -174,7 +171,7 @@
                 mDataStream = new FileInputStream(mPath);
                 mContentLength = (new File(mPath)).length();
             }
-            mHandler.status(1, 1, 0, "OK");
+            mHandler.status(1, 1, 200, "OK");
 
         } catch (java.io.FileNotFoundException ex) {
             mHandler.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex));
@@ -198,14 +195,13 @@
      *
      * @param url Full file url pointing to content to be loaded
      * @param loadListener LoadListener to pass the content to
-     * @param context Context to use to access the asset.
      * @param asset true if url points to an asset.
      * @param allowFileAccess true if this FileLoader can load files from the
      *                        file system.
      */
     public static void requestUrl(String url, LoadListener loadListener,
-            Context context, int type, boolean allowFileAccess) {
-        FileLoader loader = new FileLoader(url, loadListener, context, type,
+            int type, boolean allowFileAccess) {
+        FileLoader loader = new FileLoader(url, loadListener, type,
                 allowFileAccess);
         loader.load();
     }
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 51f60c3..58eca38 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -141,22 +141,21 @@
             return true;
         }
         if (URLUtil.isAssetUrl(url)) {
-            FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
-                    FileLoader.TYPE_ASSET, true);
+            FileLoader.requestUrl(url, loadListener, FileLoader.TYPE_ASSET,
+                    true);
             return true;
         } else if (URLUtil.isResourceUrl(url)) {
-            FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
-                    FileLoader.TYPE_RES, true);
+            FileLoader.requestUrl(url, loadListener, FileLoader.TYPE_RES,
+                    true);
             return true;
         } else if (URLUtil.isFileUrl(url)) {
-            FileLoader.requestUrl(url, loadListener, loadListener.getContext(),
-                    FileLoader.TYPE_FILE, settings.getAllowFileAccess());
+            FileLoader.requestUrl(url, loadListener, FileLoader.TYPE_FILE,
+                    settings.getAllowFileAccess());
             return true;
         } else if (URLUtil.isContentUrl(url)) {
             // Send the raw url to the ContentLoader because it will do a
             // permission check and the url has to match..
-            ContentLoader.requestUrl(loadListener.url(), loadListener,
-                                     loadListener.getContext());
+            ContentLoader.requestUrl(loadListener.url(), loadListener);
             return true;
         } else if (URLUtil.isDataUrl(url)) {
             DataLoader.requestUrl(url, loadListener);
diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java
index 0c86e0a..e61ab21 100644
--- a/core/java/android/webkit/JsResult.java
+++ b/core/java/android/webkit/JsResult.java
@@ -26,7 +26,10 @@
     private boolean mTriedToNotifyBeforeReady;
     // This is a basic result of a confirm or prompt dialog.
     protected boolean mResult;
-    // This is the caller of the prompt and is the object that is waiting.
+    /**
+     *  This is the caller of the prompt and is the object that is waiting.
+     *  @hide
+     */
     protected final CallbackProxy mProxy;
     // This is the default value of the result.
     private final boolean mDefaultValue;
diff --git a/core/java/android/webkit/StreamLoader.java b/core/java/android/webkit/StreamLoader.java
index 623ff29..ce26268 100644
--- a/core/java/android/webkit/StreamLoader.java
+++ b/core/java/android/webkit/StreamLoader.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.content.Context;
 import android.net.http.EventHandler;
 import android.net.http.Headers;
 import android.os.Handler;
@@ -52,7 +53,8 @@
     private static final int MSG_DATA = 102;  // Send data to loader
     private static final int MSG_END = 103;  // Send endData to loader
 
-    protected LoadListener mHandler; // loader class
+    protected final Context mContext;
+    protected final LoadListener mHandler; // loader class
     protected InputStream mDataStream; // stream to read data from
     protected long mContentLength; // content length of data
     private byte [] mData; // buffer to pass data to loader with.
@@ -66,6 +68,7 @@
      */
     StreamLoader(LoadListener loadlistener) {
         mHandler = loadlistener;
+        mContext = loadlistener.getContext();
     }
 
     /**
diff --git a/core/java/com/android/internal/app/UsbStorageActivity.java b/core/java/com/android/internal/app/UsbStorageActivity.java
index 37ea352..34ae2b4 100644
--- a/core/java/com/android/internal/app/UsbStorageActivity.java
+++ b/core/java/com/android/internal/app/UsbStorageActivity.java
@@ -24,7 +24,9 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Environment;
 import android.os.IMountService;
+import android.os.MountServiceResultCode;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -116,7 +118,8 @@
             IMountService mountService = IMountService.Stub.asInterface(ServiceManager
                     .getService("mount"));
             if (mountService != null) {
-                umsOn = mountService.getMassStorageEnabled();
+                umsOn = mountService.getVolumeShared(
+                        Environment.getExternalStorageDirectory().getPath(), "ums");
             }
         } catch (android.os.RemoteException exc) {
             // pass
@@ -140,10 +143,13 @@
         }
 
         try {
-            mountService.setMassStorageEnabled(true);
+            if (mountService.shareVolume(
+                    Environment.getExternalStorageDirectory().getPath(), "ums") !=
+                            MountServiceResultCode.OperationSucceeded) {
+                showSharingError();
+            }
         } catch (RemoteException e) {
             showSharingError();
-            return;
         }
     }
 
@@ -156,7 +162,8 @@
         }
 
         try {
-            mountService.setMassStorageEnabled(false);
+            mountService.unshareVolume(
+                    Environment.getExternalStorageDirectory().getPath(), "ums");
         } catch (RemoteException e) {
             showStoppingError();
             return;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDebugTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDebugTest.java
new file mode 100644
index 0000000..ea807bd
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDebugTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for the SQLiteDebug
+ */
+public class SQLiteDebugTest extends TestCase {
+    private static final String TEST_DB = "test.db";
+
+    public void testCaptureSql() {
+        String rslt = SQLiteDebug.captureSql(TEST_DB, "select * from t1 where a=? and b=1",
+                new Object[] {"blah"});
+        String expectedVal = "select * from t1 where a='blah' and b=1";
+        assertTrue(rslt.equals("captured_sql|" + TEST_DB + "|" + expectedVal));
+
+        rslt = SQLiteDebug.captureSql(TEST_DB, "select * from t1 where a=?",
+                new Object[] {"blah"});
+        expectedVal = "select * from t1 where a='blah'";
+        assertTrue(rslt.equals("captured_sql|" + TEST_DB + "|" + expectedVal));
+
+        rslt = SQLiteDebug.captureSql(TEST_DB, "select * from t1 where a=1",
+                new Object[] {"blah"});
+        assertTrue(rslt.startsWith("too many bindArgs provided."));
+
+        rslt = SQLiteDebug.captureSql(TEST_DB, "update t1 set a=? where b=?",
+                new Object[] {"blah", "foo"});
+        expectedVal = "update t1 set a='blah' where b='foo'";
+        assertTrue(rslt.equals("captured_sql|" + TEST_DB + "|" + expectedVal));
+    }
+}
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
index a61cccb..6d3e87c 100644
--- a/media/sdutils/sdutil.cpp
+++ b/media/sdutils/sdutil.cpp
@@ -38,65 +38,27 @@
     }
 }
 
-static bool isMounted(const char* mountPoint) {
-    char s[2000];
-    FILE *f = fopen("/proc/mounts", "r");
-    bool mounted = false;
-
-    while (fgets(s, sizeof(s), f))
-    {
-        char *c, *path = NULL;
-
-        for (c = s; *c; c++) 
-        {
-            if (*c == ' ') 
-            {
-                *c = 0;
-                path = c + 1;
-                break;
-            }
-        }
-
-        for (c = path; *c; c++) 
-        {
-            if (*c == ' ') 
-            {
-                *c = '\0';
-                break;
-            }
-        }
-
-        if (strcmp(mountPoint, path) == 0) {
-            mounted = true;
-            break;
-        }
-    }
-
-    fclose(f);
-    return mounted;
-}
-
-static void millisecondSleep(int milliseconds) {
-	struct timespec reqt, remt;	
-	reqt.tv_sec = milliseconds / 1000;
-	reqt.tv_nsec = 1000000 * (milliseconds % 1000);
-	nanosleep(&reqt, &remt) ;
-
-}
-
 static int mount(const char* path) {
     String16 string(path);
-    gMountService->mountVolume(string);
-    
-    for (int i = 0; i < 60; i++) {
-        if (isMounted(path)) {
-            return 0;
-        }
-        millisecondSleep(500);
-    }
-        
-    fprintf(stderr, "failed to mount %s\n", path);   
-    return -1;
+    return gMountService->mountVolume(string);
+}
+
+static int share(const char *path, const char *method) {
+    String16 sPath(path);
+    String16 sMethod(method);
+    return gMountService->shareVolume(sPath, sMethod);
+}
+
+static int unshare(const char *path, const char *method) {
+    String16 sPath(path);
+    String16 sMethod(method);
+    return gMountService->unshareVolume(sPath, sMethod);
+}
+
+static bool shared(const char *path, const char *method) {
+    String16 sPath(path);
+    String16 sMethod(method);
+    return gMountService->getVolumeShared(sPath, sMethod);
 }
 
 static int asec_create(const char *id, int sizeMb, const char *fstype,
@@ -105,39 +67,35 @@
     String16 sFstype(fstype);
     String16 sKey(key);
 
-    String16 r = gMountService->createSecureContainer(sId, sizeMb, sFstype,
-                                                      sKey, ownerUid);
-    return 0;
+    return gMountService->createSecureContainer(
+            sId, sizeMb, sFstype, sKey, ownerUid);
 }
 
 static int asec_finalize(const char *id) {
     String16 sId(id);
-    gMountService->finalizeSecureContainer(sId);
-    return 0;
+    return gMountService->finalizeSecureContainer(sId);
 }
 
 static int asec_destroy(const char *id) {
     String16 sId(id);
-    gMountService->destroySecureContainer(sId);
-    return 0;
+    return gMountService->destroySecureContainer(sId);
 }
 
 static int asec_mount(const char *id, const char *key, int ownerUid) {
     String16 sId(id);
     String16 sKey(key);
-    gMountService->mountSecureContainer(sId, sKey, ownerUid);
-    return 0;
+    return gMountService->mountSecureContainer(sId, sKey, ownerUid);
 }
 
-static void asec_unmount(const char *id) {
+static int asec_unmount(const char *id) {
     String16 sId(id);
-    gMountService->unmountSecureContainer(sId);
+    return gMountService->unmountSecureContainer(sId);
 }
 
-static void asec_rename(const char *oldId, const char *newId) {
+static int asec_rename(const char *oldId, const char *newId) {
     String16 sOldId(oldId);
     String16 sNewId(newId);
-    gMountService->renameSecureContainer(sOldId, sNewId);
+    return gMountService->renameSecureContainer(sOldId, sNewId);
 }
 
 static int asec_path(const char *id) {
@@ -148,98 +106,85 @@
 
 static int unmount(const char* path) {
     String16 string(path);
-    gMountService->unmountVolume(string);
-
-    for (int i = 0; i < 20; i++) {
-        if (!isMounted(path)) {
-            return 0;
-        }
-        millisecondSleep(500);
-    }
-        
-    fprintf(stderr, "failed to unmount %s\n", path);   
-    return -1;
+    return gMountService->unmountVolume(string);
 }
 
 static int format(const char* path) {
     String16 string(path);
-
-    if (isMounted(path))
-        return -EBUSY;
-    gMountService->formatVolume(string);
-
-    return 0;
-}
-
-static int umsEnable(bool enable) {
-    gMountService->setMassStorageEnabled(enable);
-    return 0;
+    return gMountService->formatVolume(string);
 }
 
 };
 
+static void usage(void);
+
 int main(int argc, char **argv)
 {
-    const char* command = (argc > 1 ? argv[1] : "");
-    const char* argument = (argc > 2 ? argv[2] : "");
+    if (argc < 2)
+        usage();
+
+    android::init();
+    int rc = 0;
     
-    if (strcmp(command, "mount") == 0) {
-        android::init();
-        return android::mount(argument);
-    } else if (strcmp(command, "format") == 0) {
-        android::init();
-        return android::format(argument);
-    } else if (strcmp(command, "unmount") == 0) {
-        android::init();
-        return android::unmount(argument);
-    } else if (strcmp(command, "ums") == 0) {
-        if (strcmp(argument, "enable") == 0) {
-            android::init();
-            return android::umsEnable(true);
-        } else if (strcmp(argument, "disable") == 0) {
-            android::init();
-            return android::umsEnable(false);
-        }
-    } else if (!strcmp(command, "asec")) {
-        const char* id = (argc > 3 ? argv[3] : NULL);
+    if (strcmp(argv[1], "mount") == 0) {
+        rc = android::mount(argv[2]);
+    } else if (strcmp(argv[1], "format") == 0) {
+        rc = android::format(argv[2]);
+    } else if (strcmp(argv[1], "unmount") == 0) {
+        rc = android::unmount(argv[2]);
+    } else if (strcmp(argv[1], "share") == 0) {
+        if (argc != 3)
+            usage();
+        rc = android::share(argv[2], argv[3]);
+    } else if (strcmp(argv[1], "unshare") == 0) {
+        if (argc != 3)
+            usage();
+        rc = android::unshare(argv[2], argv[3]);
+    } else if (strcmp(argv[1], "shared") == 0) {
+        if (argc != 3)
+            usage();
+        fprintf(stdout, "%s\n", (android::shared(argv[2], argv[3]) ? "true" : "false"));
+    } else if (!strcmp(argv[1], "asec")) {
+        if (argc < 3)
+            usage();
 
-        if (!id)
-            goto usage;
-
-        android::init();
-        if (!strcmp(argument, "create")) {
+        if (!strcmp(argv[2], "create")) {
 
             if (argc != 8)
-                goto usage;
-            return android::asec_create(id, atoi(argv[4]), argv[5], argv[6],
-                                        atoi(argv[7]));
-        } else if (!strcmp(argument, "finalize")) {
-            return android::asec_finalize(id);
-        } else if (!strcmp(argument, "destroy")) {
-            return android::asec_destroy(id);
-        } else if (!strcmp(argument, "mount")) {
-            if (argc == 6)
-                return android::asec_mount(id, argv[4], atoi(argv[5]));
-        } else if (!strcmp(argument, "rename")) {
-            if (argc == 5) {
-                android::asec_rename(id, argv[4]);
-                return 0;
-            }
-        } else if (!strcmp(argument, "unmount")) {
-            android::asec_unmount(id);
-            return 0;
-        } else if (!strcmp(argument, "path")) {
-            return android::asec_path(id);
+                usage();
+            rc = android::asec_create(argv[3], atoi(argv[4]), argv[5], argv[6], atoi(argv[7]));
+        } else if (!strcmp(argv[3], "finalize")) {
+            rc = android::asec_finalize(argv[3]);
+        } else if (!strcmp(argv[3], "destroy")) {
+            return android::asec_destroy(argv[3]);
+        } else if (!strcmp(argv[3], "mount")) {
+            if (argc != 6)
+                usage();
+            rc = android::asec_mount(argv[3], argv[4], atoi(argv[5]));
+        } else if (!strcmp(argv[3], "rename")) {
+            if (argc != 5)
+                usage();
+            rc = android::asec_rename(argv[3], argv[4]);
+        } else if (!strcmp(argv[3], "unmount")) {
+            rc = android::asec_unmount(argv[3]);
+        } else if (!strcmp(argv[3], "path")) {
+            rc = android::asec_path(argv[3]);
         }
     }
-    
-usage:
+
+    fprintf(stdout, "Operation completed with code %d\n", rc);
+    return rc;
+}
+
+static void usage()
+{
     fprintf(stderr, "usage:\n"
                     "    sdutil mount <mount path>          - mounts the SD card at the given mount point\n"
                     "    sdutil unmount <mount path>        - unmounts the SD card at the given mount point\n"
                     "    sdutil format <mount path>         - formats the SD card at the given mount point\n"
-                    "    sdutil ums enable                  - enables USB mass storage\n"
-                    "    sdutil ums disable                 - disables USB mass storage\n"
+                    "    sdutil share <path> <method>       - shares a volume\n"
+                    "    sdutil unshare <path> <method>     - unshares a volume\n"
+                    "    sdutil shared <path> <method>      - Queries volume share state\n"
                     "    sdutil asec create <id> <sizeMb> <fstype> <key> <ownerUid>\n"
                     "    sdutil asec finalize <id>\n"
                     "    sdutil asec destroy <id>\n"
@@ -248,5 +193,5 @@
                     "    sdutil asec rename <oldId, newId>\n"
                     "    sdutil asec path <id>\n"
                     );
-    return -1;
+    exit(1);
 }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index d36207b..b07d6e4 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -7,6 +7,7 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.IMountService;
+import android.os.MountServiceResultCode;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
@@ -147,43 +148,35 @@
         String cachePath = null;
         int ownerUid = Process.myUid();
         try {
-            cachePath = mountService.createSecureContainer(containerId,
-                mbLen,
-                "vfat", sdEncKey, ownerUid);
+            int rc = mountService.createSecureContainer(
+                    containerId, mbLen, "vfat", sdEncKey, ownerUid);
+
+            if (rc != MountServiceResultCode.OperationSucceeded) {
+                Log.e(TAG, String.format("Container creation failed (%d)", rc));
+
+                // XXX: This destroy should not be necessary
+                rc = mountService.destroySecureContainer(containerId);
+                if (rc != MountServiceResultCode.OperationSucceeded) {
+                    Log.e(TAG, String.format("Container creation-cleanup failed (%d)", rc));
+                    return null;
+                }
+
+                // XXX: Does this ever actually succeed?
+                rc = mountService.createSecureContainer(
+                        containerId, mbLen, "vfat", sdEncKey, ownerUid);
+                if (rc != MountServiceResultCode.OperationSucceeded) {
+                    Log.e(TAG, String.format("Container creation retry failed (%d)", rc));
+                }
+            }
+
+            cachePath = mountService.getSecureContainerPath(containerId);
             if (localLOGV) Log.i(TAG, "Trying to create secure container for  "
                     + containerId + ", cachePath =" + cachePath);
             return cachePath;
-        } catch(IllegalStateException e) {
-            Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
         } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
+            Log.e(TAG, "MountService not running?");
             return null;
         }
-        // TODO just fail here and let the user delete later on.
-        try {
-            mountService.destroySecureContainer(containerId);
-            if (localLOGV) Log.i(TAG, "Destroying cache for " + containerId
-                    + ", cachePath =" + cachePath);
-        } catch(IllegalStateException e) {
-            Log.e(TAG, "Failed to destroy existing cache: " + e);
-            return null;
-        } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
-            return null;
-        }
-       try {
-            cachePath = mountService.createSecureContainer(containerId,
-                mbLen,
-                "vfat", sdEncKey, ownerUid);
-            if (localLOGV) Log.i(TAG, "Trying to install again " + containerId
-                   + ", cachePath =" + cachePath);
-            return cachePath;
-        } catch(IllegalStateException e) {
-            Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
-        } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
-        }
-        return null;
     }
 
     private boolean destroySdDir(String containerId) {
@@ -194,7 +187,7 @@
         } catch (IllegalStateException e) {
             Log.i(TAG, "Failed to destroy container : " + containerId);
         } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
+            Log.e(TAG, "MountService not running?");
         }
         return false;
     }
@@ -206,7 +199,7 @@
         } catch (IllegalStateException e) {
             Log.i(TAG, "Failed to finalize container for pkg : " + containerId);
         } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
+            Log.e(TAG, "MountService not running?");
         }
         return false;
     }
@@ -218,19 +211,21 @@
         } catch (IllegalStateException e) {
             Log.e(TAG, "Failed to unmount id:  " + containerId + " with exception " + e);
         } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
+            Log.e(TAG, "MountService not running?");
         }
         return false;
     }
 
     private String mountSdDir(String containerId, String key) {
         try {
-            return getMountService().mountSecureContainer(containerId, key, Process.myUid());
-        } catch (IllegalStateException e) {
-            Log.e(TAG, "Failed to mount id: " +
-                    containerId + " with exception " + e);
+            int rc = getMountService().mountSecureContainer(containerId, key, Process.myUid());
+            if (rc == MountServiceResultCode.OperationSucceeded) {
+                return getMountService().getSecureContainerPath(containerId);
+            } else {
+                Log.e(TAG, String.format("Failed to mount id %s with rc %d ", containerId, rc));
+            }
         } catch(RemoteException e) {
-            Log.e(TAG, "MounteService not running?");
+            Log.e(TAG, "MountService not running?");
         }
         return null;
     }
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 05cea46..6382646 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -16,9 +16,6 @@
 
 package com.android.server;
 
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -27,6 +24,10 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.IMountService;
+import android.os.IMountServiceListener;
+import android.os.MountServiceResultCode;
+import android.os.RemoteException;
+import android.os.IBinder;
 import android.os.Environment;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -36,13 +37,8 @@
 import android.util.Log;
 import java.util.ArrayList;
 
-import android.provider.Settings;
-import android.content.ContentResolver;
-import android.database.ContentObserver;
-
 import java.io.File;
 import java.io.FileReader;
-import java.lang.IllegalStateException;
 
 /**
  * MountService implements an to the mount service daemon
@@ -53,6 +49,9 @@
     
     private static final String TAG = "MountService";
 
+    /*
+     * Internal vold volume state constants
+     */
     class VolumeState {
         public static final int Init       = -1;
         public static final int NoMedia    = 0;
@@ -66,73 +65,50 @@
         public static final int SharedMnt  = 8;
     }
 
+    /*
+     * Internal vold response code constants
+     */
     class VoldResponseCode {
+        /*
+         * 100 series - Requestion action was initiated; expect another reply
+         *              before proceeding with a new command.
+         */
         public static final int VolumeListResult               = 110;
         public static final int AsecListResult                 = 111;
 
-        public static final int ShareAvailabilityResult        = 210;
+        /*
+         * 200 series - Requestion action has been successfully completed.
+         */
+        public static final int ShareStatusResult              = 210;
         public static final int AsecPathResult                 = 211;
+        public static final int ShareEnabledResult             = 212;
 
+        /*
+         * 400 series - Command was accepted, but the requested action
+         *              did not take place.
+         */
+        public static final int OpFailedNoMedia                = 401;
+        public static final int OpFailedMediaBlank             = 402;
+        public static final int OpFailedMediaCorrupt           = 403;
+        public static final int OpFailedVolNotMounted          = 404;
+        public static final int OpFailedVolBusy                = 405;
+
+        /*
+         * 600 series - Unsolicited broadcasts.
+         */
         public static final int VolumeStateChange              = 605;
-        public static final int VolumeMountFailedBlank         = 610;
-        public static final int VolumeMountFailedDamaged       = 611;
-        public static final int VolumeMountFailedNoMedia       = 612;
         public static final int ShareAvailabilityChange        = 620;
         public static final int VolumeDiskInserted             = 630;
         public static final int VolumeDiskRemoved              = 631;
         public static final int VolumeBadRemoval               = 632;
     }
 
-
-    /**
-     * Binder context for this service
-     */
-    private Context mContext;
-    
-    /**
-     * connectorr object for communicating with vold
-     */
-    private NativeDaemonConnector mConnector;
-
-    /**
-     * The notification that is shown when a USB mass storage host
-     * is connected. 
-     * <p>
-     * This is lazily created, so use {@link #setUsbStorageNotification()}.
-     */
-    private Notification mUsbStorageNotification;
-
-
-    /**
-     * The notification that is shown when the following media events occur:
-     *     - Media is being checked
-     *     - Media is blank (or unknown filesystem)
-     *     - Media is corrupt
-     *     - Media is safe to unmount
-     *     - Media is missing
-     * <p>
-     * This is lazily created, so use {@link #setMediaStorageNotification()}.
-     */
-    private Notification mMediaStorageNotification;
-    
-    private boolean mShowSafeUnmountNotificationWhenUnmounted;
-
-    private boolean mPlaySounds;
-
-    private boolean mMounted;
-
-    private SettingsWatcher mSettingsWatcher;
-    private boolean mAutoStartUms;
-    private boolean mPromptUms;
-    private boolean mUmsActiveNotify;
-
-    private boolean mUmsConnected = false;
-    private boolean mUmsEnabled = false;
-    private boolean mUmsEnabling = false;
-
-    private String  mLegacyState = Environment.MEDIA_REMOVED;
-
-    private PackageManagerService mPms;
+    private Context                               mContext;
+    private NativeDaemonConnector                 mConnector;
+    private String                                mLegacyState = Environment.MEDIA_REMOVED;
+    private PackageManagerService                 mPms;
+    private boolean                               mUmsEnabling;
+    private ArrayList<MountServiceBinderListener> mListeners;
 
     /**
      * Constructs a new MountService instance
@@ -142,7 +118,9 @@
     public MountService(Context context) {
         mContext = context;
 
+        // XXX: This will go away soon in favor of IMountServiceObserver
         mPms = (PackageManagerService) ServiceManager.getService("package");
+
         // Register a BOOT_COMPLETED handler so that we can start
         // our NativeDaemonConnector. We defer the startup so that we don't
         // start processing events before we ought-to
@@ -150,78 +128,9 @@
                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
 
         mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
-        mShowSafeUnmountNotificationWhenUnmounted = false;
-
-        mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
-
-        ContentResolver cr = mContext.getContentResolver();
-        mAutoStartUms = (Settings.Secure.getInt(
-                cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
-        mPromptUms = (Settings.Secure.getInt(
-                cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
-        mUmsActiveNotify = (Settings.Secure.getInt(
-                cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
-
-        mSettingsWatcher = new SettingsWatcher(new Handler());
+        mListeners = new ArrayList<MountServiceBinderListener>();
     }
   
-    private class SettingsWatcher extends ContentObserver {
-        public SettingsWatcher(Handler handler) {
-            super(handler);
-            ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(Settings.System.getUriFor(
-                    Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND), false, this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.MOUNT_UMS_AUTOSTART), false, this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.MOUNT_UMS_PROMPT), false, this);
-            cr.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED), false, this);
-        }
-
-        public void onChange(boolean selfChange) {
-            super.onChange(selfChange);
-            ContentResolver cr = mContext.getContentResolver();
-
-            boolean newPlayNotificationSounds = (Settings.Secure.getInt(
-                    cr, Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND, 1) == 1);
-
-            boolean newUmsAutostart = (Settings.Secure.getInt(
-                    cr, Settings.Secure.MOUNT_UMS_AUTOSTART, 0) == 1);
-
-            if (newUmsAutostart != mAutoStartUms) {
-                mAutoStartUms = newUmsAutostart;
-            }
-
-            boolean newUmsPrompt = (Settings.Secure.getInt(
-                    cr, Settings.Secure.MOUNT_UMS_PROMPT, 1) == 1);
-
-            if (newUmsPrompt != mPromptUms) {
-                mPromptUms = newUmsAutostart;
-            }
-
-            boolean newUmsNotifyEnabled = (Settings.Secure.getInt(
-                    cr, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED, 1) == 1);
-
-            if (mUmsEnabled) {
-                if (newUmsNotifyEnabled) {
-                    Intent intent = new Intent();
-                    intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
-                    PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-                    setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
-                            com.android.internal.R.string.usb_storage_stop_notification_message,
-                            com.android.internal.R.drawable.stat_sys_warning,
-                            false, true, pi);
-                } else {
-                    setUsbStorageNotification(0, 0, 0, false, false, null);
-                }
-            }
-            if (newUmsNotifyEnabled != mUmsActiveNotify) {
-                mUmsActiveNotify = newUmsNotifyEnabled;
-            }
-        }
-    }
-
     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -232,8 +141,7 @@
                  * event to trigger MediaScanner
                  */
                 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
-                    notifyMediaMounted(
-                            Environment.getExternalStorageDirectory().getPath(), false);
+                    updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED);
                     return;
                 }
 
@@ -244,15 +152,394 @@
         }
     };
 
-    public void shutdown() {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.SHUTDOWN)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires SHUTDOWN permission");
+    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
+        final IMountServiceListener mListener;
+
+        MountServiceBinderListener(IMountServiceListener listener) {
+            mListener = listener;
+ 
         }
 
-        Log.d(TAG, "Shutting down");
-        String state = Environment.getExternalStorageState();
+        public void binderDied() {
+            Log.d(TAG, "An IMountServiceListener has died!");
+            synchronized(mListeners) {
+                mListeners.remove(this);
+                mListener.asBinder().unlinkToDeath(this, 0);
+            }
+        }
+    }
+
+    int doShareUnshareVolume(String path, String method, boolean enable) {
+        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+
+        // TODO: Add support for multiple share methods
+        if (!method.equals("ums")) {
+            throw new IllegalArgumentException(String.format("Method %s not supported", method));
+        }
+
+        /*
+         * If the volume is mounted and we're enabling then unmount it
+         */
+        String vs = getVolumeState(path);
+        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
+            mUmsEnabling = enable; // Supress unmounted events
+            unmountVolume(path);
+            mUmsEnabling = false; // Unsupress unmounted events
+        }
+
+        try {
+            mConnector.doCommand(String.format(
+                    "volume %sshare %s %s", (enable ? "" : "un"), path, method));
+        } catch (NativeDaemonConnectorException e) {
+            Log.e(TAG, "Failed to share/unshare", e);
+            return MountServiceResultCode.OperationFailedInternalError;
+        }
+
+        /*
+         * If we disabled UMS then mount the volume
+         */
+        if (!enable) {
+            if (mountVolume(path) != MountServiceResultCode.OperationSucceeded) {
+                Log.e(TAG, String.format(
+                        "Failed to remount %s after disabling share method %s", path, method));
+                /*
+                 * Even though the mount failed, the unshare didn't so don't indicate an error.
+                 * The mountVolume() call will have set the storage state and sent the necessary
+                 * broadcasts.
+                 */
+            }
+        }
+
+        return MountServiceResultCode.OperationSucceeded;
+    }
+
+    void updatePublicVolumeState(String path, String state) {
+        if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
+            Log.w(TAG, "Multiple volumes not currently supported");
+            return;
+        }
+        Log.i(TAG, "State for {" + path + "} = {" + state + "}");
+
+        String oldState = mLegacyState;
+        mLegacyState = state;
+
+        synchronized (mListeners) {
+            for (int i = mListeners.size() -1; i >= 0; i--) {
+                MountServiceBinderListener bl = mListeners.get(i);
+                try {
+                    bl.mListener.onVolumeStateChanged("", path, oldState, state);
+                } catch (RemoteException rex) {
+                    Log.e(TAG, "Listener dead");
+                    mListeners.remove(i);
+                } catch (Exception ex) {
+                    Log.e(TAG, "Listener failed", ex);
+                }
+            }
+        }
+    }
+
+    /**
+     *
+     * Callback from NativeDaemonConnector
+     */
+    public void onDaemonConnected() {
+        /*
+         * Since we'll be calling back into the NativeDaemonConnector,
+         * we need to do our work in a new thread.
+         */
+        new Thread() {
+            public void run() {
+                /**
+                 * Determine media state and UMS detection status
+                 */
+                String path = Environment.getExternalStorageDirectory().getPath();
+                String state = Environment.MEDIA_REMOVED;
+
+                try {
+                    String[] vols = mConnector.doListCommand(
+                        "volume list", VoldResponseCode.VolumeListResult);
+                    for (String volstr : vols) {
+                        String[] tok = volstr.split(" ");
+                        // FMT: <label> <mountpoint> <state>
+                        if (!tok[1].equals(path)) {
+                            Log.w(TAG, String.format(
+                                    "Skipping unknown volume '%s'",tok[1]));
+                            continue;
+                        }
+                        int st = Integer.parseInt(tok[2]);
+                        if (st == VolumeState.NoMedia) {
+                            state = Environment.MEDIA_REMOVED;
+                        } else if (st == VolumeState.Idle) {
+                            state = null;
+                            int rc = mountVolume(path);
+                            if (rc != MountServiceResultCode.OperationSucceeded) {
+                                Log.e(TAG, String.format("Connection-mount failed (%d)", rc));
+                            }
+                        } else if (st == VolumeState.Mounted) {
+                            state = Environment.MEDIA_MOUNTED;
+                            Log.i(TAG, "Media already mounted on daemon connection");
+                        } else if (st == VolumeState.Shared) {
+                            state = Environment.MEDIA_SHARED;
+                            Log.i(TAG, "Media shared on daemon connection");
+                        } else {
+                            throw new Exception(String.format("Unexpected state %d", st));
+                        }
+                    }
+                    if (state != null) {
+                        updatePublicVolumeState(path, state);
+                    }
+                } catch (Exception e) {
+                    Log.e(TAG, "Error processing initial volume state", e);
+                    updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
+                }
+
+                try {
+                    boolean avail = getShareMethodAvailable("ums");
+                    notifyShareAvailabilityChange("ums", avail);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Failed to get share availability");
+                }
+            }
+        }.start();
+    }
+
+    /**
+     *
+     * 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.
+             * Format: "NNN Volume <label> <path> state changed
+             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
+             */
+            notifyVolumeStateChange(
+                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
+                            Integer.parseInt(cooked[10]));
+        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
+            // FMT: NNN Share method <method> now <available|unavailable>
+            boolean avail = false;
+            if (cooked[5].equals("available")) {
+                avail = true;
+            }
+            notifyShareAvailabilityChange(cooked[3], avail);
+        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
+                   (code == VoldResponseCode.VolumeDiskRemoved) ||
+                   (code == VoldResponseCode.VolumeBadRemoval)) {
+            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
+            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
+            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
+            final String label = cooked[2];
+            final String path = cooked[3];
+            int major = -1;
+            int minor = -1;
+
+            try {
+                String devComp = cooked[6].substring(1, cooked[6].length() -1);
+                String[] devTok = devComp.split(":");
+                major = Integer.parseInt(devTok[0]);
+                minor = Integer.parseInt(devTok[1]);
+            } catch (Exception ex) {
+                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 = mountVolume(path)) != MountServiceResultCode.OperationSucceeded) {
+                                Log.w(TAG, String.format("Insertion mount failed (%d)", rc));
+                            }
+                        } catch (Exception ex) {
+                            Log.w(TAG, "Failed to mount media on insertion", ex);
+                        }
+                    }
+                }.start();
+            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
+                /*
+                 * This event gets trumped if we're already in BAD_REMOVAL state
+                 */
+                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
+                    return true;
+                }
+                /* Send the media unmounted event first */
+                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+                mContext.sendBroadcast(in);
+
+                updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
+                in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
+            } else if (code == VoldResponseCode.VolumeBadRemoval) {
+                /* Send the media unmounted event first */
+                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+                mContext.sendBroadcast(in);
+
+                updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
+                in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
+            } else {
+                Log.e(TAG, String.format("Unknown code {%d}", code));
+            }
+        } else {
+            return false;
+        }
+
+        if (in != null) {
+            mContext.sendBroadcast(in);
+	}
+       return true;
+    }
+
+    void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
+        String vs = getVolumeState(path);
+
+        Intent in = null;
+
+        if (newState == VolumeState.Init) {
+        } else if (newState == VolumeState.NoMedia) {
+            // NoMedia is handled via Disk Remove events
+        } else if (newState == VolumeState.Idle) {
+            /*
+             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
+             * if we're in the process of enabling UMS
+             */
+            if (!vs.equals(
+                    Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
+                            Environment.MEDIA_NOFS) && !vs.equals(
+                                    Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) {
+                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+            }
+        } else if (newState == VolumeState.Pending) {
+        } else if (newState == VolumeState.Checking) {
+            updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
+            in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
+        } else if (newState == VolumeState.Mounted) {
+            updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
+            // Update media status on PackageManagerService to mount packages on sdcard
+            mPms.updateExternalMediaStatus(true);
+            in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
+            in.putExtra("read-only", false);
+        } else if (newState == VolumeState.Unmounting) {
+            mPms.updateExternalMediaStatus(false);
+            in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
+        } else if (newState == VolumeState.Formatting) {
+        } else if (newState == VolumeState.Shared) {
+            /* Send the media unmounted event first */
+            updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
+            in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
+            mContext.sendBroadcast(in);
+
+            updatePublicVolumeState(path, Environment.MEDIA_SHARED);
+            in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
+        } else if (newState == VolumeState.SharedMnt) {
+            Log.e(TAG, "Live shared mounts not supported yet!");
+            return;
+        } else {
+            Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
+        }
+
+        if (in != null) {
+            mContext.sendBroadcast(in);
+        }
+    }
+
+    void notifyShareAvailabilityChange(String method, final boolean avail) {
+        if (!method.equals("ums")) {
+           Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
+           return;
+        }
+
+        synchronized (mListeners) {
+            for (int i = mListeners.size() -1; i >= 0; i--) {
+                MountServiceBinderListener bl = mListeners.get(i);
+                try {
+                    bl.mListener.onShareAvailabilityChanged(method, avail);
+                } catch (RemoteException rex) {
+                    Log.e(TAG, "Listener dead");
+                    mListeners.remove(i);
+                } catch (Exception ex) {
+                    Log.e(TAG, "Listener failed", ex);
+                }
+            }
+        }
+
+        Intent intent;
+        if (avail) {
+            intent = new Intent(Intent.ACTION_UMS_CONNECTED);
+        } else {
+            intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
+        }
+        mContext.sendBroadcast(intent);
+    }
+
+    void validatePermission(String perm) {
+        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(String.format("Requires %s permission", perm));
+        }
+    }
+
+    /**
+     * Exposed API calls below here
+     */
+
+    public void registerListener(IMountServiceListener listener) {
+        synchronized (mListeners) {
+            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
+            try {
+                listener.asBinder().linkToDeath(bl, 0);
+                mListeners.add(bl);
+            } catch (RemoteException rex) {
+                Log.e(TAG, "Failed to link to listener death");
+            }
+        }
+    }
+
+    public void unregisterListener(IMountServiceListener listener) {
+        synchronized (mListeners) {
+            for(MountServiceBinderListener bl : mListeners) {
+                if (bl.mListener == listener) {
+                    mListeners.remove(mListeners.indexOf(bl));
+                    return;
+                }
+            }
+        }
+    }
+
+    public void shutdown() {
+        validatePermission(android.Manifest.permission.SHUTDOWN);
+
+        Log.i(TAG, "Shutting down");
+
+        String path = Environment.getExternalStorageDirectory().getPath();
+        String state = getVolumeState(path);
 
         if (state.equals(Environment.MEDIA_SHARED)) {
             /*
@@ -262,10 +549,8 @@
              * the UMS host could have dirty FAT cache entries
              * yet to flush.
              */
-            try {
-               setMassStorageEnabled(false);
-            } catch (Exception e) {
-                Log.e(TAG, "ums disable failed", e);
+            if (unshareVolume(path, "ums") != MountServiceResultCode.OperationSucceeded) {
+                Log.e(TAG, "UMS disable on shutdown failed");
             }
         } else if (state.equals(Environment.MEDIA_CHECKING)) {
             /*
@@ -292,86 +577,81 @@
             /*
              * If the media is mounted, then gracefully unmount it.
              */
+            if (unmountVolume(path) != MountServiceResultCode.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) {
+        ArrayList<String> rsp = mConnector.doCommand("share status " + method);
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code;
             try {
-                String m = Environment.getExternalStorageDirectory().toString();
-                unmountVolume(m);
-
-                int retries = 12;
-                while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
-                    try {
-                        Thread.sleep(1000);
-                    } catch (InterruptedException iex) {
-                        Log.e(TAG, "Interrupted while waiting for media", iex);
-                        break;
-                    }
-                    state = Environment.getExternalStorageState();
-                }
-                if (retries == 0) {
-                    Log.e(TAG, "Timed out waiting for media to unmount");
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "external storage unmount failed", e);
+                code = Integer.parseInt(tok[0]);
+            } catch (NumberFormatException nfe) {
+                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
+                return false;
+            }
+            if (code == VoldResponseCode.ShareStatusResult) {
+                if (tok[2].equals("available"))
+                    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;
     }
 
-    /**
-     * @return true if USB mass storage support is enabled.
-     */
-    public boolean getMassStorageEnabled() {
-        return mUmsEnabled;
+    public int shareVolume(String path, String method) {
+        return doShareUnshareVolume(path, method, true);
     }
 
-    /**
-     * Enables or disables USB mass storage support.
-     * 
-     * @param enable  true to enable USB mass storage support
-     */
-    public void setMassStorageEnabled(boolean enable) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
-        }
-        try {
-            String vp = Environment.getExternalStorageDirectory().getPath();
-            String vs = getVolumeState(vp);
+    public int unshareVolume(String path, String method) {
+        return doShareUnshareVolume(path, method, false);
+    }
 
-            mUmsEnabling = enable;
-            if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
-                unmountVolume(vp);
-                mUmsEnabling = false;
-                updateUsbMassStorageNotification(true, false);
+    public boolean getVolumeShared(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;
             }
-
-            setShareMethodEnabled(vp, "ums", enable);
-            mUmsEnabled = enable;
-            mUmsEnabling = false;
-            if (!enable) {
-                mountVolume(vp);
-                if (mPromptUms) {
-                    updateUsbMassStorageNotification(false, false);
-                } else {
-                    updateUsbMassStorageNotification(true, 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;
             }
-        } catch (IllegalStateException rex) {
-            Log.e(TAG, "Failed to set ums enable {" + enable + "}");
-            return;
         }
+        Log.e(TAG, "Got an empty response");
+        return false;
     }
-
-    /**
-     * @return true if USB mass storage is connected.
-     */
-    public boolean getMassStorageConnected() {
-        return mUmsConnected;
-    }
-
+    
     /**
      * @return state of the volume at the specified mount point
      */
-    public String getVolumeState(String mountPoint) throws IllegalStateException {
+    public String getVolumeState(String mountPoint) {
         /*
          * XXX: Until we have multiple volume discovery, just hardwire
          * this to /sdcard
@@ -388,755 +668,186 @@
     /**
      * Attempt to mount external media
      */
-    public void mountVolume(String mountPath) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) 
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
+    public int mountVolume(String path) {
+        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+
+        int rc = MountServiceResultCode.OperationSucceeded;
+
+        try {
+            mConnector.doCommand(String.format("volume mount %s", path));
+        } catch (NativeDaemonConnectorException e) {
+            /*
+             * Mount failed for some reason
+             */
+            Intent in = null;
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedNoMedia) {
+                /*
+                 * Attempt to mount but no media inserted
+                 */
+                rc = MountServiceResultCode.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;
+            } 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;
+            } else {
+                rc = MountServiceResultCode.OperationFailedInternalError;
+            }
+
+            /*
+             * Send broadcast intent (if required for the failure)
+             */
+            if (in != null) {
+                mContext.sendBroadcast(in);
+            }
         }
-        mConnector.doCommand(String.format("mount %s", mountPath));
+
+        return rc;
     }
 
     /**
      * Attempt to unmount external media to prepare for eject
      */
-    public void unmountVolume(String mountPath) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) 
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
-        }
-
-        // Set a flag so that when we get the unmounted event, we know
-        // to display the notification
-        mShowSafeUnmountNotificationWhenUnmounted = true;
-
-        mConnector.doCommand(String.format("unmount %s", mountPath));
-    }
-
-    /**
-     * Attempt to format external media
-     */
-    public void formatVolume(String formatPath) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS) 
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission");
-        }
-
-        mConnector.doCommand(String.format("format %s", formatPath));
-    }
-
-    boolean getShareAvailable(String method) throws IllegalStateException  {
-        ArrayList<String> rsp = mConnector.doCommand("share_available " + method);
-
-        for (String line : rsp) {
-            String []tok = line.split(" ");
-            int code = Integer.parseInt(tok[0]);
-            if (code == VoldResponseCode.ShareAvailabilityResult) {
-                if (tok[2].equals("available"))
-                    return true;
-                return false;
-            } else {
-                throw new IllegalStateException(String.format("Unexpected response code %d", code));
-            }
-        }
-        throw new IllegalStateException("Got an empty response");
-    }
-
-    /**
-     * Enables or disables USB mass storage support.
-     * 
-     * @param enable  true to enable USB mass storage support
-     */
-    void setShareMethodEnabled(String mountPoint, String method,
-                               boolean enable) throws IllegalStateException {
-        mConnector.doCommand(String.format(
-                "%sshare %s %s", (enable ? "" : "un"), mountPoint, method));
-    }
-
-
-    /**
-     * Returns true if we're playing media notification sounds.
-     */
-    public boolean getPlayNotificationSounds() {
-        return mPlaySounds;
-    }
-
-    /**
-     * Set whether or not we're playing media notification sounds.
-     */
-    public void setPlayNotificationSounds(boolean enabled) {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.WRITE_SETTINGS) 
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires WRITE_SETTINGS permission");
-        }
-        mPlaySounds = enabled;
-        SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0"));
-    }
-
-    void updatePublicVolumeState(String mountPoint, String state) {
-        if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
-            Log.w(TAG, "Multiple volumes not currently supported");
-            return;
-        }
-        Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}");
-        mLegacyState = state;
-    }
-
-    /**
-     * Update the state of the USB mass storage notification
-     */
-    void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
+    public int unmountVolume(String path) {
+        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
 
         try {
-
-            if (getMassStorageConnected() && !suppressIfConnected) {
-                Intent intent = new Intent();
-                intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-                setUsbStorageNotification(
-                        com.android.internal.R.string.usb_storage_notification_title,
-                        com.android.internal.R.string.usb_storage_notification_message,
-                        com.android.internal.R.drawable.stat_sys_data_usb,
-                        sound, true, pi);
+            mConnector.doCommand(String.format("volume unmount %s", path));
+            return MountServiceResultCode.OperationSucceeded;
+        } catch (NativeDaemonConnectorException e) {
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedVolNotMounted) {
+                return MountServiceResultCode.OperationFailedVolumeNotMounted;
             } else {
-                setUsbStorageNotification(0, 0, 0, false, false, null);
+                return MountServiceResultCode.OperationFailedInternalError;
             }
-        } catch (IllegalStateException e) {
-            // Nothing to do
-        }
-    }
-
-    void handlePossibleExplicitUnmountBroadcast(String path) {
-        if (mMounted) {
-            mMounted = false;
-            // Update media status on PackageManagerService to unmount packages on sdcard
-            mPms.updateExternalMediaStatus(false);
-            Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, 
-                    Uri.parse("file://" + path));
-            mContext.sendBroadcast(intent);
         }
     }
 
     /**
+     * Synchronously formats a volume
      *
-     * Callback from NativeDaemonConnector
+     * @param path The volume path to format
+     * @return Error code from MountServiceResultCode
      */
-    public void onDaemonConnected() {
-        /*
-         * Since we'll be calling back into the NativeDaemonConnector,
-         * we need to do our work in a new thread.
-         */
-        new Thread() {
-            public void run() {
-                /**
-                 * Determine media state and UMS detection status
-                 */
-                String path = Environment.getExternalStorageDirectory().getPath();
-                String state = Environment.MEDIA_REMOVED;
+    public int formatVolume(String path) {
+        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
 
-                try {
-                    String[] vols = mConnector.doListCommand(
-                        "list_volumes", VoldResponseCode.VolumeListResult);
-                    for (String volstr : vols) {
-                        String[] tok = volstr.split(" ");
-                        // FMT: <label> <mountpoint> <state>
-                        if (!tok[1].equals(path)) {
-                            Log.w(TAG, String.format(
-                                    "Skipping unknown volume '%s'",tok[1]));
-                            continue;
-                        }
-                        int st = Integer.parseInt(tok[2]);
-                        if (st == VolumeState.NoMedia) {
-                            state = Environment.MEDIA_REMOVED;
-                        } else if (st == VolumeState.Idle) {
-                            state = null;
-                            try {
-                                mountVolume(path);
-                            } catch (Exception ex) {
-                                Log.e(TAG, "Connection-mount failed", ex);
-                            }
-                        } else if (st == VolumeState.Mounted) {
-                            state = Environment.MEDIA_MOUNTED;
-                            Log.i(TAG, "Media already mounted on daemon connection");
-                        } else if (st == VolumeState.Shared) {
-                            state = Environment.MEDIA_SHARED;
-                            Log.i(TAG, "Media shared on daemon connection");
-                        } else {
-                            throw new Exception(String.format("Unexpected state %d", st));
-                        }
-                    }
-                    if (state != null) {
-                        updatePublicVolumeState(path, state);
-                    }
-                } catch (Exception e) {
-                    Log.e(TAG, "Error processing initial volume state", e);
-                    updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
-                }
-
-                try {
-                    boolean avail = getShareAvailable("ums");
-                    notifyShareAvailabilityChange("ums", avail);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Failed to get share availability");
-                }
-            }
-        }.start();
-    }
-
-    /**
-     *
-     * Callback from NativeDaemonConnector
-     */
-    public boolean onEvent(int code, String raw, String[] cooked) {
-        // Log.d(TAG, "event {" + raw + "}");
-        if (code == VoldResponseCode.VolumeStateChange) {
-            // FMT: NNN Volume <label> <mountpoint> state changed
-            // from <old_#> (<old_str>) to <new_#> (<new_str>)
-            notifyVolumeStateChange(
-                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
-                            Integer.parseInt(cooked[10]));
-        } else if (code == VoldResponseCode.VolumeMountFailedBlank) {
-            // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
-            notifyMediaNoFs(cooked[3]);
-            // FMT: NNN Volume <label> <mountpoint> mount failed - no media
-        } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) {
-            notifyMediaRemoved(cooked[3]);
-        } else if (code == VoldResponseCode.VolumeMountFailedDamaged) {
-            // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
-            notifyMediaUnmountable(cooked[3]);
-        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
-            // FMT: NNN Share method <method> now <available|unavailable>
-            boolean avail = false;
-            if (cooked[5].equals("available")) {
-                avail = true;
-            }
-            notifyShareAvailabilityChange(cooked[3], avail);
-        } else if (code == VoldResponseCode.VolumeDiskInserted) {
-            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
-            notifyMediaInserted(cooked[3]);
-        } else if (code == VoldResponseCode.VolumeDiskRemoved) {
-            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
-            notifyMediaRemoved(cooked[3]);
-        } else if (code == VoldResponseCode.VolumeBadRemoval) {
-            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
-            notifyMediaBadRemoval(cooked[3]);
-        } else {
-            return false;
-        }
-       return true;
-    }
-
-    void notifyVolumeStateChange(String label, String mountPoint, int oldState,
-                                 int newState) throws IllegalStateException {
-        String vs = getVolumeState(mountPoint);
-
-        if (newState == VolumeState.Init) {
-        } else if (newState == VolumeState.NoMedia) {
-            // NoMedia is handled via Disk Remove events
-        } else if (newState == VolumeState.Idle) {
-            /*
-             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
-             * if we're in the process of enabling UMS
-             */
-            if (!vs.equals(Environment.MEDIA_BAD_REMOVAL) &&
-                !vs.equals(Environment.MEDIA_NOFS) &&
-                !vs.equals(Environment.MEDIA_UNMOUNTABLE) &&
-                !mUmsEnabling) {
-                notifyMediaUnmounted(mountPoint);
-            }
-        } else if (newState == VolumeState.Pending) {
-        } else if (newState == VolumeState.Checking) {
-            notifyMediaChecking(mountPoint);
-        } else if (newState == VolumeState.Mounted) {
-            notifyMediaMounted(mountPoint, false);
-        } else if (newState == VolumeState.Unmounting) {
-            notifyMediaUnmounting(mountPoint);
-        } else if (newState == VolumeState.Formatting) {
-        } else if (newState == VolumeState.Shared) {
-            notifyMediaShared(mountPoint, false);
-        } else if (newState == VolumeState.SharedMnt) {
-            notifyMediaShared(mountPoint, true);
-        } else {
-            Log.e(TAG, "Unhandled VolumeState {" + newState + "}");
-        }
-    }
-
-
-    /**
-     * Broadcasts the USB mass storage connected event to all clients.
-     */
-    void notifyUmsConnected() {
-        mUmsConnected = true;
-
-        String storageState = Environment.getExternalStorageState();
-        if (!storageState.equals(Environment.MEDIA_REMOVED) &&
-            !storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
-            !storageState.equals(Environment.MEDIA_CHECKING)) {
-
-            if (mAutoStartUms) {
-                try {
-                    setMassStorageEnabled(true);
-                } catch (IllegalStateException e) {
-                }
-            } else if (mPromptUms) {
-                updateUsbMassStorageNotification(false, true);
-            }
-        }
-
-        Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
-        mContext.sendBroadcast(intent);
-    }
-
-    void notifyShareAvailabilityChange(String method, final boolean avail) {
-        if (!method.equals("ums")) {
-           Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
-           return;
-        }
-
-        /*
-         * Notification needs to run in a different thread as
-         * it may need to call back into vold
-         */
-        new Thread() {
-            public void run() {
-                try {
-                    if (avail) {
-                        notifyUmsConnected();
-                    } else {
-                        notifyUmsDisconnected();
-                    }
-                } catch (Exception ex) {
-                    Log.w(TAG, "Failed to mount media on insertion");
-                }
-            }
-        }.start();
-    }
-
-    /**
-     * Broadcasts the USB mass storage disconnected event to all clients.
-     */
-    void notifyUmsDisconnected() {
-        mUmsConnected = false;
-        if (mUmsEnabled) {
-            try {
-                Log.w(TAG, "UMS disconnected while enabled!");
-                setMassStorageEnabled(false);
-            } catch (Exception ex) {
-                Log.e(TAG, "Error disabling UMS on unsafe UMS disconnect", ex);
-            }
-        }
-        updateUsbMassStorageNotification(false, false);
-        Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
-        mContext.sendBroadcast(intent);
-    }
-
-    void notifyMediaInserted(final String path) throws IllegalStateException {
-        new Thread() {
-            public void run() {
-                try {
-                    mountVolume(path);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Failed to mount media on insertion", ex);
-                }
-            }
-        }.start();
-    }
-
-    /**
-     * Broadcasts the media removed event to all clients.
-     */
-    void notifyMediaRemoved(String path) throws IllegalStateException {
-
-        // Suppress this on bad removal
-        if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
-            return;
-        }
-
-        updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
-
-        updateUsbMassStorageNotification(true, false);
-
-        setMediaStorageNotification(
-            com.android.internal.R.string.ext_media_nomedia_notification_title,
-            com.android.internal.R.string.ext_media_nomedia_notification_message,
-            com.android.internal.R.drawable.stat_notify_sdcard_usb,
-            true, false, null);
-        handlePossibleExplicitUnmountBroadcast(path);
-
-        Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media unmounted event to all clients.
-     */
-    void notifyMediaUnmounted(String path) {
-
-        updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
-
-        // Update media status on PackageManagerService to unmount packages on sdcard
-        mPms.updateExternalMediaStatus(false);
-        if (mShowSafeUnmountNotificationWhenUnmounted) {
-            setMediaStorageNotification(
-                    com.android.internal.R.string.ext_media_safe_unmount_notification_title,
-                    com.android.internal.R.string.ext_media_safe_unmount_notification_message,
-                    com.android.internal.R.drawable.stat_notify_sdcard,
-                    true, true, null);
-            mShowSafeUnmountNotificationWhenUnmounted = false;
-        } else {
-            setMediaStorageNotification(0, 0, 0, false, false, null);
-        }
-        updateUsbMassStorageNotification(false, false);
-
-        Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media checking event to all clients.
-     */
-    void notifyMediaChecking(String path) {
-        updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
-
-        setMediaStorageNotification(
-                com.android.internal.R.string.ext_media_checking_notification_title,
-                com.android.internal.R.string.ext_media_checking_notification_message,
-                com.android.internal.R.drawable.stat_notify_sdcard_prepare,
-                true, false, null);
-
-        updateUsbMassStorageNotification(true, false);
-        Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media nofs event to all clients.
-     */
-    void notifyMediaNoFs(String path) {
-        updatePublicVolumeState(path, Environment.MEDIA_NOFS);
-        
-        Intent intent = new Intent();
-        intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
-        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-
-        setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
-                                    com.android.internal.R.string.ext_media_nofs_notification_message,
-                                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
-                                    true, false, pi);
-        updateUsbMassStorageNotification(false, false);
-        intent = new Intent(Intent.ACTION_MEDIA_NOFS, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media mounted event to all clients.
-     */
-    void notifyMediaMounted(String path, boolean readOnly) {
-        updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
-
-        // Update media status on PackageManagerService to mount packages on sdcard
-        mPms.updateExternalMediaStatus(true);
-        setMediaStorageNotification(0, 0, 0, false, false, null);
-        updateUsbMassStorageNotification(false, false);
-        Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, 
-                Uri.parse("file://" + path));
-        intent.putExtra("read-only", readOnly);
-        mMounted = true;
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media shared event to all clients.
-     */
-    void notifyMediaShared(String path, boolean mounted) {
-        if (mounted) {
-            Log.e(TAG, "Live shared mounts not supported yet!");
-            return;
-        }
-
-        updatePublicVolumeState(path, Environment.MEDIA_SHARED);
-
-        if (mUmsActiveNotify) {
-            Intent intent = new Intent();
-            intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
-            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-            setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
-                    com.android.internal.R.string.usb_storage_stop_notification_message,
-                    com.android.internal.R.drawable.stat_sys_warning,
-                    false, true, pi);
-        }
-        handlePossibleExplicitUnmountBroadcast(path);
-        Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED,
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media bad removal event to all clients.
-     */
-    void notifyMediaBadRemoval(String path) {
-        updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
-
-        updateUsbMassStorageNotification(true, false);
-        setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title,
-                                    com.android.internal.R.string.ext_media_badremoval_notification_message,
-                                    com.android.internal.R.drawable.stat_sys_warning,
-                                    true, true, null);
-
-        handlePossibleExplicitUnmountBroadcast(path);
-        Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-
-    /**
-     * Broadcasts the media unmountable event to all clients.
-     */
-    void notifyMediaUnmountable(String path) {
-        updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
-
-        Intent intent = new Intent();
-        intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
-        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-
-        setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
-                                    com.android.internal.R.string.ext_media_unmountable_notification_message,
-                                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
-                                    true, false, pi); 
-        updateUsbMassStorageNotification(false, false);
-
-        handlePossibleExplicitUnmountBroadcast(path);
-
-        intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-    
-    /**
-     * Broadcasts the media eject event to all clients.
-     */
-    void notifyMediaUnmounting(String path) {
-        Intent intent = new Intent(Intent.ACTION_MEDIA_EJECT, 
-                Uri.parse("file://" + path));
-        mContext.sendBroadcast(intent);
-    }
-    
-    /**
-     * Sets the USB storage notification.
-     */
-    private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
-                                                        PendingIntent pi) {
-
-        if (!visible && mUsbStorageNotification == null) {
-            return;
-        }
-
-        NotificationManager notificationManager = (NotificationManager) mContext
-                .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        if (notificationManager == null) {
-            return;
-        }
-        
-        if (visible) {
-            Resources r = Resources.getSystem();
-            CharSequence title = r.getText(titleId);
-            CharSequence message = r.getText(messageId);
-
-            if (mUsbStorageNotification == null) {
-                mUsbStorageNotification = new Notification();
-                mUsbStorageNotification.icon = icon;
-                mUsbStorageNotification.when = 0;
-            }
-
-            if (sound && mPlaySounds) {
-                mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
+        try {
+            String cmd = String.format("volume format %s", path);
+            mConnector.doCommand(cmd);
+            return MountServiceResultCode.OperationSucceeded;
+        } catch (NativeDaemonConnectorException e) {
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedNoMedia) {
+                return MountServiceResultCode.OperationFailedNoMedia;
+            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
+                return MountServiceResultCode.OperationFailedMediaCorrupt;
             } else {
-                mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
+                return MountServiceResultCode.OperationFailedInternalError;
             }
-                
-            mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
-
-            mUsbStorageNotification.tickerText = title;
-            if (pi == null) {
-                Intent intent = new Intent();
-                pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-            }
-
-            mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
-        }
-    
-        final int notificationId = mUsbStorageNotification.icon;
-        if (visible) {
-            notificationManager.notify(notificationId, mUsbStorageNotification);
-        } else {
-            notificationManager.cancel(notificationId);
         }
     }
 
-    private synchronized boolean getMediaStorageNotificationDismissable() {
-        if ((mMediaStorageNotification != null) &&
-            ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
-                    Notification.FLAG_AUTO_CANCEL))
-            return true;
-
-        return false;
-    }
-
-    /**
-     * Sets the media storage notification.
-     */
-    private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
-                                                          boolean dismissable, PendingIntent pi) {
-
-        if (!visible && mMediaStorageNotification == null) {
-            return;
-        }
-
-        NotificationManager notificationManager = (NotificationManager) mContext
-                .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        if (notificationManager == null) {
-            return;
-        }
-
-        if (mMediaStorageNotification != null && visible) {
-            /*
-             * Dismiss the previous notification - we're about to
-             * re-use it.
-             */
-            final int notificationId = mMediaStorageNotification.icon;
-            notificationManager.cancel(notificationId);
-        }
-        
-        if (visible) {
-            Resources r = Resources.getSystem();
-            CharSequence title = r.getText(titleId);
-            CharSequence message = r.getText(messageId);
-
-            if (mMediaStorageNotification == null) {
-                mMediaStorageNotification = new Notification();
-                mMediaStorageNotification.when = 0;
-            }
-
-            if (mPlaySounds) {
-                mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
-            } else {
-                mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
-            }
-
-            if (dismissable) {
-                mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
-            } else {
-                mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
-            }
-
-            mMediaStorageNotification.tickerText = title;
-            if (pi == null) {
-                Intent intent = new Intent();
-                pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-            }
-
-            mMediaStorageNotification.icon = icon;
-            mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
-        }
-    
-        final int notificationId = mMediaStorageNotification.icon;
-        if (visible) {
-            notificationManager.notify(notificationId, mMediaStorageNotification);
-        } else {
-            notificationManager.cancel(notificationId);
+    public String[] getSecureContainerList() {
+        validatePermission(android.Manifest.permission.ASEC_ACCESS);
+        try {
+            return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
+        } catch (NativeDaemonConnectorException e) {
+            return new String[0];
         }
     }
 
-    public String[] getSecureContainerList() throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_ACCESS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_ACCESS permission");
+    public int createSecureContainer(String id, int sizeMb, String fstype,
+                                    String key, int ownerUid) {
+        validatePermission(android.Manifest.permission.ASEC_CREATE);
+
+        int rc = MountServiceResultCode.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;
         }
-        return mConnector.doListCommand("list_asec", VoldResponseCode.AsecListResult);
+        return rc;
     }
 
-    public String createSecureContainer(String id, int sizeMb, String fstype,
-                                    String key, int ownerUid) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_CREATE)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_CREATE permission");
+    public int finalizeSecureContainer(String id) {
+        validatePermission(android.Manifest.permission.ASEC_CREATE);
+
+        int rc = MountServiceResultCode.OperationSucceeded;
+        try {
+            mConnector.doCommand(String.format("asec finalize %s", id));
+        } catch (NativeDaemonConnectorException e) {
+            rc = MountServiceResultCode.OperationFailedInternalError;
         }
-        String cmd = String.format("create_asec %s %d %s %s %d",
-                                   id, sizeMb, fstype, key, ownerUid);
-        mConnector.doCommand(cmd);
-        return getSecureContainerPath(id);
+        return rc;
     }
 
-    public void finalizeSecureContainer(String id) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_CREATE)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_CREATE permission");
-        }
-        mConnector.doCommand(String.format("finalize_asec %s", id));
-    }
+    public int destroySecureContainer(String id) {
+        validatePermission(android.Manifest.permission.ASEC_DESTROY);
 
-    public void destroySecureContainer(String id) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_DESTROY)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_DESTROY permission");
+        int rc = MountServiceResultCode.OperationSucceeded;
+        try {
+            mConnector.doCommand(String.format("asec destroy %s", id));
+        } catch (NativeDaemonConnectorException e) {
+            rc = MountServiceResultCode.OperationFailedInternalError;
         }
-        mConnector.doCommand(String.format("destroy_asec %s", id));
+        return rc;
     }
    
-    public String mountSecureContainer(String id, String key,
-                                       int ownerUid) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_MOUNT_UNMOUNT)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_MOUNT_UNMOUNT permission");
+    public int mountSecureContainer(String id, String key, int ownerUid) {
+        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+
+        int rc = MountServiceResultCode.OperationSucceeded;
+        String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
+        try {
+            mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            rc = MountServiceResultCode.OperationFailedInternalError;
         }
-        String cmd = String.format("mount_asec %s %s %d",
-                                   id, key, ownerUid);
-        mConnector.doCommand(cmd);
-        return getSecureContainerPath(id);
+        return rc;
     }
 
-    public void unmountSecureContainer(String id) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_MOUNT_UNMOUNT)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_MOUNT_UNMOUNT permission");
+    public int unmountSecureContainer(String id) {
+        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+
+        int rc = MountServiceResultCode.OperationSucceeded;
+        String cmd = String.format("asec unmount %s", id);
+        try {
+            mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            rc = MountServiceResultCode.OperationFailedInternalError;
         }
-        String cmd = String.format("unmount_asec %s", id);
-        mConnector.doCommand(cmd);
+        return rc;
     }
 
-    public void renameSecureContainer(String oldId, String newId) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_RENAME)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_RENAME permission");
+    public int renameSecureContainer(String oldId, String newId) {
+        validatePermission(android.Manifest.permission.ASEC_RENAME);
+
+        int rc = MountServiceResultCode.OperationSucceeded;
+        String cmd = String.format("asec rename %s %s", oldId, newId);
+        try {
+            mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            rc = MountServiceResultCode.OperationFailedInternalError;
         }
-        String cmd = String.format("rename_asec %s %s", oldId, newId);
-        mConnector.doCommand(cmd);
+        return rc;
     }
 
-    public String getSecureContainerPath(String id) throws IllegalStateException {
-        if (mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.ASEC_ACCESS)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ASEC_ACCESS permission");
-        }
-        ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
+    public String getSecureContainerPath(String id) {
+        validatePermission(android.Manifest.permission.ASEC_ACCESS);
+        ArrayList<String> rsp = mConnector.doCommand("asec path " + id);
 
         for (String line : rsp) {
             String []tok = line.split(" ");
@@ -1144,10 +855,13 @@
             if (code == VoldResponseCode.AsecPathResult) {
                 return tok[1];
             } else {
-                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+                Log.e(TAG, String.format("Unexpected response code %d", code));
+                return "";
             }
         }
-        throw new IllegalStateException("Got an empty response");
+
+        Log.e(TAG, "Got an empty response");
+        return "";
     }
 }
 
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 92ba5f8..016aa52 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -28,7 +28,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.Socket;
-import java.lang.IllegalStateException;
 
 import java.util.List;
 import java.util.ArrayList;
@@ -82,12 +81,12 @@
                 listenToSocket();
             } catch (Exception e) {
                 Log.e(TAG, "Error in NativeDaemonConnector", e);
-                SystemClock.sleep(1000);
+                SystemClock.sleep(5000);
             }
         }
     }
 
-    private void listenToSocket() {
+    private void listenToSocket() throws IOException {
        LocalSocket socket = null;
 
         try {
@@ -143,31 +142,27 @@
             }
         } catch (IOException ex) {
             Log.e(TAG, "Communications error", ex);
-        }
-
-        synchronized (this) {
-            if (mOutputStream != null) {
-                try {
-                    mOutputStream.close();
-                } catch (IOException e) {
-                    Log.w(TAG, "Failed closing output stream", e);
+            throw ex;
+        } finally {
+            synchronized (this) {
+                if (mOutputStream != null) {
+                    try {
+                        mOutputStream.close();
+                    } catch (IOException e) {
+                        Log.w(TAG, "Failed closing output stream", e);
+                    }
+                    mOutputStream = null;
                 }
+            }
 
-                mOutputStream = null;
+            try {
+                if (socket != null) {
+                    socket.close();
+                }
+            } catch (IOException ex) {
+                Log.w(TAG, "Failed closing socket", ex);
             }
         }
-
-        try {
-            if (socket != null) {
-                socket.close();
-            }
-        } catch (IOException ex) {
-            Log.w(TAG, "Failed closing socket", ex);
-        }
-
-        Log.e(TAG, "Failed to connect to native daemon",
-                new IllegalStateException());
-        SystemClock.sleep(5000);
     }
 
     private void sendCommand(String command) {
@@ -204,7 +199,8 @@
     /**
      * Issue a command to the native daemon and return the responses
      */
-    public synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException {
+    public synchronized ArrayList<String> doCommand(String cmd)
+            throws NativeDaemonConnectorException  {
         sendCommand(cmd);
 
         ArrayList<String> response = new ArrayList<String>();
@@ -214,12 +210,12 @@
         while (!complete) {
             try {
                 String line = mResponseQueue.take();
-//                Log.d(TAG, "Removed off queue -> " + line);
+                Log.d(TAG, String.format("RSP -> {%s}", line));
                 String[] tokens = line.split(" ");
                 try {
                     code = Integer.parseInt(tokens[0]);
                 } catch (NumberFormatException nfe) {
-                    throw new IllegalStateException(
+                    throw new NativeDaemonConnectorException(
                             String.format("Invalid response from daemon (%s)", line));
                 }
 
@@ -233,7 +229,7 @@
 
         if (code >= ResponseCode.FailedRangeStart &&
                 code <= ResponseCode.FailedRangeEnd) {
-            throw new IllegalStateException(String.format(
+            throw new NativeDaemonConnectorException(code, String.format(
                                                "Command %s failed with code %d",
                                                 cmd, code));
         }
@@ -244,7 +240,7 @@
      * Issues a list command and returns the cooked list
      */
     public String[] doListCommand(String cmd, int expectedResponseCode)
-            throws IllegalStateException {
+            throws NativeDaemonConnectorException {
 
         ArrayList<String> rsp = doCommand(cmd);
         String[] rdata = new String[rsp.size()-1];
@@ -259,14 +255,15 @@
                 } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
                     return rdata;
                 } else {
-                    throw new IllegalStateException(
+                    throw new NativeDaemonConnectorException(
                             String.format("Expected list response %d, but got %d",
                                     expectedResponseCode, code));
                 }
             } catch (NumberFormatException nfe) {
-                throw new IllegalStateException(String.format("Error reading code '%s'", line));
+                throw new NativeDaemonConnectorException(
+                        String.format("Error reading code '%s'", line));
             }
         }
-        throw new IllegalStateException("Got an empty response");
+        throw new NativeDaemonConnectorException("Got an empty response");
     }
 }
diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/java/com/android/server/NativeDaemonConnectorException.java
new file mode 100644
index 0000000..e60aaf8
--- /dev/null
+++ b/services/java/com/android/server/NativeDaemonConnectorException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+/**
+ * An exception that indicates there was an error with a NativeDaemonConnector operation
+ */
+public class NativeDaemonConnectorException extends RuntimeException
+{
+    private int mCode = -1;
+
+    public NativeDaemonConnectorException() {}
+
+    public NativeDaemonConnectorException(String error)
+    {
+        super(error);
+    }
+
+    public NativeDaemonConnectorException(int code, String error)
+    {
+        super(error);
+        mCode = code;
+    }
+
+    public int getCode() {
+        return mCode;
+    }
+}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index cd4ae4c..4801817 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -73,6 +73,7 @@
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.MountServiceResultCode;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.ServiceManager;
@@ -7940,33 +7941,28 @@
             Log.e(TAG, "Failed to create encryption keys with exception: " + nsae);
             return null;
         }
-        try {
-            cachePath = mountService.createSecureContainer(pkgName,
-                mbLen,
-                "vfat", sdEncKey, Process.SYSTEM_UID);
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install " + pkgName + ", cachePath =" + cachePath);
-            return cachePath;
-        } catch(IllegalStateException e) {
-            Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
+
+        int rc = mountService.createSecureContainer(
+                pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
+        if (rc != MountServiceResultCode.OperationSucceeded) {
+            Log.e(TAG, String.format("Failed to create container (%d)", rc));
+
+            rc = mountService.destroySecureContainer(pkgName);
+            if (rc != MountServiceResultCode.OperationSucceeded) {
+                Log.e(TAG, String.format("Failed to cleanup container (%d)", rc));
+                return null;
+            }
+            rc = mountService.createSecureContainer(
+                    pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
+            if (rc != MountServiceResultCode.OperationSucceeded) {
+                Log.e(TAG, String.format("Failed to create container (2nd try) (%d)", rc));
+                return null;
+            }
         }
-        // TODO just fail here and let the user delete later on.
-        try {
-            mountService.destroySecureContainer(pkgName);
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "Destroying cache for " + pkgName + ", cachePath =" + cachePath);
-        } catch(IllegalStateException e) {
-            Log.e(TAG, "Failed to destroy existing cache: " + e);
-            return null;
-        } 
-       try {
-            cachePath = mountService.createSecureContainer(pkgName,
-                mbLen,
-                "vfat", sdEncKey, Process.SYSTEM_UID);
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install again " + pkgName + ", cachePath =" + cachePath);
+
+        cachePath = mountService.getSecureContainerPath(pkgName);
+        if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install " + pkgName + ", cachePath =" + cachePath);
             return cachePath;
-        } catch(IllegalStateException e) {
-            Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
-            return null;
-        }
     }
 
    private String mountSdDir(String pkgName, int ownerUid) {
@@ -7975,64 +7971,53 @@
            Log.e(TAG, "Failed to retrieve encryption keys to mount package code: " + pkgName + ".");
            return null;
        }
-       try {
-           return getMountService().mountSecureContainer(pkgName, sdEncKey, ownerUid);
-       } catch (IllegalStateException e) {
-           Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " exception : " + e);
+
+       int rc = getMountService().mountSecureContainer(pkgName, sdEncKey, ownerUid);
+
+       if (rc != MountServiceResultCode.OperationSucceeded) {
+           Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " rc : " + rc);
+           return null;
        }
-       return null;
+
+       return getMountService().getSecureContainerPath(pkgName);
    }
 
    private boolean unMountSdDir(String pkgName) {
        // STOPSHIP unmount directory
-       try {
-           getMountService().unmountSecureContainer(pkgName);
-           return true;
-       } catch (IllegalStateException e) {
-           Log.e(TAG, "Failed to unmount : " + pkgName + " with exception " + e);
-       }
-       return false;
-   }
-
-   private String getSdDir(String pkgName) {
-       String cachePath = null;
-       try {
-           cachePath = getMountService().getSecureContainerPath(pkgName);
-       } catch (IllegalStateException e) {
-           Log.e(TAG, "Failed to retrieve secure container path for pkg : " + pkgName + " with exception " + e);
-       }
-       return cachePath;
-   }
-
-   private boolean finalizeSdDir(String pkgName) {
-       try {
-           getMountService().finalizeSecureContainer(pkgName);
-           return true;
-       } catch (IllegalStateException e) {
-           Log.i(TAG, "Failed to destroy container for pkg : " + pkgName);
+       int rc = getMountService().unmountSecureContainer(pkgName);
+       if (rc != MountServiceResultCode.OperationSucceeded) {
+           Log.e(TAG, "Failed to unmount : " + pkgName + " with rc " + rc);
            return false;
        }
+       return true;
    }
 
-   private boolean destroySdDir(String pkgName) {
-       try {
-           // We need to destroy right away
-           getMountService().destroySecureContainer(pkgName);
-           return true;
-       } catch (IllegalStateException e) {
-           Log.i(TAG, "Failed to destroy container for pkg : " + pkgName);
-           return false;
-       }
-   }
+    private String getSdDir(String pkgName) {
+        return getMountService().getSecureContainerPath(pkgName);
+    }
 
-   static String[] getSecureContainerList() {
-       try {
-           return getMountService().getSecureContainerList();
-       } catch (IllegalStateException e) {
-           Log.i(TAG, "Failed to getSecureContainerList");
-       }
-       return null;
-   }
+    private boolean finalizeSdDir(String pkgName) {
+        int rc = getMountService().finalizeSecureContainer(pkgName);
+        if (rc != MountServiceResultCode.OperationSucceeded) {
+            Log.i(TAG, "Failed to finalize container for pkg : " + pkgName);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean destroySdDir(String pkgName) {
+        int rc = getMountService().destroySecureContainer(pkgName);
+        if (rc != MountServiceResultCode.OperationSucceeded) {
+            Log.i(TAG, "Failed to destroy container for pkg : " + pkgName);
+            return false;
+        }
+        return true;
+    }
+
+    static String[] getSecureContainerList() {
+        String[] list = getMountService().getSecureContainerList();
+        return list.length == 0 ? null : list;
+    }
 
    static String getTempContainerId() {
        String prefix = "smdl1tmp";