【转】 android vold浅析(1)
(2011-11-29 17:41:58)
标签:
android
杂谈
vold的全称是volume daemon。实际上是负责完成系统的CDROM,
USB大容量存储,MMC卡等扩展存储的挂载任务自动完成的守护进程。它提供的主要特点是支持这些存储外设的热插拔。这里有GNU/Linux
vold的介绍[http://vold.sourceforge.net/]。在Android上的这个vold系统和GNU/Linux的之间存在很大的差异,这里我们主要是分析Android上的vold系统的处理过程。
Vold处理过程大致分为三步:
1.创建链接:
在
vold作为一个守护进程,一方面接受驱动的信息,并把信息传给应用层;另一方面接受上层的命令并完成相应。所以这里的链接一共有两条:
(1)vold socket: 负责vold与应用层的信息传递;
(2)访问udev的socket: 负责vold与底层的信息传递;
这两个链接都是在进程的一开始完成创建的。
2.引导:
这里主要是在vold启动时,对现有外设存储设备的处理。首先,要加载并解析vold.conf,
并检查挂载点是否已经被挂载(注:这里检查挂载点的用意不是很清楚!); 其次,执行MMC卡挂载;
最后,处理USB大容量存储。
3.事件处理:
这里通过对两个链接的监听,完成对动态事件的处理,以及对上层应用操作的响应。
我们分析具体的代码
makefile文件位于/system/vold文件夹下的Android.mk
入口函数在main.cpp中
int main() {
VolumeManager *vm;
CommandListener *cl;
NetlinkManager *nm;
SLOGI("Vold 2.1 (the revenge) firing up");
mkdir("/dev/block/vold", 0755);
if (!(vm = VolumeManager::Instance())) {
SLOGE("Unable to create VolumeManager");
exit(1);
};
//创建一个VolumeManager实例,具体的构造函数位于文件VolumeManager.cpp中
if (!(nm = NetlinkManager::Instance())) {
SLOGE("Unable to create NetlinkManager");
exit(1);
};
//实例化一个NetlinkManager对象,具体的构造函数位于文件NetlinkManager.cpp中
cl = new CommandListener();
**************************************************
**********************
//构造一个CommandListener对象,这个类定义在文件CommandListener.h中,继承了类FrameworkListener,这个类定义在sysutils/FrameworkListener.h中
//这个类又继承了类SocketListener,这个类定义在文件SocketListener.h中,我们看文件/system/core/libsysutils/src/SocketListener.cpp
//SocketListener::SocketListener(const char *socketName, bool
listen) {
mListen = listen;
mSocketName = socketName;
mSock = -1;
pthread_mutex_init(&mClientsLock, NULL);
mClients = new SocketClientCollection();
//typedef android::List
*> SocketClientCollection;
SocketClientCollection是一个SocketClient类对象的集合
} */
//
//文件/system/core/libsysutils/src/FrameworkListener.cpp中定义了FrameworkListener类的构造函数
FrameworkListener::FrameworkListener(const char *socketName)
:
SocketListener(socketName, true) {
mCommands = new FrameworkCommandCollection();
//typedef android::List
*> FrameworkCommandCollection;
} */
//回头我们再看看CommandListener的构造函数
CommandListener::CommandListener() :
FrameworkListener("vold") {
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ShareCmd());
registerCmd(new StorageCmd());
registerCmd(new XwarpCmd());
} */
//这里会调用其继承类的protected成员函数registerCmd,其参数是一个指向类FrameworkCommand的指针。类CommandListener包含几个私有的内部类class
DumpCmd : public VoldCommand
// class VolumeCmd : public VoldCommand
class ShareCmd : public VoldCommand
class AsecCmd : public VoldCommand
class StorageCmd : public VoldCommand
class XwarpCmd : public VoldCommand
我们分析如何实例化一个DumpCmd
CommandListener::DumpCmd::DumpCmd() :
VoldCommand("dump") {
}
其父类在文件system/vold/VoldCommand.cpp中
VoldCommand::VoldCommand(const char *cmd) :
FrameworkCommand(cmd) {
}
其父类FrameworkCommand::FrameworkCommand(const char *cmd) {
mCommand = cmd;
}
同理创建VolumeCmd, AsecCmd, ShareCmd, StorageCmd, XwarpCmd
其mCommand私有成员分别取值为 dump, volume, asec, share, storage,
xwarp
我们看看怎么注册指令的
void FrameworkListener::registerCmd(FrameworkCommand *cmd)
{
mCommands->push_back(cmd);
}
mCommands指向FrameworkCommandCollection
而FrameworkCommandCollection是一个包含FrameworkCommand指针的链表
typedef android::List
*> FrameworkCommandCollection
因此这里是将创建的FrameworkCommand指针对象压入链表存储起来
**************************************************
*************************
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) {
SLOGE("Unable to start VolumeManager (%s)",
strerror(errno));
exit(1);
}
//vm->start()始终返回0,什么都不做
if (process_config(vm)) {
SLOGE("Error reading configuration (%s)... continuing anyways",
strerror(errno));
}
if (nm->start()) {
SLOGE("Unable to start NetlinkManager (%s)",
strerror(errno));
exit(1);
}
++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++
nm->start()会调用NetlinkManager类的start()方法
int NetlinkManager::start() {
struct sockaddr_nl nladdr;
int sz = 64 * 1024;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
if ((mSock = socket(PF_NETLINK,
SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
SLOGE("Unable to create uevent socket: %s",
strerror(errno));
return -1;
}
if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz,
sizeof(sz)) < 0) {
SLOGE("Unable to set uevent socket options: %s",
strerror(errno));
return -1;
}
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr))
< 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
return -1;
}
//创建一个socket用于内核空间和用户空间的异步通信,监控系统的hotplug事件
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s",
strerror(errno));
return -1;
}
**************************************************
****************************
线程真正执行的函数:mListen成员用来判定是否监听套接字
Netlink套接字属于udp套接字,非监听套接字,该函数的主要功能体现在,如果该套接字有数据到来,就调用相关函数读取数据。android工程师
void SocketListener::runListener() {
while(1) {//无线循环,一直监听
SocketClientCollection::iterator it;
fd_set read_fds;
int rc = 0;
int max = 0;
FD_ZERO(&read_fds); //清空文件描述符集read_fds
if (mListen) {
max = mSock;
FD_SET(mSock, &read_fds); //添加文件描述符到文件描述符集read_fds
}
FD_SET(mCtrlPipe[0], &read_fds);
//添加管道的读取端文件描述符到read_fds
if (mCtrlPipe[0] > max)
max = mCtrlPipe[0];
pthread_mutex_lock(&mClientsLock);//对容器mClients的操作需要加锁
for (it = mClients->begin(); it !=
mClients->end(); ++it) {
FD_SET((*it)->getSocket(), &read_fds);
//遍历容器mClients的所有成员,调用内联函数getSocket()获取文件描述符,
并添加到文件描述符集read_fds
if ((*it)->getSocket() > max)
max = (*it)->getSocket();
}
pthread_mutex_unlock(&mClientsLock);
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL))
< 0) { // 等待文件描述符中某一文件描述符或者说socket有数据到来
SLOGE("select failed (%s)", strerror(errno));
sleep(1);
continue;
} else if (!rc)
continue;
if (FD_ISSET(mCtrlPipe[0], &read_fds))
break;
if (mListen && FD_ISSET(mSock, &read_fds))
{//监听套接字处理
struct sockaddr addr;
socklen_t alen = sizeof(addr);
int c;
if ((c = accept(mSock, &addr, &alen)) < 0)
{ //接收链接请求,建立连接,如果成功c即为建立链接后的数据交换套接字,
将其添加到mClient容器;
SLOGE("accept failed (%s)", strerror(errno));
sleep(1);
continue;
}
pthread_mutex_lock(&mClientsLock);
mClients->push_back(new SocketClient(c));
pthread_mutex_unlock(&mClientsLock);
}
do {//非监听套接字处理
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it !=
mClients->end(); ++it) {
int fd = (*it)->getSocket();
if (FD_ISSET(fd, &read_fds)) {//调用相应的数据读取函数,读取数据
pthread_mutex_unlock(&mClientsLock);
if (!onDataAvailable(*it)) {
close(fd);
pthread_mutex_lock(&mClientsLock);
delete *it;
it = mClients->erase(it);
pthread_mutex_unlock(&mClientsLock);
}
FD_CLR(fd, &read_fds);
continue;
}
}
pthread_mutex_unlock(&mClientsLock);
} while (0);
}
}
分享:
喜欢
0
赠金笔
加载中,请稍候......
评论加载中,请稍候...
发评论
登录名: 密码: 找回密码 注册记住登录状态
昵 称:
评论并转载此博文
发评论
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。