您的位置:首页 > 移动开发 > Android开发

Android4.4----Vold挂载管理分析USB挂载(四)

2015-06-05 14:55 447 查看
在上一篇Android4.4----Vold挂载管理分析USB挂载(三)中,介绍了VolumeManager接收到kernel发出的uevent事件后,向上层发送了VolumeStateChange和VolumeDiskInserted两个广播,这里我们研究一下framework接收到这两个广播后的处理动作!

Volume发出广播后,会在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java中的onEvent()方法中接收!

先分析VolumeStateChange!

public boolean onEvent(int code, String raw, String[] cooked) {
if (DEBUG_EVENTS) {
StringBuilder builder = new StringBuilder();
builder.append("onEvent::");
builder.append(" raw= " + raw);
if (cooked != null) {
builder.append(" cooked = " );
for (String str : cooked) {
builder.append(" " + str);
}
}
Slog.i(TAG, builder.toString());
}
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]));//重点分析一下这个函数,通过打印我们可以知道cooked[2]=CAA5-CD0B, cooked[3]=/mnt/usb/sda1,Integer.parseInt(cooked[7])=0, Integer.parseInt(cooked[10])=1
</pre><pre>
加打印可以看到在onEvent中接收到的信息如下:

I/MountService( 1419): onEvent:: raw= 605 Volume CAA5-CD0B /mnt/usb/sda1 state changed from 0 (No-Media) to 1 (Idle-Unmounted) cooked =  605 Volume CAA5-CD0B /mnt/usb/sda1 state changed from 0 (No-Media) to 1 (Idle-Unmounted)
其中605就是VolumeStateChange;

public static final int VolumeStateChange              = 605;
public static final int VolumeUuidChange               = 613;
public static final int VolumeUserLabelChange          = 614;
public static final int VolumeDiskInserted             = 630;
public static final int VolumeDiskRemoved              = 631;
public static final int VolumeBadRemoval               = 632;


查看notifyVolumeStateChange函数

private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
// MStar Android Patch Begin
StorageVolume volume = null;
String state;
// MStar Android Patch End
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
state = getVolumeState(path);
}

if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);//查看state为:notifyVolumeStateChange::removed

String action = null;
....................
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 (!state.equals(
Environment.MEDIA_BAD_REMOVAL) && !state.equals(
Environment.MEDIA_NOFS) && !state.equals(
Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
// MStar Android Patch Begin
synchronized (mVolumesLock) {
if (volume == null) {
volume = StorageVolume.fromTemplate(mSecondStorageTemplate, new File(path), null);
addVolumeLocked(volume);
}
}
// MStar Android Patch End
updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
action = Intent.ACTION_MEDIA_UNMOUNTED;
}
..................
if (action != null) {
sendStorageIntent(action, volume, UserHandle.ALL);
}
private void updatePublicVolumeState(StorageVolume volume, String state) {
final String path = volume.getPath();

// MStar Android Patch Begin
String oldState;
synchronized (mVolumesLock) {
oldState = mVolumeStates.put(path, state);
volume.setState(state);
if (oldState == null) {
oldState = Environment.MEDIA_REMOVED;
}
}

if (state.equals(oldState)) {
Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
state, state, path));
return;
}
.............
if (Environment.MEDIA_UNMOUNTED.equals(state)) {
pmGuardThread.registerMediaEvents(PMGuardThread.MEDIA_UNMOUNT_EVENT);

/*
* 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));
}
..................
synchronized (mListeners) {
for (int i = mListeners.size() -1; i >= 0; i--) {
MountServiceBinderListener bl = mListeners.get(i);
try {
bl.mListener.onStorageStateChanged(path, oldState, state);//这里就会通过onStorageStateChanged函数来把挂载状态变化发出去,其他重写了这个函数的地方就能接收的到,比如systemUI中的StorageNotification中
} catch (RemoteException rex) {
Slog.e(TAG, "Listener dead");
mListeners.remove(i);
} catch (Exception ex) {
Slog.e(TAG, "Listener failed", ex);
}
}
}
private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) {
final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath()));
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume);
Slog.d(TAG, "sendStorageIntent " + intent + " to " + user);
mContext.sendBroadcastAsUser(intent, user);//这里会把相应的广播发出去
}

在SystemUI\src\com\android\systemui\usb\StorageNotification.java中

public void onStorageStateChanged(final String path,
final String oldState, final String newState) {
Log.d(TAG,"Javen.tang onStorageStateChanged path="+path+"oldState="+oldState+"newState="+newState);
mAsyncEventHandler.post(new Runnable() {
@Override
public void run() {
onStorageStateChangedAsync(path, oldState, newState);
}
});
}
}
这样就把挂载状态信息就传递到应用层了!

接着我们再分析VolumeDiskInserted

同样也是在MountService中的onEvent()中

public boolean onEvent(int code, String raw, String[] cooked) {
if (DEBUG_EVENTS) {
StringBuilder builder = new StringBuilder();
builder.append("onEvent::");
builder.append(" raw= " + raw);
if (cooked != null) {
builder.append(" cooked = " );
for (String str : cooked) {
builder.append(" " + str);
}
}
Slog.i(TAG, builder.toString());
}
.....................
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>)
String action = null;
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) {
Slog.e(TAG, "Failed to parse major/minor", ex);
}

final StorageVolume volume;
final String state;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
state = mVolumeStates.get(path);
}

if (code == VoldResponseCode.VolumeDiskInserted) {
new Thread("MountService#VolumeDiskInserted") {
@Override
public void run() {
try {
int rc;
if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {//执行doMountVolume(path)
Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
}
} catch (Exception ex) {
Slog.w(TAG, "Failed to mount media on insertion", ex);
}
}
}.start();
}
查看一下在onEvent()中接收到的数据打印:

I/MountService( 1419): onEvent:: raw= 630 Volume CAA5-CD0B /mnt/usb/sda1 Partition Added (8:1) cooked =  630 Volume CAA5-CD0B /mnt/usb/sda1 Partition Added (8:1)
private int doMountVolume(String path) {
int rc = StorageResultCode.OperationSucceeded;

final StorageVolume volume;
synchronized (mVolumesLock) {
volume = mVolumesByPath.get(path);
}

if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
try {
mConnector.execute("volume", "mount", path);//发送命令
} catch (NativeDaemonConnectorException e) {
/*
* Mount failed for some reason
*/
public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)
throws NativeDaemonConnectorException {
final long startTime = SystemClock.elapsedRealtime();

final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();

final StringBuilder rawBuilder = new StringBuilder();
final StringBuilder logBuilder = new StringBuilder();
final int sequenceNumber = mSequenceNumber.incrementAndGet();

makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);

final String rawCmd = rawBuilder.toString();
final String logCmd = logBuilder.toString();

log("SND -> {" + logCmd + "}");

synchronized (mDaemonLock) {
if (mOutputStream == null) {
throw new NativeDaemonConnectorException("missing output stream");
} else {
try {
Slog.d(TAG,"mOutputStream.write rawCmd="+rawCmd);//这里看打印为mOutputStream.write rawCmd=5 volume mount /mnt/usb/sda1
mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new NativeDaemonConnectorException("problem sending command", e);
}
}
}
这里通过NativeDaemonConnector向Vold发送命令,在system/core/libsysutils/src/SocketListener.cpp中有个runListener()函数一直在监听socket,接收从上层发送过来的指令,跟着会调用到FrameworkListener::onDataAvailable()来处理接收到的消息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: