From 0eec21d97d9dc4eb4fdbad0e4c0fc53703452d02 Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu Date: Thu, 25 Feb 2010 17:07:14 -0800 Subject: [PATCH] Add dialog to display storage users when enabling/disabling ums Some error dialogs and related strings MountService changes to follow unmount path when enabling ums. Please note that MountService api setUmsEnabled does not return error codes for now. This is a known limitation. --- api/current.xml | 4 +- .../android/os/storage/IMountService.aidl | 4 +- .../android/os/storage/StorageManager.java | 14 +- core/res/res/values/strings.xml | 10 +- .../java/com/android/server/MountService.java | 122 ++++++++++------- .../server/status/UsbStorageActivity.java | 126 +++++++++++++----- 6 files changed, 183 insertions(+), 97 deletions(-) diff --git a/api/current.xml b/api/current.xml index 492bb347a5fb3..394a68a10872f 100644 --- a/api/current.xml +++ b/api/current.xml @@ -120110,7 +120110,7 @@ visibility="public" > Select to copy files to/from your computer. - Turn off USB storage @@ -2084,6 +2083,15 @@ There was a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again. + + Enable Mass Storage + + Some processes accessing data on sdcard will be killed. Do you want to continue? + + UMS operation failed + + OK + diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 4485c79ee6a3a..41f38501bd3f0 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -111,15 +111,18 @@ class MountService extends IMountService.Stub private String mLegacyState = Environment.MEDIA_REMOVED; private PackageManagerService mPms; private boolean mUmsEnabling; - private ArrayList mListeners; + // Used as a lock for methods that register/unregister listeners. + final private ArrayList mListeners = + new ArrayList(); private boolean mBooted = false; private boolean mReady = false; private boolean mSendUmsConnectedOnBoot = false; /** * Private hash of currently mounted secure containers. + * Used as a lock in methods to manipulate secure containers. */ - private HashSet mAsecMountSet = new HashSet(); + final private HashSet mAsecMountSet = new HashSet(); private static final int H_UNMOUNT_PM_UPDATE = 1; private static final int H_UNMOUNT_PM_DONE = 2; @@ -148,6 +151,25 @@ class MountService extends IMountService.Stub this.path = path; this.force = force; } + + void handleFinished() { + doUnmountVolume(path, true); + } + } + + class UmsEnableCallBack extends UnmountCallBack { + String method; + + UmsEnableCallBack(String path, String method, boolean force) { + super(path, force); + this.method = method; + } + + @Override + void handleFinished() { + super.handleFinished(); + doShareUnshareVolume(path, method, true); + } } final private Handler mHandler = new Handler() { @@ -217,8 +239,7 @@ class MountService extends IMountService.Stub } case H_UNMOUNT_MS : { UnmountCallBack ucb = (UnmountCallBack) msg.obj; - String path = ucb.path; - doUnmountVolume(path, true); + ucb.handleFinished(); break; } } @@ -298,52 +319,18 @@ class MountService extends IMountService.Stub } } - private int doShareUnshareVolume(String path, String method, boolean enable) { - validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); - + private void doShareUnshareVolume(String path, String method, boolean enable) { // 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; // Override for isUsbMassStorageEnabled() - int rc = doUnmountVolume(path, true); - mUmsEnabling = false; // Clear override - if (rc != StorageResultCode.OperationSucceeded) { - Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc)); - return rc; - } - } - 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 StorageResultCode.OperationFailedInternalError; } - - /* - * If we disabled UMS then mount the volume - */ - if (!enable) { - if (doMountVolume(path) != StorageResultCode.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 StorageResultCode.OperationSucceeded; } private void updatePublicVolumeState(String path, String state) { @@ -547,7 +534,7 @@ class MountService extends IMountService.Stub if (!vs.equals( Environment.MEDIA_BAD_REMOVAL) && !vs.equals( Environment.MEDIA_NOFS) && !vs.equals( - Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) { + Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); } @@ -791,8 +778,6 @@ class MountService extends IMountService.Stub mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); - mListeners = new ArrayList(); - /* * Vold does not run in the simulator, so pretend the connector thread * ran and did its thing. @@ -852,9 +837,7 @@ class MountService extends IMountService.Stub * the UMS host could have dirty FAT cache entries * yet to flush. */ - if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) { - Log.e(TAG, "UMS disable on shutdown failed"); - } + setUsbMassStorageEnabled(false); } else if (state.equals(Environment.MEDIA_CHECKING)) { /* * If the media is being checked, then we need to wait for @@ -886,19 +869,62 @@ class MountService extends IMountService.Stub } } + private boolean getUmsEnabling() { + synchronized (mListeners) { + return mUmsEnabling; + } + } + + private void setUmsEnabling(boolean enable) { + synchronized (mListeners) { + mUmsEnabling = true; + } + } + public boolean isUsbMassStorageConnected() { waitForReady(); - if (mUmsEnabling) { + if (getUmsEnabling()) { return true; } return doGetShareMethodAvailable("ums"); } - public int setUsbMassStorageEnabled(boolean enable) { + public void setUsbMassStorageEnabled(boolean enable) { waitForReady(); + validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); - return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable); + // TODO: Add support for multiple share methods + + /* + * If the volume is mounted and we're enabling then unmount it + */ + String path = Environment.getExternalStorageDirectory().getPath(); + String vs = getVolumeState(path); + String method = "ums"; + if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { + // Override for isUsbMassStorageEnabled() + setUmsEnabling(enable); + UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); + mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); + // Clear override + setUmsEnabling(false); + } + /* + * If we disabled UMS then mount the volume + */ + if (!enable) { + doShareUnshareVolume(path, method, enable); + if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { + Log.e(TAG, "Failed to remount " + path + + " after disabling share method " + 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. + */ + } + } } public boolean isUsbMassStorageEnabled() { diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java index 7a2a2d67d1e51..c1c8c22230d7f 100644 --- a/services/java/com/android/server/status/UsbStorageActivity.java +++ b/services/java/com/android/server/status/UsbStorageActivity.java @@ -16,25 +16,27 @@ package com.android.server.status; +import com.android.internal.R; import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; -import android.os.Handler; import android.os.Environment; +import android.os.IBinder; +import android.os.storage.IMountService; import android.os.storage.StorageManager; import android.os.storage.StorageEventListener; -import android.os.storage.StorageResultCode; -import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.widget.ImageView; import android.widget.Button; import android.widget.TextView; -import android.widget.Toast; import android.view.View; import android.util.Log; @@ -43,7 +45,8 @@ import android.util.Log; * on-demand (that is, when the USB cable is connected). It uses the alert * dialog style. It will be launched from a notification. */ -public class UsbStorageActivity extends Activity { +public class UsbStorageActivity extends Activity + implements View.OnClickListener, OnCancelListener { private static final String TAG = "UsbStorageActivity"; private Button mMountButton; private Button mUnmountButton; @@ -51,6 +54,9 @@ public class UsbStorageActivity extends Activity { private TextView mMessage; private ImageView mIcon; private StorageManager mStorageManager = null; + private static final int DLG_CONFIRM_KILL_STORAGE_USERS = 1; + private static final int DLG_ERROR_SHARING = 2; + static final boolean localLOGV = false; /** Used to detect when the USB cable is unplugged, so we can call finish() */ private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { @@ -82,7 +88,6 @@ public class UsbStorageActivity extends Activity { if (mStorageManager == null) { Log.w(TAG, "Failed to get StorageManager"); } - mStorageManager.registerListener(mStorageListener); } setTitle(getString(com.android.internal.R.string.usb_storage_activity_title)); @@ -94,28 +99,9 @@ public class UsbStorageActivity extends Activity { mMessage = (TextView) findViewById(com.android.internal.R.id.message); mMountButton = (Button) findViewById(com.android.internal.R.id.mount_button); - mMountButton.setOnClickListener( - new View.OnClickListener() { - public void onClick(View v) { - int rc = mStorageManager.enableUsbMassStorage(); - if (rc != StorageResultCode.OperationSucceeded) { - Log.e(TAG, String.format("UMS enable failed (%d)", rc)); - showSharingError(); - } - } - }); - + mMountButton.setOnClickListener(this); mUnmountButton = (Button) findViewById(com.android.internal.R.id.unmount_button); - mUnmountButton.setOnClickListener( - new View.OnClickListener() { - public void onClick(View v) { - int rc = mStorageManager.disableUsbMassStorage(); - if (rc != StorageResultCode.OperationSucceeded) { - Log.e(TAG, String.format("UMS disable failed (%d)", rc)); - showStoppingError(); - } - } - }); + mUnmountButton.setOnClickListener(this); } private void switchDisplay(boolean usbStorageInUse) { @@ -138,6 +124,7 @@ public class UsbStorageActivity extends Activity { protected void onResume() { super.onResume(); + mStorageManager.registerListener(mStorageListener); registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); try { switchDisplay(mStorageManager.isUsbMassStorageEnabled()); @@ -151,6 +138,9 @@ public class UsbStorageActivity extends Activity { super.onPause(); unregisterReceiver(mBatteryReceiver); + if (mStorageManager == null && mStorageListener != null) { + mStorageManager.unregisterListener(mStorageListener); + } } private void handleBatteryChanged(Intent intent) { @@ -160,15 +150,81 @@ public class UsbStorageActivity extends Activity { finish(); } } - - private void showSharingError() { - Toast.makeText(this, com.android.internal.R.string.usb_storage_error_message, - Toast.LENGTH_LONG).show(); + + private IMountService getMountService() { + IBinder service = ServiceManager.getService("mount"); + if (service != null) { + return IMountService.Stub.asInterface(service); + } + return null; } - - private void showStoppingError() { - Toast.makeText(this, com.android.internal.R.string.usb_storage_stop_error_message, - Toast.LENGTH_LONG).show(); + + @Override + public Dialog onCreateDialog(int id, Bundle args) { + switch (id) { + case DLG_CONFIRM_KILL_STORAGE_USERS: + return new AlertDialog.Builder(this) + .setTitle(R.string.dlg_confirm_kill_storage_users_title) + .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mStorageManager.enableUsbMassStorage(); + }}) + .setNegativeButton(R.string.cancel, null) + .setMessage(R.string.dlg_confirm_kill_storage_users_text) + .setOnCancelListener(this) + .create(); + case DLG_ERROR_SHARING: + return new AlertDialog.Builder(this) + .setTitle(R.string.dlg_error_title) + .setNeutralButton(R.string.dlg_ok, null) + .setMessage(R.string.usb_storage_error_message) + .setOnCancelListener(this) + .create(); + } + return null; + } + + private void showDialogInner(int id) { + removeDialog(id); + showDialog(id); + } + + private void checkStorageUsers() { + IMountService ims = getMountService(); + if (ims == null) { + // Display error dialog + showDialogInner(DLG_ERROR_SHARING); + } + String path = Environment.getExternalStorageDirectory().getPath(); + int stUsers[] = null; + try { + if (localLOGV) Log.i(TAG, "Checking getStorageUsers"); + stUsers = ims.getStorageUsers(path); + } catch (RemoteException e) { + showDialogInner(DLG_ERROR_SHARING); + } + if (stUsers != null && stUsers.length > 0) { + // Display dialog to user + showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS); + } else { + if (localLOGV) Log.i(TAG, "Enabling UMS"); + mStorageManager.enableUsbMassStorage(); + } + } + + public void onClick(View v) { + Log.i(TAG, "Clicked button"); + if (v == mMountButton) { + // Check for list of storage users and display dialog if needed. + checkStorageUsers(); + } else if (v == mUnmountButton) { + if (localLOGV) Log.i(TAG, "Disabling UMS"); + mStorageManager.disableUsbMassStorage(); + } + } + + public void onCancel(DialogInterface dialog) { + finish(); } }