前篇地址
前一篇讲到SDCard unmout onEvent 发送socket 到框架层,接下来分析框架层得到数据后的流程。
MoutService
当android 系统启动时,system将MountService 添加到启动服务里面,而MountService 会开启一个线程来运行NativeDaemonConnector,由它来监听vold的消息,代码:
mConnector =
new NativeDaemonConnector(
this,
" vold ", MAX_CONTAINERS *
2, VOLD_TAG);
mReady =
false;
Thread thread =
new Thread(mConnector, VOLD_TAG);
thread.start();
该函数运行在MountService的构造函数里面,而NativeDaemonConnector 本身就是继承自Runnable。
NativeDaemonConnector
Framework与vold 的通信是通过socket来实现的,不过该socket 由 android做了一个封装,LocalSocket 实现的socket功能。
NativeDaecomConnector 位于framework/base/service/java/com/android/server目录下, 监听vold 的消息代码在继承自Runnable对象的run方法里面 :
@Override
public void run() {
HandlerThread thread =
new HandlerThread(TAG +
" .CallbackHandler ");
thread.start();
mCallbackHandler =
new Handler(thread.getLooper(),
this);
while (
true) {
try {
listenToSocket();
}
catch (Exception e) {
Slog.e(TAG,
" Error in NativeDaemonConnector ", e);
SystemClock.sleep(
5000);
}
}
}
NativeDaemonConnector 类实例化了一个LocalSocket来与vold 通信。LocalSocket 里面有一个类LocalSocketImpl,该类部分是通过JNI实现的。
关于socket 内部如何通信,这个不是我们所关心的内容,因为如果要深入进去估计没完没了,有兴趣的朋友可以参考源码进入SocketListener查看:
建立连接
SocketListener::SocketListener
当main初始化CommandListener 后,会为socketName 传入一个叫vold 的字符串
SocketListener::startListener
SocketListener::runListener
bool FrameworkListener::onDataAvailable
dispatchCommand 到相应的命令类,并返回一部分消息给上层 FrameworkListener::dispatchCommand
再回过头看NativeDaemonConnector 的listenToSocket,代码中实例化了一个LocalSocketAddress的实例,并传入一个叫"vold"字符串的socket 名称,这与CommandListener中继承了FrameworkListener时给的"vold"名称是一致的,两个socket名称一致则可以互相进行通讯了,代码如下:
private void listenToSocket() throws IOException {
LocalSocket socket =
null;
Slog.w(TAG,String.format(
" NativeDaemonConnector--->listenToSocket:start "));
try {
socket =
new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); socket.connect(address);
InputStream inputStream = socket.getInputStream();
mOutputStream = socket.getOutputStream();
mCallbacks.onDaemonConnected();
byte[] buffer =
new byte[BUFFER_SIZE];
int start =
0;
while (
true) {
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
if (count <
0)
break;
// Add our starting point to the count and reset the start. count += start;
start =
0;
for (
int i =
0; i < count; i++) {
if (buffer[i] ==
0) {
String event = new String(buffer, start, i - start);//解析socket 的数据并获取event if (LOCAL_LOGD) Slog.d(TAG, String.format(
" RCV <- {%s} ",
event));
String[] tokens =
event.split(
" ",
2);
try {
int code = Integer.parseInt(tokens[
0]);
if (code >= ResponseCode.UnsolicitedInformational) {
mCallbackHandler.sendMessage(
mCallbackHandler.obtainMessage(code,
event));//发送消息给handler
}
else {
try {
mResponseQueue.put(
event);
}
catch (InterruptedException ex) {
Slog.e(TAG,
" Failed to put response onto queue ", ex);
}
}
}
catch (NumberFormatException nfe) {
Slog.w(TAG, String.format(
" Bad msg (%s) ",
event));
}
start = i +
1;
}
}
// We should end at the amount we read. If not, compact then // buffer and read again. if (start != count) {
final
int remaining = BUFFER_SIZE - start;
System.arraycopy(buffer, start, buffer,
0, remaining);
start = remaining;
}
else {
start =
0;
}
}
}
catch (IOException ex) {
Slog.e(TAG,
" Communications error ", ex);
throw ex;
}
finally {
synchronized (mDaemonLock) {
if (mOutputStream !=
null) {
try {
mOutputStream.close();
}
catch (IOException e) {
Slog.w(TAG,
" Failed closing output stream ", e);
}
mOutputStream =
null;
}
}
try {
if (socket !=
null) {
socket.close();
}
}
catch (IOException ex) {
Slog.w(TAG,
" Failed closing socket ", ex);
}
}
}
上面代码,通过socket 并event 解析出来,并通handler 发送到handleMessage 中,当handleMessage接收到传过来的消息时,会调用MountService 的onEvent 方法将code和event和sdcard 的状态传递进去。代码如下:
public boolean handleMessage(Message msg) {
String
event = (String) msg.obj;
Slog.w(TAG,String.format(
" NativeDaemonConnector--->handleMessage the event value is "+
event));
try {
if (!
mCallbacks.onEvent(msg.what, event, event.split(" "))) {
Slog.w(TAG, String.format(
" Unhandled event '%s' ",
event));
}
}
catch (Exception e) {
Slog.e(TAG, String.format(
" Error handling '%s' ",
event), e);
}
return true;
}
又回到MountService ,在onEvent里面当接收到的code ==VoldResponseCode.VolumeBadRemoval时会调用updatePublicVolumeState,发送unmount改变的广播,代码如下:
else if (code == VoldResponseCode.VolumeBadRemoval) {
if (DEBUG_EVENTS) Slog.i(TAG,
" Sending unmounted event first ");
/* Send the media unmounted event first */ updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
action = Intent.ACTION_MEDIA_UNMOUNTED;
if (DEBUG_EVENTS) Slog.i(TAG,
" Sending media bad removal ");
updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); action = Intent.ACTION_MEDIA_BAD_REMOVAL;}
到这里,进入updatePublicVolumeState看该函数里的主要代码:
synchronized (mListeners) {
for (
int i = mListeners.size() -
1; i >=
0; i--) {
MountServiceBinderListener bl = mListeners.
get(i);
try {
Slog.w(TAG,
" MountService--->updatePublicVolumeState-->bl.mListener.onStorageStateChanged ");
bl.mListener.onStorageStateChanged(path, oldState, state); }
catch (RemoteException rex) {
Slog.e(TAG,
" Listener dead ");
mListeners.remove(i);
}
catch (Exception ex) {
Slog.e(TAG,
" Listener failed ", ex);
}
}
}
}
并且调用sendStorageIntent 方法将SDCard的Action:android.intent.action.MEDIA_BAD_REMOVAL 和dat:file:///mnt/sdcard 通过这个广播发送出去,代码如下:
private void sendStorageIntent(String action, String path) {
Intent intent =
new Intent(action, Uri.parse(
" file:// " + path));
// add StorageVolume extra intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap.
get(path));
Slog.d(TAG,
" sendStorageIntent " + intent);
mContext.sendBroadcast(intent);
}
再回到 updatePublicVolumeState ,调用了stateChange 后,将状态为632的标识发送到NativeDaemonConnector 的handlemessage,当NativeDaemonConnector 发现SDCard的状态发送改变时,比如unmount 的时候,从632(VolumeBadRemoval)变到605(VolumeStateChange)到onEvent,当onEvent再次得到请求时,进入判断会直接执行notifyVolumeStateChange 函数,代码如下:
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]));
}
notifyStateChange 会调用updatePublicVolumeState通知packageManger SDCard己经unmount.
再回到Vold
由于vold 启动文件一开始就启动了CommandListener的runcommand由于socket 一直在通讯,当发现值改变后,进入以下代码runCommand 方法里面:
else if (!strcmp(argv[
1],
" unmount ")) {
if (argc <
3 || argc >
4 ||
((argc ==
4 && strcmp(argv[
3],
" force ")) &&
(argc ==
4 && strcmp(argv[
3],
" force_and_revert ")))) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
" Usage: volume unmount <path> [force|force_and_revert] ",
false);
return 0;
}
bool force =
false;
bool revert =
false;
if (argc >=
4 && !strcmp(argv[
3],
" force ")) {
force =
true;
}
else if (argc >=
4 && !strcmp(argv[
3],
" force_and_revert ")) {
force =
true;
revert =
true;
}
rc =
vm->unmountVolume(argv[
2], force, revert);
}
这时调用VolumeManage的unmoutVolume。该方法来源于Volume 的unmountVol,调用这个函数会unmount 三个挂载点,并同时调用setState通知框架unmount 成功,可以改变UI等一系列动作。
最后总结
MountService: 实现用于管理存储设备的后台服务
StorageManage:访问MountService 接口,并向应用层提供接口
PackageMangeService:是用于管理系统中所有apk,当SDCard发生变化时,向应用层发送消息
NativeDaemonConnector:创建socket实现mountservice 和vold 的通信
可以这么说:当vold 捕获到uevent 事件,会将事件消息通知framework,framework 进行判断,然后再下发执行命令。
粗糙图
最后附一张比较粗糙的结构图,时间较急,没仔细画好
本文转自 terry_龙 51CTO博客,原文链接:http://blog.51cto.com/terryblog/817015,如需转载请自行联系原作者