热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android挂载usb设备,androidusb挂载分析MountService启动

在androidusb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下Mount

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

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

[cpp] view plain copy print ?

try{

/*

* NotificationManagerService is dependant on MountService,

* (for media / usb notifications) so we must start MountService first.

*/

Slog.i(TAG, "Mount Service");

ServiceManager.addService("mount",newMountService(context));

} catch(Throwable e) {

Slog.e(TAG, "Failure starting Mount Service", e);

} 这里new 了一个

MountService,并把service添加到了

ServiceManager,我们看下MountService的构造函数:

[cpp] view plain copy print ?

/**

* Constructs a new MountService instance

*

* @param context  Binder context for this service

*/

publicMountService(Context context) {

mContext = context;

// XXX: This will go away soon in favor of IMountServiceObserver

mPms = (PackageManagerService) ServiceManager.getService("package");//获取包管理服务

mContext.registerReceiver(mBroadcastReceiver,

newIntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);//注册广播接收器

mHandlerThread = newHandlerThread("MountService");//处理消息

mHandlerThread.start();

mHandler = newMountServiceHandler(mHandlerThread.getLooper());

// Add OBB Action Handler to MountService thread.

mObbActionHandler = newObbActionHandler(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 = newNativeDaemonConnector(this,"vold",

PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);

mReady = false;

Thread thread=newThread(mConnector, VOLD_TAG);

thread.start();

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

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

[cpp] view plain copy print ?

publicvoidrun() {

while(true) {

try{

listenToSocket();

} catch(Exception e) {

Slog.e(TAG, "Error in NativeDaemonConnector", e);

SystemClock.sleep(5000);

}

}

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

[cpp] view plain copy print ?

privatevoidlistenToSocket() throws IOException {

LocalSocket socket = null;

try{

socket = newLocalSocket();

LocalSocketAddress address = newLocalSocketAddress(mSocket,//这里mSocket=“vold"

LocalSocketAddress.Namespace.RESERVED);              //注意这里的RESERVED

socket.connect(address);              //连接到vold模块监听的套接字处

mCallbacks.onDaemonConnected();       //实现在MountService中

InputStream inputStream = socket.getInputStream();

mOutputStream = socket.getOutputStream();

byte[] buffer = newbyte[BUFFER_SIZE];

intstart = 0;

while(true) {

intcount = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取消息

if(count break;

// Add our starting point to the count and reset the start.

count += start;

start = 0;

for(inti = 0; i

if(buffer[i] == 0) {

String event = newString(buffer, start, i - start);

if(LOCAL_LOGD) Slog.d(TAG, String.format("RCV , event));

String[] tokens = event.split(" ");

try{

intcode = 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 intremaining = BUFFER_SIZE - start;

System.arraycopy(buffer, start, buffer, 0, remaining);

start = remaining;

} else{

start = 0;

}

}

} catch(IOException ex) {

Slog.e(TAG, "Communications error", ex);

throwex;

} 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层代码,最后调用的:

[cpp] view plain copy print ?

intsocket_local_client_connect(intfd,constchar*name,intnamespaceId,

inttype)

{

structsockaddr_un addr;

socklen_t alen;

size_tnamelen;

interr;

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

if(err

gotoerror;

}

if(connect(fd, (structsockaddr *) &addr, alen)

gotoerror;

}

returnfd;

error:

return-1;

}

/**

* connect to peer named "name"

* returns fd or -1 on error

*/

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

[cpp] view plain copy print ?

caseANDROID_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(structsockaddr_un, sun_path) - 1) {

gotoerror;

}

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:

[cpp] view plain copy print ?

intsocket_local_client(constchar*name,intnamespaceId,inttype)

{

ints;

s = socket("color:#ff0000;">AF_LOCAL, type, 0);

if(s return-1;

if( 0 > socket_local_client_connect(s, name, namespaceId, type)) {

close(s);

return-1;

}

returns;

} 这样,就建立了一条从FrameWork层到vold层的通信链路,后面FrameWork层就等待Vold发送消息过来了。。。FrameWork层的通信也ok了,就可以等待U盘挂载了。。

转自:http://blog.csdn.net/new_abc/article/details/7400740



推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
author-avatar
六尾11
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有