android usb挂载分析---MountService启动
在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是一样的。NativeDaemonConnector实现了Runnable接口
接下来调用 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(
system/core/libcutils/socket_local_client.c)进行连接工作,我们看下他的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盘挂载了。。
android usb挂载分析---MountService启动的更多相关文章
- android usb挂载分析----vold启动
http://blog.csdn.net/new_abc/article/details/7396733 前段时间做了下usb挂载的,现在出了几个bug,又要把流程给梳理下,顺便也把相关的知识总结下, ...
- android usb挂载分析---vold处理内核消息
android usb挂载分析---vold处理内核消息 分类: u盘挂载2012-03-29 22:25 3215人阅读 评论(0) 收藏 举报 androidactioniteratordiskd ...
- android usb挂载分析
http://blog.csdn.net/new_abc/article/details/7409018
- [Openwrt 扩展上篇]USB挂载&U盘启动&Samba共享
最近偷懒,没学习,反想起自己的路由刷了Openwrt,正好闲置了一个硬盘想拿来做个网络硬盘,于是开始了折腾....这里将不谈论如何刷Openwrt,如何ssh,如何添加PPOE,如何添加相对应服务的包 ...
- [Openwrt 项目开发笔记]:USB挂载& U盘启动(三)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 在上一篇中,我结合Netgear Wndr370 ...
- Appium Android Bootstrap源代码分析之启动执行
通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...
- android文件系统挂载分析(1)---正常开机挂载
未完,更新中 ... "android"系列分为三部分: 1.正常开机挂载 2.encryption 3.dm-verity 我们知道android有很多分区,如"sys ...
- Appium Android Bootstrap源码分析之启动运行
通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...
- Android USB驱动源码分析(-)
Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...
随机推荐
- JavaScript学习总结(十七)——Javascript原型链的原理
一.JavaScript原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法.其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在JavaScript中, ...
- php:二进制处理
直接上代码 <?php #字符串 #php中字符串就是二进制,不用特别转化 #方法1:直接把字符串当成二进制 $c = "ccc"; var_dump($c, bin2hex ...
- PHP:urlencode
urlencode是用于对字符串进行编码,使得所有字符都能被放入url中,而不会被解析器误解. 正如html中的<>这样的符号是标记符,如果正文中存在<,要把它转义为< url ...
- Ubuntu 下安装 nfs
1先安装sudo apt-get install nfs-kernel-server(安装nfs-kernel-server时,apt会自动安装nfs-common和portmap) 分开看就是1.服 ...
- ecshop后台管理显示扩展分类
ecshop 后台商品列表默认只显示分类下的商品,而不显示扩展分类中的商品,以下是我个人给出的解决方法: 打开admin/includes/lib_goods.php 第839行左右的位置 可以看到如 ...
- table导出到excel的两种方法
1. 用table2excel 的js文件,这种方法没有IE兼容性 需要在文件中导入 <script type="text/javascript" src="< ...
- textarea内容太多, 鼠标点击全部显示
strRight+="<td bordercolor='#DEDEDE' width='500px' height='50'><div title='"+data ...
- HDU 5963 博弈
http://acm.hdu.edu.cn/showproblem.php?pid=5963 题目大意:中文题 思路:看ICPC camp好了,简单易懂:https://async.icpc-camp ...
- Android中实现滑动翻页—使用ViewFlipper(dp和px之间进行转换)
Android中实现滑动翻页—使用ViewFlipper(dp和px之间进行转换) Android中dp和px之间进行转换 在xml布局文件中,我们既可以设置px,也可以设置dp(或者dip).一般情 ...
- webview h5页面 关闭
说明:在 ios 安卓 客户端上的h5页面执行完毕关闭h5页面 引入的js在文件中的xhdoctor_mobile.rar