首页 > 代码库 > Android -- Vold机制简要分析
Android -- Vold机制简要分析
Android -- Vold机制简要分析
Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SDK的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。
Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是:
- NetlinkManager:用于从kernel中获取SD卡插拔的Uevnet消息
- VolumeManager:管理模块,对NetlinkManager转发的消息做一些处理,并通过CommandListener发送给framework(MountService.java);接着framework会通过套接字下发命令,指引VolumeManager对存储设备做下一步的操作,如挂载/卸载等
- CommandListener:通过socket,实现MountService.java与Vold之间的消息交换
由上述介绍,我们可以得到如下的Vold框架图描述:
有了Vold的架构描述,接下来就开始分析Vold进程的整体流程及实现了。
一、Vold进程的声明与创建
Vold进程的声明与创建过程跟zygote一样,在init.rc中声明,在init进程创建:
service vold /system/bin/vold --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0 class core socket vold stream 0660 root mount socket cryptd stream 0660 root mount ioprio be 2在创建Vold进程时,会为它创建两个socket,用于与framework进行信息交互。其他的细节,参考之前zygote进程创建的介绍。
二、进入Vold主程序
Vold的主程序在/system/vold目录中,直接看main.cpp::main()函数:
int main(int argc, char** argv) { setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); LOG(INFO) << "Vold 3.0 (the awakening) firing up"; LOG(VERBOSE) << "Detected support for:" << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "") << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "") << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : ""); VolumeManager *vm; CommandListener *cl; CryptCommandListener *ccl; NetlinkManager *nm; parse_args(argc, argv); sehandle = selinux_android_file_context_handle(); if (sehandle) { selinux_android_set_sehandle(sehandle); } // Quickly throw a CLOEXEC on the socket we just inherited from init fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);//拿到init进程创建的名为vold的socket句柄,并为它设置FD_CLOEXEC标志位 fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);//同上 mkdir("/dev/block/vold", 0755);//创建/dev/block/vold目录,存放所有subdisk和sdcard的挂载点信息 /* For when cryptfs checks and mounts an encrypted filesystem */ klog_set_level(6); /* Create our singleton managers */ //1、创建VolumeManager if (!(vm = VolumeManager::Instance())) { LOG(ERROR) << "Unable to create VolumeManager"; exit(1); } //2、创建NetlinkManager if (!(nm = NetlinkManager::Instance())) { LOG(ERROR) << "Unable to create NetlinkManager"; exit(1); } if (property_get_bool("vold.debug", false)) { vm->setDebug(true); } //3、创建CommandListener、CryptCommandListener cl = new CommandListener(); ccl = new CryptCommandListener(); vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl); //4、启动VolumeManager if (vm->start()) { PLOG(ERROR) << "Unable to start VolumeManager"; exit(1); } if (process_config(vm)) { PLOG(ERROR) << "Error reading configuration... continuing anyways"; } //6、启动NetlinkManager,处理来自kernel的usb/sdcard插拔消息 if (nm->start()) { PLOG(ERROR) << "Unable to start NetlinkManager"; exit(1); } //7、应用层往/sys/block目录下的uevent文件写"add\n"指令,触发kernel向上发送Uevent消息,获取设备的当前信息 coldboot("/sys/block"); // coldboot("/sys/class/switch"); /* * Now that we‘re up, we can respond to commands */ //8、启动CommandListener if (cl->startListener()) { PLOG(ERROR) << "Unable to start CommandListener"; exit(1); } //9、启动CryptCommandListener if (ccl->startListener()) { PLOG(ERROR) << "Unable to start CryptCommandListener"; exit(1); } // Eventually we‘ll become the monitoring thread while(1) { sleep(1000); } LOG(ERROR) << "Vold exiting"; exit(0); }从代码中的注释可知,Vold主要创了三个对象:NetlinkManager、VolumeManager和CommandListener。根据Vold的架构图,现分别对它们的创建及启动过程进行分析。
(1)、NetlinkManager
主要的处理过程:
- nm = NetlinkManager::Instance()
- nm->setBroadcaster((SocketListener *) cl)
- nm->start()
现按步骤进行分析。
1、NetlinkManager::Instance():
2、NetlinkManager::setBroadcaster():
NetlinkManager *NetlinkManager::Instance() { if (!sInstance) sInstance = new NetlinkManager(); return sInstance; } NetlinkManager::NetlinkManager() { mBroadcaster = NULL; //type:SocketListener*,用来进行socket通信 }这里使用了单例模式来构建NetlinkManager对象,构造函数中只是简单地初始化了成员变量。
2、NetlinkManager::setBroadcaster():
cl = new CommandListener(); nm->setBroadcaster((SocketListener *) cl); void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }setBroadcaster()函数也很简单,为mBroadcast进行赋值。
3、NetlinkManager::start():
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; //创建地址族为PF_NETLINK的socket,与Kernel进行通信;也可以为AF_NETLINK.参照Linux Netlink机制资料 if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, 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);//mHandler、mSock都是成员变量.mHandler对象主要保存了套接字的文件描述符,供后续使用 if (mHandler->start()) {//startListener通过父类方法,在mSock上监听连接请求 SLOGE("Unable to start NetlinkHandler: %s", strerror(errno)); goto out; } return 0; out: close(mSock); return -1; }start()方法中创建了一个句柄值为mSock的套接字,用来和kernel通信;而实际具体的socket信息交互是由NetlinkHandler处理的。
NetlinkHandler的实现有一套继承机制,其实际继承关系如图所示:
按照继承关系,分析它的构建过程:
mHandler = new NetlinkHandler(mSock); NetlinkHandler::NetlinkHandler(int listenerSocket) : NetlinkListener(listenerSocket) { }
/* temporary version until we can get Motorola to update their * ril.so. Their prebuilt ril.so is using this private class * so changing the NetlinkListener() constructor breaks their ril. */ NetlinkListener::NetlinkListener(int socket) : SocketListener(socket, false) { mFormat = NETLINK_FORMAT_ASCII; }
SocketListener::SocketListener(const char *socketName, bool listen) { init(socketName, -1, listen, false); } void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) { mListen = listen;//是否是监听端,这里为false mSocketName = socketName;//保存socket的名字 mSock = socketFd;//保存socket的句柄值,与Kernel通信 mUseCmdNum = useCmdNum; pthread_mutex_init(&mClientsLock, NULL); mClients = new SocketClientCollection();//集合对象,保存类型SocketClient为的变量;保存了socket通信中的客户端对象 }再看NetlinkHandler::start()方法:
int NetlinkHandler::start() { return this->startListener(); }实际调用的是SocketListener::startListener():
int SocketListener::startListener() { return startListener(4); } int SocketListener::startListener(int backlog) { if (!mSocketName && mSock == -1) { SLOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) { SLOGE("Obtaining file descriptor socket ‘%s‘ failed: %s", mSocketName, strerror(errno)); return -1; } SLOGV("got mSock = %d for %s", mSock, mSocketName); fcntl(mSock, F_SETFD, FD_CLOEXEC); } if (mListen && listen(mSock, backlog) < 0) {//如果mListen为true,则监听该socket;表明此socket应该是服务端 SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen)//实际传入的mListen值为false,走此分支 mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));//创建一个SocketClient对象,并保存到集合中 if (pipe(mCtrlPipe)) { SLOGE("pipe failed (%s)", strerror(errno)); return -1; } if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {//创建一个线程,在其中调用threadStart(),根据mListen值,等待接收来自Kernel的Uevent消息 SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0; }创建一个SocketListener对象,并加入mClients中;随后,创建一个线程,并调用SocketListener::threadStart():
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL; } void SocketListener::runListener() { SocketClientCollection pendingList; while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds); if (mListen) { max = mSock; FD_SET(mSock, &read_fds); } FD_SET(mCtrlPipe[0], &read_fds); if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { // NB: calling out to an other object with mClientsLock held (safe) int fd = (*it)->getSocket(); FD_SET(fd, &read_fds); if (fd > max) { max = fd; } } pthread_mutex_unlock(&mClientsLock); SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) { char c = CtrlPipe_Shutdown; TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1)); if (c == CtrlPipe_Shutdown) { break; } continue; } if (mListen && FD_ISSET(mSock, &read_fds)) {//mListener实际为false;监听端,有客户端连接请求 struct sockaddr addr; socklen_t alen; int c; do { alen = sizeof(addr); c = accept(mSock, &addr, &alen);//接受client的连接请求,c是代表client套接字的文件描述符 SLOGV("%s got %d from accept", mSocketName, c); } while (c < 0 && errno == EINTR); if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } fcntl(c, F_SETFD, FD_CLOEXEC); pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c, true, mUseCmdNum));//根据c,创建一个SocketListener对象,并加入到队列中 pthread_mutex_unlock(&mClientsLock); } /* Add all active clients to the pending list first */ pendingList.clear(); pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { SocketClient* c = *it; // NB: calling out to an other object with mClientsLock held (safe) int fd = c->getSocket(); if (FD_ISSET(fd, &read_fds)) {//遍历所有保存的客户端;有数据可读,将该套接字加入到队列中 pendingList.push_back(c); c->incRef(); } } pthread_mutex_unlock(&mClientsLock); /* Process the pending list, since it is owned by the thread, * there is no need to lock it */ while (!pendingList.empty()) { /* Pop the first item from the list */ it = pendingList.begin(); SocketClient* c = *it; pendingList.erase(it); /* Process it, if false is returned, remove from list */ if (!onDataAvailable(c)) {//客户端收到数据,调用NetlinkListener::onDataAvailable()处理 release(c, false);//数据处理失败,则释放socket资源 } c->decRef(); } } }我们初始化NetlinkListener时传入的mListener值为false;上述代码中,会遍历所有保存的客户端socket,如果收到数据,则进行处理。
调用NetlinkListener::onDataAvailable():
(2)、VolumeManager
Vold使用VolumeManager的过程和NetlinkManager类似,也是三步:
bool NetlinkListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); ssize_t count; uid_t uid = -1; bool require_group = true; if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) { require_group = false; } count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket, mBuffer, sizeof(mBuffer), require_group, &uid));//从kernel获取Uevent消息,保存到mBuffer中 if (count < 0) { if (uid > 0) LOG_EVENT_INT(65537, uid); SLOGE("recvmsg failed (%s)", strerror(errno)); return false;//读取失败,则返回false,上层调用则会关闭socket资源 } NetlinkEvent *evt = new NetlinkEvent();//事件的代码封装 if (evt->decode(mBuffer, count, mFormat)) {////解析Uevent数据,填充到NetlinkEvent对象中 onEvent(evt);//NetlinkHandler::onEvent() } else if (mFormat != NETLINK_FORMAT_BINARY) { // Don‘t complain if parseBinaryNetlinkMessage returns false. That can // just mean that the buffer contained no messages we‘re interested in. SLOGE("Error decoding NetlinkEvent"); } delete evt; return true; }先通过socket获取到Uevent数据,再解析并将信息封装到NetlinkEvent对象中。NetlinkHandler::onEvent()分发处理该对象:
void NetlinkHandler::onEvent(NetlinkEvent *evt) { VolumeManager *vm = VolumeManager::Instance(); const char *subsys = evt->getSubsystem(); if (!subsys) {//如果事件和外部存储设备无关,则不处理 SLOGW("No subsystem found in netlink event"); return; } if (!strcmp(subsys, "block")) {//如果Uevent是block子系统 vm->handleBlockEvent(evt);//进入VolumeManager中处理;此处和VolumeManager进行交互 } }如果事件是和外部存储有关,则调用VolumeManager::handleBlockEvent()处理该事件;这里,就看到了NetlinkManager和VolumeManager之间进行数据流动的处理了。
(2)、VolumeManager
Vold使用VolumeManager的过程和NetlinkManager类似,也是三步:
- vm= VolumeManager::Instance()
- vm->setBroadcaster((SocketListener *) cl)
- vm->start()
//单例模式 VolumeManager *VolumeManager::Instance() { if (!sInstance) sInstance = new VolumeManager(); return sInstance; } VolumeManager::VolumeManager() { mDebug = false; mActiveContainers = new AsecIdCollection(); mBroadcaster = NULL; mUmsSharingCount = 0; mSavedDirtyRatio = -1; // set dirty ratio to 0 when UMS is active mUmsDirtyRatio = 0; } void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }直接看VolumeManager::start()的处理:
int VolumeManager::start() { // Always start from a clean slate by unmounting everything in // directories that we own, in case we crashed. unmountAll();//在处理外部设备事件之前,先重置所有状态 // Assume that we always have an emulated volume on internal // storage; the framework will decide if it should be mounted. CHECK(mInternalEmulated == nullptr); mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>( new android::vold::EmulatedVolume("/data/media")); mInternalEmulated->create();//预先设定/data/media,由framework决定是否mount;EmulatedVolume和VolumeBase之间是继承关系,代表不同类型的Volume return 0; }再直接看NetlinkManager和VolumeManager直接信息处理的调用:
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { std::lock_guard<std::mutex> lock(mLock); if (mDebug) { LOG(VERBOSE) << "----------------"; LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction(); evt->dump(); } std::string eventPath(evt->findParam("DEVPATH"));//设备路径 std::string devType(evt->findParam("DEVTYPE"));//设备类型 if (devType != "disk") return; //主次设备号,两者可以描述一个具体设备 int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); dev_t device = makedev(major, minor);//根据主次设备号创建设备 switch (evt->getAction()) { case NetlinkEvent::Action::kAdd: { for (auto source : mDiskSources) { if (source->matches(eventPath)) { // For now, assume that MMC devices are SD, and that // everything else is USB int flags = source->getFlags(); if (major == kMajorBlockMmc) { flags |= android::vold::Disk::Flags::kSd; } else { flags |= android::vold::Disk::Flags::kUsb; } auto disk = new android::vold::Disk(eventPath, device, source->getNickname(), flags);//将信息封装成Disk对象,表示一个检测到的物理设备 disk->create();//Disk::create() mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));//加进集合 break; } } break; } case NetlinkEvent::Action::kChange: { LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed"; for (auto disk : mDisks) { if (disk->getDevice() == device) { disk->readMetadata(); disk->readPartitions(); } } break; } case NetlinkEvent::Action::kRemove: { auto i = mDisks.begin(); while (i != mDisks.end()) { if ((*i)->getDevice() == device) { (*i)->destroy(); i = mDisks.erase(i); } else { ++i; } } break; } default: { LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction(); break; } } }向上层发送各种类型的消息都是通过notifyEvent()函数处理的,其实际就是通过socket来发送的。
同时,Vold的主函数中还有一个重要的函数调用process_config():
static int process_config(VolumeManager *vm) { std::string path(android::vold::DefaultFstabPath()); //获取到vold.fstab文件路径 fstab = fs_mgr_read_fstab(path.c_str());//解析.fstab文件,并返回封装的fstab对象 if (!fstab) { PLOG(ERROR) << "Failed to open default fstab " << path; return -1; } /* Loop through entries looking for ones that vold manages */ bool has_adoptable = false; for (int i = 0; i < fstab->num_entries; i++) { if (fs_mgr_is_voldmanaged(&fstab->recs[i])) { if (fs_mgr_is_nonremovable(&fstab->recs[i])) { LOG(WARNING) << "nonremovable no longer supported; ignoring volume"; continue; } std::string sysPattern(fstab->recs[i].blk_device); std::string nickname(fstab->recs[i].label); int flags = 0; if (fs_mgr_is_encryptable(&fstab->recs[i])) { flags |= android::vold::Disk::Flags::kAdoptable; has_adoptable = true; } if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) || property_get_bool("vold.debug.default_primary", false)) { flags |= android::vold::Disk::Flags::kDefaultPrimary;//is Primary? } vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>( new VolumeManager::DiskSource(sysPattern, nickname, flags)));//添加一个VolumeManager::DiskSource对象,保存了一些信息 } } property_set("vold.has_adoptable", has_adoptable ? "1" : "0"); return 0; }
//解析.fstab配置文件,并返回一个fstab结构对象 struct fstab *fs_mgr_read_fstab(const char *fstab_path) { FILE *fstab_file; int cnt, entries; ssize_t len; size_t alloc_len = 0; char *line = NULL; const char *delim = " \t"; char *save_ptr, *p; struct fstab *fstab = NULL; struct fs_mgr_flag_values flag_vals; #define FS_OPTIONS_LEN 1024 char tmp_fs_options[FS_OPTIONS_LEN]; fstab_file = fopen(fstab_path, "r"); if (!fstab_file) { ERROR("Cannot open file %s\n", fstab_path); return 0; } entries = 0; while ((len = getline(&line, &alloc_len, fstab_file)) != -1) { /* if the last character is a newline, shorten the string by 1 byte */ if (line[len - 1] == ‘\n‘) { line[len - 1] = ‘\0‘; } /* Skip any leading whitespace */ p = line; while (isspace(*p)) { p++; } /* ignore comments or empty lines */ if (*p == ‘#‘ || *p == ‘\0‘) continue; entries++; } if (!entries) { ERROR("No entries found in fstab\n"); goto err; } /* Allocate and init the fstab structure */ fstab = calloc(1, sizeof(struct fstab)); fstab->num_entries = entries; fstab->fstab_filename = strdup(fstab_path); fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec)); fseek(fstab_file, 0, SEEK_SET); cnt = 0; //解析fstab中每行的内容,并进行封装 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) { /* if the last character is a newline, shorten the string by 1 byte */ if (line[len - 1] == ‘\n‘) { line[len - 1] = ‘\0‘; } /* Skip any leading whitespace */ p = line; while (isspace(*p)) { p++; } /* ignore comments or empty lines */ if (*p == ‘#‘ || *p == ‘\0‘) continue; /* If a non-comment entry is greater than the size we allocated, give an * error and quit. This can happen in the unlikely case the file changes * between the two reads. */ if (cnt >= entries) { ERROR("Tried to process more entries than counted\n"); break; } if (!(p = strtok_r(line, delim, &save_ptr))) { ERROR("Error parsing mount source\n"); goto err; } fstab->recs[cnt].blk_device = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_point\n"); goto err; } fstab->recs[cnt].mount_point = strdup(p);//mount的位置 if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_type\n"); goto err; } fstab->recs[cnt].fs_type = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_flags\n"); goto err; } tmp_fs_options[0] = ‘\0‘; fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL, tmp_fs_options, FS_OPTIONS_LEN); /* fs_options are optional */ if (tmp_fs_options[0]) { fstab->recs[cnt].fs_options = strdup(tmp_fs_options); } else { fstab->recs[cnt].fs_options = NULL; } if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_mgr_options\n"); goto err; } fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0); fstab->recs[cnt].key_loc = flag_vals.key_loc; fstab->recs[cnt].verity_loc = flag_vals.verity_loc; fstab->recs[cnt].length = flag_vals.part_length; fstab->recs[cnt].label = flag_vals.label; fstab->recs[cnt].partnum = flag_vals.partnum; fstab->recs[cnt].swap_prio = flag_vals.swap_prio; fstab->recs[cnt].zram_size = flag_vals.zram_size; cnt++; } fclose(fstab_file); free(line); return fstab; err: fclose(fstab_file); free(line); if (fstab) fs_mgr_free_fstab(fstab); return NULL; }fstab文件是Linux下配置分区的一个文件,这部分后续补充......总之,就是解析fstab文件后,会根据配置信息创建DiskSource对象,加入到VolumeManager::mDiskSource中。
(3)、CommandListener
VolumeManager要想向MountService发送消息,就要借助CommandListener。CommandListener有一个较为复杂的继承关系:
CommandListener的创建过程跟NetlinkManager类似:
CommandListener::CommandListener() : FrameworkListener("vold", true) {//vold是socket名称,init.rc文件中声明的一个socket资源,用于和framework通信 registerCmd(new DumpCmd());//注册不同的命令对象 registerCmd(new VolumeCmd()); registerCmd(new AsecCmd()); registerCmd(new ObbCmd()); registerCmd(new StorageCmd()); registerCmd(new FstrimCmd()); }
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) : SocketListener(socketName, true, withSeq) { init(socketName, withSeq); }
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) { init(socketName, -1, listen, useCmdNum); } void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) { mListen = listen;//是否是监听端,与前面不同,这里为true mSocketName = socketName;//保存socket的名字"vold",与MountService通信 mSock = socketFd;//保存socket的句柄值 mUseCmdNum = useCmdNum; pthread_mutex_init(&mClientsLock, NULL); mClients = new SocketClientCollection();//集合对象 }
下面直接看CommandListener->startListener():
int SocketListener::startListener() { return startListener(4); } int SocketListener::startListener(int backlog) { if (!mSocketName && mSock == -1) { SLOGE("Failed to start unbound listener"); errno = EINVAL; return -1; } else if (mSocketName) { if ((mSock = android_get_control_socket(mSocketName)) < 0) {//名为"vold"的socket的句柄值 SLOGE("Obtaining file descriptor socket ‘%s‘ failed: %s", mSocketName, strerror(errno)); return -1; } SLOGV("got mSock = %d for %s", mSock, mSocketName); fcntl(mSock, F_SETFD, FD_CLOEXEC); } if (mListen && listen(mSock, backlog) < 0) {//mListener为true,则监听该socket SLOGE("Unable to listen on socket (%s)", strerror(errno)); return -1; } else if (!mListen)//mListener为false,走此分支 mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)); if (pipe(mCtrlPipe)) { SLOGE("pipe failed (%s)", strerror(errno)); return -1; } if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {//创建一个线程,在其中调用threadStart(),并在mSock代表的套接字上等待客户端的连接请求 SLOGE("pthread_create (%s)", strerror(errno)); return -1; } return 0; }在CommandListener监听流程中,mListene为true;表示这一端是监听侧,等待Client的连接请求。这种场景下,MountService就是这里描述的客户端。MountService在创建过程,会通过创建NativeDaemonConnector对象,去连接名为"vold"的socket,这样两者就可以通信了。
SocketListener::threadStart():
void *SocketListener::threadStart(void *obj) { SocketListener *me = reinterpret_cast<SocketListener *>(obj); me->runListener(); pthread_exit(NULL); return NULL; } void SocketListener::runListener() { SocketClientCollection pendingList; while(1) { SocketClientCollection::iterator it; fd_set read_fds; int rc = 0; int max = -1; FD_ZERO(&read_fds); if (mListen) { max = mSock; FD_SET(mSock, &read_fds); } FD_SET(mCtrlPipe[0], &read_fds); if (mCtrlPipe[0] > max) max = mCtrlPipe[0]; pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { // NB: calling out to an other object with mClientsLock held (safe) int fd = (*it)->getSocket(); FD_SET(fd, &read_fds); if (fd > max) { max = fd; } } pthread_mutex_unlock(&mClientsLock); SLOGV("mListen=%d, max=%d, mSocketName=%s", mListen, max, mSocketName); if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) { if (errno == EINTR) continue; SLOGE("select failed (%s) mListen=%d, max=%d", strerror(errno), mListen, max); sleep(1); continue; } else if (!rc) continue; if (FD_ISSET(mCtrlPipe[0], &read_fds)) { char c = CtrlPipe_Shutdown; TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1)); if (c == CtrlPipe_Shutdown) { break; } continue; } if (mListen && FD_ISSET(mSock, &read_fds)) {//mListener值实际为true;服务端,等待客户端连接请求 struct sockaddr addr; socklen_t alen; int c; do { alen = sizeof(addr); c = accept(mSock, &addr, &alen);//接受MountService发起的socket连接请求, SLOGV("%s got %d from accept", mSocketName, c); } while (c < 0 && errno == EINTR); if (c < 0) { SLOGE("accept failed (%s)", strerror(errno)); sleep(1); continue; } fcntl(c, F_SETFD, FD_CLOEXEC); pthread_mutex_lock(&mClientsLock); mClients->push_back(new SocketClient(c, true, mUseCmdNum));//根据c,创建一个SocketListener对象,并加入到集合中 pthread_mutex_unlock(&mClientsLock); } /* Add all active clients to the pending list first */ pendingList.clear(); pthread_mutex_lock(&mClientsLock); for (it = mClients->begin(); it != mClients->end(); ++it) { SocketClient* c = *it; // NB: calling out to an other object with mClientsLock held (safe) int fd = c->getSocket(); if (FD_ISSET(fd, &read_fds)) {//有数据可读,将该套接字加入到队列中 pendingList.push_back(c); c->incRef(); } } pthread_mutex_unlock(&mClientsLock); /* Process the pending list, since it is owned by the thread, * there is no need to lock it */ while (!pendingList.empty()) { /* Pop the first item from the list */ it = pendingList.begin(); SocketClient* c = *it; pendingList.erase(it); /* Process it, if false is returned, remove from list */ if (!onDataAvailable(c)) {//有数据来,调用FrameworkListener::onDataAvailable()处理 release(c, false); } c->decRef(); } } }由于mListen值的变化(此时为true),处理流程有所不同。首先作为服务端,会等待Client的连接请求;如果有连接请求,并有数据发送过来,则通过
onDataAvailable()处理。根据继承关系,此处调用FrameworkListener::onDataAvailable():
bool FrameworkListener::onDataAvailable(SocketClient *c) { char buffer[CMD_BUF_SIZE]; int len; len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer))); if (len < 0) { SLOGE("read() failed (%s)", strerror(errno)); return false; } else if (!len) return false; if(buffer[len-1] != ‘\0‘) SLOGW("String is not zero-terminated"); int offset = 0; int i; for (i = 0; i < len; i++) { if (buffer[i] == ‘\0‘) { /* IMPORTANT: dispatchCommand() expects a zero-terminated string */ dispatchCommand(c, buffer + offset);//命令分发处理 offset = i + 1; } } return true; }如果消息不为空,则调用FrameworkListener::dispatchCommand()进行处理:
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { FrameworkCommandCollection::iterator i; int argc = 0; char *argv[FrameworkListener::CMD_ARGS_MAX]; char tmp[CMD_BUF_SIZE]; char *p = data; char *q = tmp; char *qlimit = tmp + sizeof(tmp) - 1; bool esc = false; bool quote = false; bool haveCmdNum = !mWithSeq; memset(argv, 0, sizeof(argv)); memset(tmp, 0, sizeof(tmp)); while(*p) { if (*p == ‘\\‘) { if (esc) { if (q >= qlimit) goto overflow; *q++ = ‘\\‘; esc = false; } else esc = true; p++; continue; } else if (esc) { if (*p == ‘"‘) { if (q >= qlimit) goto overflow; *q++ = ‘"‘; } else if (*p == ‘\\‘) { if (q >= qlimit) goto overflow; *q++ = ‘\\‘; } else { cli->sendMsg(500, "Unsupported escape sequence", false); goto out; } p++; esc = false; continue; } if (*p == ‘"‘) { if (quote) quote = false; else quote = true; p++; continue; } if (q >= qlimit) goto overflow; *q = *p++; if (!quote && *q == ‘ ‘) { *q = ‘\0‘; if (!haveCmdNum) { char *endptr; int cmdNum = (int)strtol(tmp, &endptr, 0); if (endptr == NULL || *endptr != ‘\0‘) { cli->sendMsg(500, "Invalid sequence number", false); goto out; } cli->setCmdNum(cmdNum); haveCmdNum = true; } else { if (argc >= CMD_ARGS_MAX) goto overflow; argv[argc++] = strdup(tmp); } memset(tmp, 0, sizeof(tmp)); q = tmp; continue; } q++; } *q = ‘\0‘; if (argc >= CMD_ARGS_MAX) goto overflow; argv[argc++] = strdup(tmp); #if 0 for (int k = 0; k < argc; k++) { SLOGD("arg[%d] = ‘%s‘", k, argv[k]); } #endif if (quote) { cli->sendMsg(500, "Unclosed quotes error", false); goto out; } if (errorRate && (++mCommandCount % errorRate == 0)) { /* ignore this command - let the timeout handler handle it */ SLOGE("Faking a timeout"); goto out; } for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i; if (!strcmp(argv[0], c->getCommand())) { if (c->runCommand(cli, argc, argv)) {//重要,调用不同Command类型的对象runCommand()方法处理指令(定义在CommandListener中) SLOGW("Handler ‘%s‘ error (%s)", c->getCommand(), strerror(errno)); } goto out; } } cli->sendMsg(500, "Command not recognized", false); out: int j; for (j = 0; j < argc; j++) free(argv[j]); return; overflow: LOG_EVENT_INT(78001, cli->getUid()); cli->sendMsg(500, "Command too long", false); goto out;最后,会根据不同的Command命令对象,执行相应的runCommand()方法来处理不同的指令。
到此,Vold机制及原理的分析就基本结束了。Vold与MountService的交互后续再介绍。
PS:Android是基于Linux的,其中很多知识都与Linux的内容息息相关,如文件系统、设备管理。懂点Kernel的朋友,搞安卓会有不少优势......
还需努力,其中有些内容较为简略,后续有机会再来补充、完善。有错欢迎指出,乐于讨论,共同进步。
Android -- Vold机制简要分析
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。