Vold是用于管理和控制Android外部存储介质的后台进程,这里说的管控,主要包括SD卡的插拔、挂载/卸载和格式化等;它是Android平台外部存储系统的管控枢纽。
Vold的整个控制模块主要由三个类模块构成:NetlinkManager、VolumeManager和CommandListener,它们的功能划分大概是:
NetLink是Linux下用户进程和kernel进行信息交互的一种机制,借助这种机制,用户进程(如Vold/Netd)可以接收来自kernel的一些消息,同时也可以向kernel发送一些控制命令。NetlinkManager就是基于此设计的。Uevent也跟Linux系统有关,它与Linux 的设备文件系统有一定关系;这里,我们可以简单的认为,Uevent就是一个字符串,它描述了外部存储设备插入/拔出、挂载/卸载的状态信息。Vold通过Netlink机制,可以得到这些信息,并进行外部存储设备的管理、控制。
由上述介绍,我们可以得到如下的Vold框架图描述: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进程创建的介绍。
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的架构图,现分别对它们的创建及启动过程进行分析。
NetlinkManager *NetlinkManager::Instance() {
if (!sInstance)
sInstance = new NetlinkManager();
return sInstance;
}
NetlinkManager::NetlinkManager() {
mBroadcaster = NULL; //type:SocketListener*,用来进行socket通信
}
这里使用了单例模式来构建NetlinkManager对象,构造函数中只是简单地初始化了成员变量。
cl = new CommandListener();
nm->setBroadcaster((SocketListener *) cl);
void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
setBroadcaster()函数也很简单,为mBroadcast进行赋值。
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) {//NETLINK_KOBJECT_UEVENT协议:Kernel messages to userspace
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处理的。
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(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) {//如果我们是服务端,则将该socket的套接字加入到可读监控队列中
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) {//如果监测到read_fds集合中有socket可读
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)) {//监听端客户端连接请求
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)) {//遍历所有保存的客户端;如果该socket可读,将该套接字加入到队列中
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,如果收到数据,则进行处理。
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之间进行数据流动的处理了。
//单例模式
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(
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 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(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来发送的。
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(
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中。
CommandListener::CommandListener() :
FrameworkListener("vold", true) {//vold是socket名称,init.rc文件中声明的一个socket资源,用于和framework通信
registerCmd(new DumpCmd());//注册不同的命令对象,保存到mCommands成员中;同时,创建Cmd对象时,会保存一个字符串标识(一般是上层下发命令中的第一个字符串),用于后续区分不同的命令
registerCmd(new VolumeCmd());//标识:volume
registerCmd(new AsecCmd());//标识:asec
registerCmd(new ObbCmd());//标识:obb
registerCmd(new StorageCmd());//标识:storage
registerCmd(new FstrimCmd());//标识:fstrim
}
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();//集合对象
}
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,这样两者就可以通信了。
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast(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) {//如果我们是服务端,则将该socket的套接字加入到可读监控队列中
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) {//如果集合read_fds中有socket可读
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)) {//遍历保存的所有客户端socket,如果对应的socket可读,则将该套接字加入到队列中
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的连接请求;如果有连接请求,并有数据发送过来,则通过
bool FrameworkListener::onDataAvailable(SocketClient *c) {
char buffer[CMD_BUF_SIZE];
int len;
len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));//从MountService接收指令数据,存入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())) {//获取命令的第一个参数(即标识),遍历mCommands,找到符合的Command对象去执行runCommand();例如,如果标识是volume,则执行VolumeCommand的runCommand()函数处理下发的指令
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()方法来处理不同的指令。我们下发的指令有一定的规则,一般第一个字符串是标识,用以获得不同的Command对象;第二个参数一般是我们需要进行的操作命令;后续的参数一般都是下发的用以完成操作的数据。一般情况,格式类似于:
volume mount /mnt/sda/sda1
字符串之间以空格分开。