回顾:前贴主要分析了Android存储系统的架构和原理图,简要的介绍了整个从Kernel-->Vold-->上层MountService之间的数据传输流程,在这样的基础上,我们开始今天的源码分析!
【源码分析】
1. Vold的main函数
Vold也是通过init进程启动,它在init.rc中的定义如下:
XML/HTML代码
- service vold /system/bin/vold
- class core
- socket vold stream 0660 root mount
- ioprio be 2
Vold服务放到了core分组,这就意味着系统启动时,它就会被init进程启动。这里定义的一个socket,主要用语Vold和Java层的MountService通信。
Vold模块的源代码位于system/vold,我们看看入口函数main(),代码如下:
C++代码
- int main() {
- VolumeManager *vm;
- CommandListener *cl;
- NetlinkManager *nm;
- SLOGI("Vold 2.1 (the revenge) firing up");
-
- mkdir("/dev/block/vold", 0755);
- klog_set_level(6);
- if (!(vm = VolumeManager::Instance())) {
- exit(1);
- };
-
- if (!(nm = NetlinkManager::Instance())) {
- exit(1);
- };
- cl = new CommandListener();
- vm->setBroadcaster((SocketListener *) cl);
- nm->setBroadcaster((SocketListener *) cl);
- if (vm->start()) {
- exit(1);
- }
- if (process_config(vm)) {
- SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno));
- }
- cryptfs_pfe_boot();
- if (nm->start()) {
- exit(1);
- }
- coldboot("/sys/block");
- if (cl->startListener()) {
- exit(1);
- }
-
- while(1) {
- sleep(1000);
- }
- SLOGI("Vold exiting");
- exit(0);
- }
main函数的主要工作是创建3个对象:VolumeManager、NetlinkManager和CommandListener,同时将CommandListener对象分别设置到了VolumeManager对象和NetlinkManager对象中。
从前贴的架构图中可以发现,CommandListener对象用于和Java层的NativeDaemonConnector对象进行socket通信,因此,无论是VolumeManager对象还是NetlinkManager对象都需要拥有CommandListener对象的引用。
2. 监听驱动发出的消息—Vold的NetlinkManager对象
NetlinkManager对象的主要工作是监听驱动发出的uevent消息。
main()函数中调用NetlinkManager类的静态函数Instance()来创建NetlinkManager对象,代码如下:
C++代码
- NetlinkManager *NetlinkManager::Instance() {
- if (!sInstance)
- sInstance = new NetlinkManager();
- return sInstance;
- }
看下NetlinkManager的构造函数,代码如下:
C++代码
- NetlinkManager::NetlinkManager() {
- mBroadcaster = NULL;
- }
NetlinkManager的构造函数只是对mBroadcaster进行了初始化。我们可以发现main()函数中通过调用NetlinkManager的setBroadcaster()函数来给变量mBroadcaster重新赋值。
C++代码
- nm->setBroadcaster((SocketListener *) cl);
main()函数还调用了NetlinkManager的start()函数,我们观察一下NetlinkManager中的start()方法,代码如下:
C++代码
- int NetlinkManager::start() {
- struct sockaddr_nl nladdr;
- int sz = 64 * 1024;
- int on = 1;
-
- 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 SO_RCVBUFFORCE option: %s", strerror(errno));
- goto out;
- }
-
- if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
- goto out;
- }
-
- if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
- SLOGE("Unable to bind uevent socket: %s", strerror(errno));
- goto out;
- }
-
- mHandler = new NetlinkHandler(mSock);
- if (mHandler->start()) {
- SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
- goto out;
- }
-
- return 0;
-
- out:
- close(mSock);
- return -1;
- }
我们看一下NetlinkManager的家族关系,如下图:
上面的虚线为启动时的调用流程:
(1) class NetlinkManager(在其start函数中创建了NetlinkHandler对象,并把创建的socket作为参数)
(2)class NetlinkHandler: public NetlinkListener(实现了onEvent)
(3) class NetlinkListener : public SocketListener(实现了onDataAvailable)
(4) class SocketListener(实现了runListener,在一个线程中通过select查看哪些socket有数据,通过调用onDataAvailable来读取数据)。
总结:此贴主要分析了Vold的main()函数和NetlinkManager对象的源码,通过源码了解对象的创建时机和函数调用流程,下一贴会继续从NetlinkHandler的start()方法深入分析,继续源码的学习,很快会与大家见面,欢迎大家批评指正,我们互相学习。