summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/MountService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/MountService.java')
-rw-r--r--services/java/com/android/server/MountService.java144
1 files changed, 123 insertions, 21 deletions
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index a191549..3101222 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -19,6 +19,7 @@ package com.android.server;
import com.android.internal.app.IMediaContainerService;
import com.android.server.am.ActivityManagerService;
+import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -73,8 +74,8 @@ import javax.crypto.spec.PBEKeySpec;
* @hide - Applications should use android.os.storage.StorageManager
* to access the MountService.
*/
-class MountService extends IMountService.Stub
- implements INativeDaemonConnectorCallbacks {
+class MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks {
+
private static final boolean LOCAL_LOGD = false;
private static final boolean DEBUG_UNMOUNT = false;
private static final boolean DEBUG_EVENTS = false;
@@ -151,6 +152,8 @@ class MountService extends IMountService.Stub
private boolean mBooted = false;
private boolean mReady = false;
private boolean mSendUmsConnectedOnBoot = false;
+ // true if we should fake MEDIA_MOUNTED state for external storage
+ private boolean mEmulateExternalStorage = false;
/**
* Private hash of currently mounted secure containers.
@@ -332,6 +335,7 @@ class MountService extends IMountService.Stub
super(l);
}
+ @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case H_UNMOUNT_PM_UPDATE: {
@@ -425,6 +429,7 @@ class MountService extends IMountService.Stub
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -440,12 +445,15 @@ class MountService extends IMountService.Stub
return;
}
new Thread() {
+ @Override
public void run() {
try {
String path = Environment.getExternalStorageDirectory().getPath();
String state = getVolumeState(path);
- if (state.equals(Environment.MEDIA_UNMOUNTED)) {
+ if (mEmulateExternalStorage) {
+ notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Mounted);
+ } else if (state.equals(Environment.MEDIA_UNMOUNTED)) {
int rc = doMountVolume(path);
if (rc != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, String.format("Boot-time mount failed (%d)", rc));
@@ -516,21 +524,21 @@ class MountService extends IMountService.Stub
Slog.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
return;
}
+ // Update state on PackageManager, but only of real events
+ if (!mEmulateExternalStorage) {
+ if (Environment.MEDIA_UNMOUNTED.equals(state)) {
+ mPms.updateExternalMediaStatus(false, false);
- if (Environment.MEDIA_UNMOUNTED.equals(state)) {
- // Tell the package manager the media is gone.
- mPms.updateExternalMediaStatus(false, false);
-
- /*
- * Some OBBs might have been unmounted when this volume was
- * unmounted, so send a message to the handler to let it know to
- * remove those from the list of mounted OBBS.
- */
- mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE,
- path));
- } else if (Environment.MEDIA_MOUNTED.equals(state)) {
- // Tell the package manager the media is available for use.
- mPms.updateExternalMediaStatus(true, false);
+ /*
+ * Some OBBs might have been unmounted when this volume was
+ * unmounted, so send a message to the handler to let it know to
+ * remove those from the list of mounted OBBS.
+ */
+ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE,
+ path));
+ } else if (Environment.MEDIA_MOUNTED.equals(state)) {
+ mPms.updateExternalMediaStatus(true, false);
+ }
}
String oldState = mLegacyState;
@@ -561,6 +569,7 @@ class MountService extends IMountService.Stub
* we need to do our work in a new thread.
*/
new Thread() {
+ @Override
public void run() {
/**
* Determine media state and UMS detection status
@@ -610,7 +619,7 @@ class MountService extends IMountService.Stub
Slog.w(TAG, "Failed to get share availability");
}
/*
- * Now that we've done our initialization, release
+ * Now that we've done our initialization, release
* the hounds!
*/
mReady = true;
@@ -674,6 +683,7 @@ class MountService extends IMountService.Stub
if (code == VoldResponseCode.VolumeDiskInserted) {
new Thread() {
+ @Override
public void run() {
try {
int rc;
@@ -1003,6 +1013,7 @@ class MountService extends IMountService.Stub
* USB mass storage disconnected while enabled
*/
new Thread() {
+ @Override
public void run() {
try {
int rc;
@@ -1040,6 +1051,13 @@ class MountService extends IMountService.Stub
public MountService(Context context) {
mContext = context;
+ mEmulateExternalStorage = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_emulateExternalStorage);
+ if (mEmulateExternalStorage) {
+ Slog.d(TAG, "using emulated external storage");
+ mLegacyState = Environment.MEDIA_MOUNTED;
+ }
+
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
@@ -1144,6 +1162,17 @@ class MountService extends IMountService.Stub
// Post a unmount message.
ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
+ } else if (observer != null) {
+ /*
+ * Observer is waiting for onShutDownComplete when we are done.
+ * Since nothing will be done send notification directly so shutdown
+ * sequence can continue.
+ */
+ try {
+ observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException when shutting down");
+ }
}
}
@@ -1209,7 +1238,7 @@ class MountService extends IMountService.Stub
waitForReady();
return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
}
-
+
/**
* @return state of the volume at the specified mount point
*/
@@ -1226,6 +1255,10 @@ class MountService extends IMountService.Stub
return mLegacyState;
}
+ public boolean isExternalStorageEmulated() {
+ return mEmulateExternalStorage;
+ }
+
public int mountVolume(String path) {
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
@@ -1375,7 +1408,7 @@ class MountService extends IMountService.Stub
return rc;
}
-
+
public int mountSecureContainer(String id, String key, int ownerUid) {
validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
waitForReady();
@@ -1463,7 +1496,7 @@ class MountService extends IMountService.Stub
synchronized (mAsecMountSet) {
/*
- * Because a mounted container has active internal state which cannot be
+ * Because a mounted container has active internal state which cannot be
* changed while active, we must ensure both ids are not currently mounted.
*/
if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
@@ -1598,6 +1631,71 @@ class MountService extends IMountService.Stub
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
+ public int decryptStorage(String password) {
+ if (password == null) {
+ throw new IllegalArgumentException("password cannot be null");
+ }
+
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
+ "no permission to access the crypt keeper");
+
+ waitForReady();
+
+ if (DEBUG_EVENTS) {
+ Slog.i(TAG, "decrypting storage...");
+ }
+
+ try {
+ ArrayList<String> rsp = mConnector.doCommand("cryptfs checkpw " + password);
+ String []tok = rsp.get(0).split(" ");
+
+ if (tok == null || tok.length != 2) {
+ return -1;
+ }
+
+ int code = Integer.parseInt(tok[1]);
+
+ if (code == 0) {
+ // Decrypt was successful. Post a delayed message before restarting in order
+ // to let the UI to clear itself
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mConnector.doCommand(String.format("cryptfs restart"));
+ }
+ }, 2000); // 2 seconds
+ }
+
+ return code;
+ } catch (NativeDaemonConnectorException e) {
+ // Decryption failed
+ return e.getCode();
+ }
+ }
+
+ public int encryptStorage(String password) {
+ if (password == null) {
+ throw new IllegalArgumentException("password cannot be null");
+ }
+
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
+ "no permission to access the crypt keeper");
+
+ waitForReady();
+
+ if (DEBUG_EVENTS) {
+ Slog.i(TAG, "encrypting storage...");
+ }
+
+ try {
+ mConnector.doCommand(String.format("cryptfs enablecrypto inplace %s", password));
+ } catch (NativeDaemonConnectorException e) {
+ // Encryption failed
+ return e.getCode();
+ }
+
+ return 0;
+ }
+
private void addObbStateLocked(ObbState obbState) throws RemoteException {
final IBinder binder = obbState.getBinder();
List<ObbState> obbStates = mObbMounts.get(binder);
@@ -1885,6 +1983,7 @@ class MountService extends IMountService.Stub
mKey = key;
}
+ @Override
public void handleExecute() throws IOException, RemoteException {
waitForReady();
warnOnNotMounted();
@@ -1965,6 +2064,7 @@ class MountService extends IMountService.Stub
}
}
+ @Override
public void handleError() {
sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
}
@@ -1994,6 +2094,7 @@ class MountService extends IMountService.Stub
mForceUnmount = force;
}
+ @Override
public void handleExecute() throws IOException {
waitForReady();
warnOnNotMounted();
@@ -2048,6 +2149,7 @@ class MountService extends IMountService.Stub
}
}
+ @Override
public void handleError() {
sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
}