MountService: Refactor to use NativeDaemonConnector and clean-up
Signed-off-by: San Mehat <san@google.com>
This commit is contained in:
@@ -42,17 +42,17 @@ interface IMountService
|
||||
/**
|
||||
* Mount external storage at given mount point.
|
||||
*/
|
||||
void mountMedia(String mountPoint);
|
||||
void mountVolume(String mountPoint);
|
||||
|
||||
/**
|
||||
* Safely unmount external storage at given mount point.
|
||||
*/
|
||||
void unmountMedia(String mountPoint);
|
||||
void unmountVolume(String mountPoint);
|
||||
|
||||
/**
|
||||
* Format external storage given a mount point.
|
||||
*/
|
||||
void formatMedia(String mountPoint);
|
||||
void formatVolume(String mountPoint);
|
||||
|
||||
/**
|
||||
* Returns true if media notification sounds are enabled.
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ExternalMediaFormatActivity extends AlertActivity implements Dialog
|
||||
.getService("mount"));
|
||||
if (mountService != null) {
|
||||
try {
|
||||
mountService.formatMedia(Environment.getExternalStorageDirectory().toString());
|
||||
mountService.formatVolume(Environment.getExternalStorageDirectory().toString());
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,377 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.server;
|
||||
|
||||
import android.net.LocalSocketAddress;
|
||||
import android.net.LocalSocket;
|
||||
import android.os.Environment;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.lang.IllegalStateException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.ListIterator;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Vold Connection class
|
||||
*/
|
||||
final class MountListener implements Runnable {
|
||||
private static final String TAG = "MountListener";
|
||||
private static final String VOLD_SOCKET = "vold";
|
||||
private static final int RESPONSE_QUEUE_SIZE = 10;
|
||||
|
||||
private MountService mService;
|
||||
private BlockingQueue<String> mResponseQueue;
|
||||
private OutputStream mOutputStream;
|
||||
|
||||
class ResponseCode {
|
||||
public static final int ActionInitiated = 100;
|
||||
public static final int VolumeListResult = 110;
|
||||
public static final int AsecListResult = 111;
|
||||
|
||||
public static final int CommandOkay = 200;
|
||||
public static final int ShareAvailabilityResult = 210;
|
||||
public static final int AsecPathResult = 211;
|
||||
|
||||
public static final int UnsolicitedInformational = 600;
|
||||
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;
|
||||
}
|
||||
|
||||
MountListener(MountService service) {
|
||||
mService = service;
|
||||
mResponseQueue = new LinkedBlockingQueue<String>(RESPONSE_QUEUE_SIZE);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// Vold does not run in the simulator, so fake out a mounted event to trigger the Media Scanner
|
||||
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
|
||||
mService.notifyMediaMounted(Environment.getExternalStorageDirectory().getPath(), false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
listenToSocket();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "Fatal error " + t + " in MountListener thread!");
|
||||
}
|
||||
}
|
||||
|
||||
private void listenToSocket() {
|
||||
LocalSocket socket = null;
|
||||
|
||||
try {
|
||||
socket = new LocalSocket();
|
||||
LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,
|
||||
LocalSocketAddress.Namespace.RESERVED);
|
||||
|
||||
socket.connect(address);
|
||||
mService.onVoldConnected();
|
||||
|
||||
InputStream inputStream = socket.getInputStream();
|
||||
mOutputStream = socket.getOutputStream();
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
|
||||
while (true) {
|
||||
int count = inputStream.read(buffer);
|
||||
if (count < 0) break;
|
||||
|
||||
int start = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (buffer[i] == 0) {
|
||||
String event = new String(buffer, start, i - start);
|
||||
// Log.d(TAG, "Got packet {" + event + "}");
|
||||
|
||||
String[] tokens = event.split(" ");
|
||||
try {
|
||||
int code = Integer.parseInt(tokens[0]);
|
||||
|
||||
if (code >= ResponseCode.UnsolicitedInformational) {
|
||||
try {
|
||||
handleUnsolicitedEvent(code, event, tokens);
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, String.format(
|
||||
"Error handling '%s'", event), ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
mResponseQueue.put(event);
|
||||
} catch (InterruptedException ex) {
|
||||
Log.e(TAG, "InterruptedException");
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
Log.w(TAG,
|
||||
"Unknown msg from Vold '" + event + "'");
|
||||
}
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "IOException in listenToSocket");
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (mOutputStream != null) {
|
||||
try {
|
||||
mOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "IOException closing output stream");
|
||||
}
|
||||
|
||||
mOutputStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Log.w(TAG, "IOException closing socket");
|
||||
}
|
||||
|
||||
Log.e(TAG, "Failed to connect to Vold", new IllegalStateException());
|
||||
SystemClock.sleep(5000);
|
||||
}
|
||||
|
||||
private void handleUnsolicitedEvent(int code, String raw,
|
||||
String[] cooked) throws IllegalStateException {
|
||||
// Log.d(TAG, "unsolicited {" + raw + "}");
|
||||
if (code == ResponseCode.VolumeStateChange) {
|
||||
// FMT: NNN Volume <label> <mountpoint> state changed from <old_#> (<old_str>) to <new_#> (<new_str>)
|
||||
mService.notifyVolumeStateChange(cooked[2], cooked[3],
|
||||
Integer.parseInt(cooked[7]),
|
||||
Integer.parseInt(cooked[10]));
|
||||
} else if (code == ResponseCode.VolumeMountFailedBlank) {
|
||||
// FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems
|
||||
mService.notifyMediaNoFs(cooked[3]);
|
||||
// FMT: NNN Volume <label> <mountpoint> mount failed - no media
|
||||
} else if (code == ResponseCode.VolumeMountFailedNoMedia) {
|
||||
mService.notifyMediaRemoved(cooked[3]);
|
||||
} else if (code == ResponseCode.VolumeMountFailedDamaged) {
|
||||
// FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed
|
||||
mService.notifyMediaUnmountable(cooked[3]);
|
||||
} else if (code == ResponseCode.ShareAvailabilityChange) {
|
||||
// FMT: NNN Share method <method> now <available|unavailable>
|
||||
boolean avail = false;
|
||||
if (cooked[5].equals("available")) {
|
||||
avail = true;
|
||||
}
|
||||
mService.notifyShareAvailabilityChange(cooked[3], avail);
|
||||
} else if (code == ResponseCode.VolumeDiskInserted) {
|
||||
// FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
|
||||
mService.notifyMediaInserted(cooked[3]);
|
||||
} else if (code == ResponseCode.VolumeDiskRemoved) {
|
||||
// FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
|
||||
mService.notifyMediaRemoved(cooked[3]);
|
||||
} else if (code == ResponseCode.VolumeBadRemoval) {
|
||||
// FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
|
||||
mService.notifyMediaBadRemoval(cooked[3]);
|
||||
} else {
|
||||
Log.w(TAG, "Unhandled event {" + raw + "}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sendCommand(String command) {
|
||||
sendCommand(command, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to Vold with a single argument
|
||||
*
|
||||
* @param command The command to send to the mount service daemon
|
||||
* @param argument The argument to send with the command (or null)
|
||||
*/
|
||||
private void sendCommand(String command, String argument) {
|
||||
synchronized (this) {
|
||||
// Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}");
|
||||
if (mOutputStream == null) {
|
||||
Log.e(TAG, "No connection to Vold", new IllegalStateException());
|
||||
} else {
|
||||
StringBuilder builder = new StringBuilder(command);
|
||||
if (argument != null) {
|
||||
builder.append(argument);
|
||||
}
|
||||
builder.append('\0');
|
||||
|
||||
try {
|
||||
mOutputStream.write(builder.toString().getBytes());
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "IOException in sendCommand", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException {
|
||||
sendCommand(cmd);
|
||||
|
||||
ArrayList<String> response = new ArrayList<String>();
|
||||
boolean complete = false;
|
||||
int code = -1;
|
||||
|
||||
while (!complete) {
|
||||
try {
|
||||
String line = mResponseQueue.take();
|
||||
// Log.d(TAG, "Removed off queue -> " + line);
|
||||
String[] tokens = line.split(" ");
|
||||
code = Integer.parseInt(tokens[0]);
|
||||
|
||||
if ((code >= 200) && (code < 600))
|
||||
complete = true;
|
||||
response.add(line);
|
||||
} catch (InterruptedException ex) {
|
||||
Log.e(TAG, "InterruptedException");
|
||||
}
|
||||
}
|
||||
|
||||
if (code >= 400 && code < 600) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Command %s failed with code %d",
|
||||
cmd, code));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
boolean getShareAvailable(String method) throws IllegalStateException {
|
||||
ArrayList<String> rsp = doCommand("share_available " + method);
|
||||
|
||||
for (String line : rsp) {
|
||||
String []tok = line.split(" ");
|
||||
int code = Integer.parseInt(tok[0]);
|
||||
if (code == ResponseCode.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 {
|
||||
doCommand((enable ? "" : "un") + "share " + mountPoint + " " + method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mount media at given mount point.
|
||||
*/
|
||||
public void mountVolume(String label) throws IllegalStateException {
|
||||
doCommand("mount " + label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmount media at given mount point.
|
||||
*/
|
||||
public void unmountVolume(String label) throws IllegalStateException {
|
||||
doCommand("unmount " + label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format media at given mount point.
|
||||
*/
|
||||
public void formatVolume(String label) throws IllegalStateException {
|
||||
doCommand("format " + label);
|
||||
}
|
||||
|
||||
public String createAsec(String id, int sizeMb, String fstype, String key,
|
||||
int ownerUid) throws IllegalStateException {
|
||||
String cmd = String.format("create_asec %s %d %s %s %d",
|
||||
id, sizeMb, fstype, key, ownerUid);
|
||||
doCommand(cmd);
|
||||
return getAsecPath(id);
|
||||
}
|
||||
|
||||
public void finalizeAsec(String id) throws IllegalStateException {
|
||||
doCommand("finalize_asec " + id);
|
||||
}
|
||||
|
||||
public void destroyAsec(String id) throws IllegalStateException {
|
||||
doCommand("destroy_asec " + id);
|
||||
}
|
||||
|
||||
public String mountAsec(String id, String key, int ownerUid) throws IllegalStateException {
|
||||
String cmd = String.format("mount_asec %s %s %d",
|
||||
id, key, ownerUid);
|
||||
doCommand(cmd);
|
||||
return getAsecPath(id);
|
||||
}
|
||||
|
||||
public String getAsecPath(String id) throws IllegalStateException {
|
||||
ArrayList<String> rsp = doCommand("asec_path " + id);
|
||||
|
||||
for (String line : rsp) {
|
||||
String []tok = line.split(" ");
|
||||
int code = Integer.parseInt(tok[0]);
|
||||
if (code == ResponseCode.AsecPathResult) {
|
||||
return tok[1];
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("Unexpected response code %d", code));
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Got an empty response");
|
||||
}
|
||||
|
||||
public String[] listAsec() throws IllegalStateException {
|
||||
ArrayList<String> rsp = doCommand("list_asec");
|
||||
|
||||
String[] rdata = new String[rsp.size()];
|
||||
int idx = 0;
|
||||
|
||||
for (String line : rsp) {
|
||||
String []tok = line.split(" ");
|
||||
int code = Integer.parseInt(tok[0]);
|
||||
if (code == ResponseCode.AsecListResult) {
|
||||
rdata[idx++] = tok[1];
|
||||
} else if (code == ResponseCode.CommandOkay) {
|
||||
return rdata;
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("Unexpected response code %d", code));
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Got an empty response");
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import android.os.UEventObserver;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.provider.Settings;
|
||||
import android.content.ContentResolver;
|
||||
@@ -46,7 +47,8 @@ import java.lang.IllegalStateException;
|
||||
* MountService implements an to the mount service daemon
|
||||
* @hide
|
||||
*/
|
||||
class MountService extends IMountService.Stub {
|
||||
class MountService extends IMountService.Stub
|
||||
implements INativeDaemonConnectorCallbacks {
|
||||
|
||||
private static final String TAG = "MountService";
|
||||
|
||||
@@ -63,15 +65,33 @@ class MountService extends IMountService.Stub {
|
||||
public static final int SharedMnt = 8;
|
||||
}
|
||||
|
||||
class VoldResponseCode {
|
||||
public static final int VolumeListResult = 110;
|
||||
public static final int AsecListResult = 111;
|
||||
|
||||
public static final int ShareAvailabilityResult = 210;
|
||||
public static final int AsecPathResult = 211;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* listener object for communicating with the mount service daemon
|
||||
* connectorr object for communicating with vold
|
||||
*/
|
||||
private MountListener mListener;
|
||||
private NativeDaemonConnector mConnector;
|
||||
|
||||
/**
|
||||
* The notification that is shown when a USB mass storage host
|
||||
@@ -119,12 +139,12 @@ class MountService extends IMountService.Stub {
|
||||
mContext = context;
|
||||
|
||||
// Register a BOOT_COMPLETED handler so that we can start
|
||||
// MountListener. We defer the startup so that we don't
|
||||
// our NativeDaemonConnector. We defer the startup so that we don't
|
||||
// start processing events before we ought-to
|
||||
mContext.registerReceiver(mBroadcastReceiver,
|
||||
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
|
||||
|
||||
mListener = new MountListener(this);
|
||||
mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
|
||||
mShowSafeUnmountNotificationWhenUnmounted = false;
|
||||
|
||||
mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
|
||||
@@ -202,7 +222,18 @@ class MountService extends IMountService.Stub {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
Thread thread = new Thread(mListener, MountListener.class.getName());
|
||||
/*
|
||||
* Vold does not run in the simulator, so fake out a mounted
|
||||
* event to trigger MediaScanner
|
||||
*/
|
||||
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
|
||||
notifyMediaMounted(
|
||||
Environment.getExternalStorageDirectory().getPath(), false);
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread(
|
||||
mConnector, NativeDaemonConnector.class.getName());
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
@@ -258,7 +289,7 @@ class MountService extends IMountService.Stub {
|
||||
*/
|
||||
try {
|
||||
String m = Environment.getExternalStorageDirectory().toString();
|
||||
unmountMedia(m);
|
||||
unmountVolume(m);
|
||||
|
||||
int retries = 12;
|
||||
while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) {
|
||||
@@ -302,17 +333,14 @@ class MountService extends IMountService.Stub {
|
||||
String vs = getVolumeState(vp);
|
||||
|
||||
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
|
||||
mListener.unmountVolume(vp);
|
||||
unmountVolume(vp);
|
||||
updateUsbMassStorageNotification(true, false);
|
||||
}
|
||||
|
||||
mListener.setShareMethodEnabled(Environment
|
||||
.getExternalStorageDirectory()
|
||||
.getPath(),
|
||||
"ums", enable);
|
||||
setShareMethodEnabled(vp, "ums", enable);
|
||||
mUmsEnabled = enable;
|
||||
if (!enable) {
|
||||
mountMedia(vp);
|
||||
mountVolume(vp);
|
||||
if (mPromptUms) {
|
||||
updateUsbMassStorageNotification(false, false);
|
||||
} else {
|
||||
@@ -352,19 +380,19 @@ class MountService extends IMountService.Stub {
|
||||
/**
|
||||
* Attempt to mount external media
|
||||
*/
|
||||
public void mountMedia(String mountPath) throws IllegalStateException {
|
||||
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");
|
||||
}
|
||||
mListener.mountVolume(mountPath);
|
||||
mConnector.doCommand(String.format("mount %s", mountPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to unmount external media to prepare for eject
|
||||
*/
|
||||
public void unmountMedia(String mountPath) throws IllegalStateException {
|
||||
public void unmountVolume(String mountPath) throws IllegalStateException {
|
||||
if (mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
@@ -375,23 +403,51 @@ class MountService extends IMountService.Stub {
|
||||
// to display the notification
|
||||
mShowSafeUnmountNotificationWhenUnmounted = true;
|
||||
|
||||
// tell mountd to unmount the media
|
||||
mListener.unmountVolume(mountPath);
|
||||
mConnector.doCommand(String.format("unmount %s", mountPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to format external media
|
||||
*/
|
||||
public void formatMedia(String formatPath) throws IllegalStateException {
|
||||
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");
|
||||
}
|
||||
|
||||
mListener.formatVolume(formatPath);
|
||||
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.
|
||||
*/
|
||||
@@ -417,7 +473,7 @@ class MountService extends IMountService.Stub {
|
||||
Log.w(TAG, "Multiple volumes not currently supported");
|
||||
return;
|
||||
}
|
||||
Log.w(TAG, "State for {" + mountPoint + "} = {" + state + "}");
|
||||
Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}");
|
||||
mLegacyState = state;
|
||||
}
|
||||
|
||||
@@ -455,14 +511,18 @@ class MountService extends IMountService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
void onVoldConnected() {
|
||||
/**
|
||||
*
|
||||
* Callback from NativeDaemonConnector
|
||||
*/
|
||||
public void onDaemonConnected() {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
if (!getVolumeState(Environment.getExternalStorageDirectory().getPath())
|
||||
.equals(Environment.MEDIA_MOUNTED)) {
|
||||
try {
|
||||
mountMedia(Environment.getExternalStorageDirectory().getPath());
|
||||
mountVolume(Environment.getExternalStorageDirectory().getPath());
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Connection-mount failed");
|
||||
}
|
||||
@@ -474,7 +534,7 @@ class MountService extends IMountService.Stub {
|
||||
}
|
||||
|
||||
try {
|
||||
boolean avail = mListener.getShareAvailable("ums");
|
||||
boolean avail = getShareAvailable("ums");
|
||||
notifyShareAvailabilityChange("ums", avail);
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Failed to get share availability");
|
||||
@@ -483,6 +543,49 @@ class MountService extends IMountService.Stub {
|
||||
}.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);
|
||||
@@ -587,7 +690,7 @@ class MountService extends IMountService.Stub {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
mountMedia(path);
|
||||
mountVolume(path);
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Failed to mount media on insertion", ex);
|
||||
}
|
||||
@@ -903,29 +1006,62 @@ class MountService extends IMountService.Stub {
|
||||
}
|
||||
|
||||
public String[] getSecureContainerList() throws IllegalStateException {
|
||||
return mListener.listAsec();
|
||||
ArrayList<String> rsp = mConnector.doCommand("list_asec");
|
||||
|
||||
String[] rdata = new String[rsp.size()];
|
||||
int idx = 0;
|
||||
|
||||
for (String line : rsp) {
|
||||
String []tok = line.split(" ");
|
||||
int code = Integer.parseInt(tok[0]);
|
||||
if (code == VoldResponseCode.AsecListResult) {
|
||||
rdata[idx++] = tok[1];
|
||||
} else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
|
||||
return rdata;
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("Unexpected response code %d", code));
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Got an empty response");
|
||||
}
|
||||
|
||||
public String createSecureContainer(String id, int sizeMb, String fstype,
|
||||
String key, int ownerUid) throws IllegalStateException {
|
||||
return mListener.createAsec(id, sizeMb, fstype, key, ownerUid);
|
||||
String cmd = String.format("create_asec %s %d %s %s %d",
|
||||
id, sizeMb, fstype, key, ownerUid);
|
||||
mConnector.doCommand(cmd);
|
||||
return getSecureContainerPath(id);
|
||||
}
|
||||
|
||||
public void finalizeSecureContainer(String id) throws IllegalStateException {
|
||||
mListener.finalizeAsec(id);
|
||||
mConnector.doCommand(String.format("finalize_asec %s", id));
|
||||
}
|
||||
|
||||
public void destroySecureContainer(String id) throws IllegalStateException {
|
||||
mListener.destroyAsec(id);
|
||||
mConnector.doCommand(String.format("destroy_asec %s", id));
|
||||
}
|
||||
|
||||
public String mountSecureContainer(String id, String key, int ownerUid) throws IllegalStateException {
|
||||
return mListener.mountAsec(id, key, ownerUid);
|
||||
public String mountSecureContainer(String id, String key,
|
||||
int ownerUid) throws IllegalStateException {
|
||||
String cmd = String.format("mount_asec %s %s %d",
|
||||
id, key, ownerUid);
|
||||
mConnector.doCommand(cmd);
|
||||
return getSecureContainerPath(id);
|
||||
}
|
||||
|
||||
public String getSecureContainerPath(String id) throws IllegalStateException {
|
||||
return mListener.getAsecPath(id);
|
||||
}
|
||||
ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
|
||||
|
||||
for (String line : rsp) {
|
||||
String []tok = line.split(" ");
|
||||
int code = Integer.parseInt(tok[0]);
|
||||
if (code == VoldResponseCode.AsecPathResult) {
|
||||
return tok[1];
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("Unexpected response code %d", code));
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Got an empty response");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user