From 4270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Fri, 29 Jan 2010 05:32:19 -0800 Subject: [PATCH] MountService: Massive bloat reduction and rewrite - Most API calls now return an int as a result code (see MountServiceResultCode.java) - All notification code has been removed - All settings code has been removed - Removed UMS centric API calls in favor of more generic 'shares' - Mount error reporting is no longer done via an event, but is done as part of the actual mount process - Rework vold IPC commands to be more sane Updated: MountService: Rename MountServiceObserver -> MountServiceListener MountService: Add support for Async callbacks Updated: MountService: Add BinderDeath handling Updated: MountService: Remove notifys since we dont listen anyways Updated: MountService: Fix bad cast Signed-off-by: San Mehat --- Android.mk | 2 +- core/java/android/os/IMountService.aidl | 72 +- ...iceObserver.aidl => IMountServiceListener.aidl} | 10 +- ...viceObserver.java => MountServiceListener.java} | 2 +- core/java/android/os/MountServiceResultCode.java | 34 + services/java/com/android/server/MountService.java | 1312 ++++++++------------ 6 files changed, 601 insertions(+), 831 deletions(-) rename core/java/android/os/{IMountServiceObserver.aidl => IMountServiceListener.aidl} (83%) rename core/java/android/os/{MountServiceObserver.java => MountServiceListener.java} (98%) create mode 100644 core/java/android/os/MountServiceResultCode.java diff --git a/Android.mk b/Android.mk index f225ecd86d07..682f2865d1ad 100644 --- a/Android.mk +++ b/Android.mk @@ -112,7 +112,7 @@ LOCAL_SRC_FILES += \ 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/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl index 2124e85b480c..a5828f65c1a4 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 @@ package android.os; 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(); + /** - * Mount external storage at given mount point. + * Returns true if the share method is available */ - void mountVolume(String mountPoint); + boolean getShareMethodAvailable(String method); /** - * Safely unmount external storage at given mount point. + * Shares a volume via the specified method + * Returns an int consistent with MountServiceResultCode */ - void unmountVolume(String mountPoint); + int shareVolume(String path, String method); /** - * Format external storage given a mount point. + * 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. */ - void formatVolume(String mountPoint); + boolean getVolumeShared(String path, String method); /** - * Returns true if media notification sounds are enabled. + * Mount external storage at given mount point. + * Returns an int consistent with MountServiceResultCode */ - boolean getPlayNotificationSounds(); + int mountVolume(String mountPoint); /** - * Sets whether or not media notification sounds are played. + * Safely unmount external storage at given mount point. + * Returns an int consistent with MountServiceResultCode + */ + int unmountVolume(String mountPoint); + + /** + * Format external storage given a mount point. + * Returns an int consistent with MountServiceResultCode */ - void setPlayNotificationSounds(boolean value); + int formatVolume(String mountPoint); /** * Gets the state of an volume via it's mountpoint. @@ -71,37 +89,41 @@ interface IMountService /* * 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 f753649c2ec8..3df64b213fe5 100644 --- a/core/java/android/os/IMountServiceObserver.aidl +++ b/core/java/android/os/IMountServiceListener.aidl @@ -21,14 +21,14 @@ package android.os; * * @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 @@ interface IMountServiceObserver { * @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 @@ interface IMountServiceObserver { * @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 @@ interface IMountServiceObserver { * * 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 98% rename from core/java/android/os/MountServiceObserver.java rename to core/java/android/os/MountServiceListener.java index 3020562b53bb..a68f464703d7 100644 --- a/core/java/android/os/MountServiceObserver.java +++ b/core/java/android/os/MountServiceListener.java @@ -21,7 +21,7 @@ package android.os; * 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 000000000000..e71dbf46f493 --- /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/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 05cea4657585..638264606a0e 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.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; import android.os.IMountService; +import android.os.IMountServiceListener; +import android.os.MountServiceResultCode; +import android.os.RemoteException; +import android.os.IBinder; import android.os.Environment; import android.os.ServiceManager; import android.os.SystemProperties; @@ -36,13 +37,8 @@ import android.text.TextUtils; 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 @@ class MountService extends IMountService.Stub 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 @@ class MountService extends IMountService.Stub 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. - *

- * 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 - *

- * 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 mListeners; /** * Constructs a new MountService instance @@ -142,7 +118,9 @@ class MountService extends IMountService.Stub 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 @@ class MountService extends IMountService.Stub 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(); } - 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 @@ class MountService extends IMountService.Stub * event to trigger MediaScanner */ if ("simulator".equals(SystemProperties.get("ro.product.device"))) { - notifyMediaMounted( - Environment.getExternalStorageDirectory().getPath(), false); + updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED); return; } @@ -244,280 +152,89 @@ class MountService extends IMountService.Stub } }; - public void shutdown() { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.SHUTDOWN) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires SHUTDOWN permission"); - } - - Log.d(TAG, "Shutting down"); - String state = Environment.getExternalStorageState(); + private final class MountServiceBinderListener implements IBinder.DeathRecipient { + final IMountServiceListener mListener; - if (state.equals(Environment.MEDIA_SHARED)) { - /* - * If the media is currently shared, unshare it. - * XXX: This is still dangerous!. We should not - * be rebooting at *all* if UMS is enabled, since - * 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); - } - } else if (state.equals(Environment.MEDIA_CHECKING)) { - /* - * If the media is being checked, then we need to wait for - * it to complete before being able to proceed. - */ - // XXX: @hackbod - Should we disable the ANR timer here? - int retries = 30; - while (state.equals(Environment.MEDIA_CHECKING) && (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 check"); - } + MountServiceBinderListener(IMountServiceListener listener) { + mListener = listener; + } - if (state.equals(Environment.MEDIA_MOUNTED)) { - /* - * If the media is mounted, then gracefully unmount it. - */ - 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); + public void binderDied() { + Log.d(TAG, "An IMountServiceListener has died!"); + synchronized(mListeners) { + mListeners.remove(this); + mListener.asBinder().unlinkToDeath(this, 0); } } } - /** - * @return true if USB mass storage support is enabled. - */ - public boolean getMassStorageEnabled() { - return mUmsEnabled; - } + int doShareUnshareVolume(String path, String method, boolean enable) { + validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); - /** - * 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); - - mUmsEnabling = enable; - if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { - unmountVolume(vp); - mUmsEnabling = false; - updateUsbMassStorageNotification(true, false); - } - - setShareMethodEnabled(vp, "ums", enable); - mUmsEnabled = enable; - mUmsEnabling = false; - if (!enable) { - mountVolume(vp); - if (mPromptUms) { - updateUsbMassStorageNotification(false, false); - } else { - updateUsbMassStorageNotification(true, false); - } - } - } catch (IllegalStateException rex) { - Log.e(TAG, "Failed to set ums enable {" + enable + "}"); - return; + // TODO: Add support for multiple share methods + if (!method.equals("ums")) { + throw new IllegalArgumentException(String.format("Method %s not supported", method)); } - } - /** - * @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 { /* - * XXX: Until we have multiple volume discovery, just hardwire - * this to /sdcard + * If the volume is mounted and we're enabling then unmount it */ - if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) { - Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); - throw new IllegalArgumentException(); - } - - return mLegacyState; - } - - - /** - * 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"); - } - mConnector.doCommand(String.format("mount %s", mountPath)); - } - - /** - * 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"); + String vs = getVolumeState(path); + if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { + mUmsEnabling = enable; // Supress unmounted events + unmountVolume(path); + mUmsEnabling = false; // Unsupress unmounted events } - // 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"); + 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; } - mConnector.doCommand(String.format("format %s", formatPath)); - } - - boolean getShareAvailable(String method) throws IllegalStateException { - ArrayList 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)); + /* + * 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. + */ } } - 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")); + return MountServiceResultCode.OperationSucceeded; } - void updatePublicVolumeState(String mountPoint, String state) { - if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) { + 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 {" + mountPoint + "} = {" + state + "}"); - mLegacyState = state; - } + Log.i(TAG, "State for {" + path + "} = {" + state + "}"); - /** - * Update the state of the USB mass storage notification - */ - void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) { - - try { + String oldState = mLegacyState; + mLegacyState = state; - 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); - } else { - setUsbStorageNotification(0, 0, 0, false, false, null); + 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); + } } - } 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); } } @@ -540,7 +257,7 @@ class MountService extends IMountService.Stub try { String[] vols = mConnector.doListCommand( - "list_volumes", VoldResponseCode.VolumeListResult); + "volume list", VoldResponseCode.VolumeListResult); for (String volstr : vols) { String[] tok = volstr.split(" "); // FMT: