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

android usb挂载分析---MountService启动

2012-07-24 19:44 537 查看
关于vold的一系列文章都是转自:http://my.csdn.net/new_abc

android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动,首先看下其大概流程:



MountService的启动在SystemServer.java中,有如下代码:

try {
/*
* NotificationManagerService is dependant on MountService,
* (for media / usb notifications) so we must start MountService first.
*/
Slog.i(TAG, "Mount Service");
ServiceManager.addService("mount", new MountService(context));
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Mount Service", e);
}


这里new 了一个MountService,并把service添加到了ServiceManager,我们看下MountService的构造函数:

/**
* Constructs a new MountService instance
*
* @param context  Binder context for this service
*/
public MountService(Context context) {
mContext = context;

// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");//获取包管理服务

mContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);//注册广播接收器

mHandlerThread = new HandlerThread("MountService");//处理消息
mHandlerThread.start();
mHandler = new MountServiceHandler(mHandlerThread.getLooper());

// Add OBB Action Handler to MountService thread.
mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());

/*
* Vold does not run in the simulator, so pretend the connector thread
* ran and did its thing.
*/
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
mReady = true;
mUmsEnabling = true;
return;
}

/*
* Create the connection to vold with a maximum queue of twice the
* amount of containers we'd ever expect to have. This keeps an
* "asec list" from blocking a thread repeatedly.
*/
mConnector = new NativeDaemonConnector(this, "vold",
PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
mReady = false;
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
}


后面new 了一个NativeDaemonConnector,注意这里传递了一个"vold"字符串,跟我们在vold启动的时候传给CommandListener是一样的。

接下来调用 thread.start()启动线程,我们看下它的run函数

public void run() {

while (true) {
try {
listenToSocket();
} catch (Exception e) {
Slog.e(TAG, "Error in NativeDaemonConnector", e);
SystemClock.sleep(5000);
}
}
}


在循环中调用listenToSocket函数,看下这个函数

private void listenToSocket() throws IOException {
LocalSocket socket = null;

try {
socket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(mSocket,   //这里mSocket=“vold"
LocalSocketAddress.Namespace.RESERVED);              //注意这里的RESERVED

socket.connect(address);              //连接到vold模块监听的套接字处
mCallbacks.onDaemonConnected();       //实现在MountService中

InputStream inputStream = socket.getInputStream();
mOutputStream = socket.getOutputStream();

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);
if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));

String[] tokens = event.split(" ");
try {
int code = Integer.parseInt(tokens[0]);

if (code >= ResponseCode.UnsolicitedInformational) {
try {
if (!mCallbacks.onEvent(code, event, tokens)) {//实现在MountService中
Slog.w(TAG, String.format(
"Unhandled event (%s)", event));
}
} catch (Exception ex) {
Slog.e(TAG, String.format(
"Error handling '%s'", event), ex);
}
}
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 (this) {
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);
}
}
}


onDaemonConnected的实现在MountServices吕,将向下下发volume list消息 获取到了磁盘的标签,挂载点与状态,调用connect函数连接到vold模块,connetc最终调用native函数connectLocal进行连接工作,我们看下他的jni层代码,最后调用的:

int socket_local_client_connect(int fd, const char *name, int namespaceId,
int type)
{
struct sockaddr_un addr;
socklen_t alen;
size_t namelen;
int err;

err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);

if (err < 0) {
goto error;
}

if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
goto error;
}

return fd;

error:
return -1;
}

/**
* connect to peer named "name"
* returns fd or -1 on error
*/


我们再跟进socket_make_sockaddr_un函数,这时namespaceId传的ANDROID_SOCKET_NAMESPACE_RESERVED,所以会执行下面几句:

case ANDROID_SOCKET_NAMESPACE_RESERVED:
namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
/* unix_path_max appears to be missing on linux */
if (namelen > sizeof(*p_addr)
- offsetof(struct sockaddr_un, sun_path) - 1) {
goto error;
}

strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);  //  ANDROID_RESERVED_SOCKET_PREFIX="/dev/socket/"
strcat(p_addr->sun_path, name);
break;


注意在前面 connect 函数中的套接字的构造,使用了AF_LOCAL:

int socket_local_client(const char *name, int namespaceId, int type)
{
int s;

s = socket(<span style="color:#ff0000;">AF_LOCAL</span>, type, 0);
if(s < 0) return -1;

if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
close(s);
return -1;
}

return s;
}


这样,就建立了一条从FrameWork层到vold层的通信链路,后面FrameWork层就等待Vold发送消息过来了。。。

FrameWork层的通信也ok了,就可以等待U盘挂载了。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: