前言
印象中是参考 《深入理解 Android 卷 1 》 追的流程,差不多供参考吧
基于安卓 4.4
框架
MountService 流程
/*
【初始化流程总结】:
SystemServer
initAndLoop()
// 创建 MountService 服务对象
mountService = new MountService(context);
//
MountService::MountService(Context context)
///
// 从 xml 中读取存储设备列表,文件位于: frameworks/base/core/res/res/xml/storage_list.xml
readStorageListLocked();
///
// 创建并启动一个带消息循环的 MountService 工作线程
HandlerThread hthread = new HandlerThread(TAG);
hthread.start();
// 为 MountService 工作线程创建一个 Handler
// 有消息时时会调用 MountServiceHandler::handleMessage() 处理
// 处理的消息类型为: H_UNMOUNT_PM_UPDATE,H_UNMOUNT_PM_DONE,H_UNMOUNT_MS
mHandler = new MountServiceHandler(hthread.getLooper());
///
// Watch for user changes
// 注册一系列变化广播接收器
final IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
userFilter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
。。。
//
// Add OBB Action Handler to MountService thread.
// 为 MountService 工作线程创建一个 ObbActionHandler
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
//
// 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 = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
// 创建并启动一个 socket 连接监听线程
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();// 会执行到传入参数的 run() 函数
///
NativeDaemonConnector::run()
mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
while (true) {
try {
// 监听套接字 vold
listenToSocket();
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
SystemClock.sleep(5000);
}
}
/
// Add ourself to the Watchdog monitors if enabled.
if (WATCHDOG_ENABLE) {
Watchdog.getInstance().addMonitor(this);
}
///
// 将 mountService 服务注册到 C++ 层的 service manager 进程中管理
ServiceManager.addService("mount", mountService);
【MountService 命令下发流程】:
MountService::mountVolume()
// 核心函数
int ret = doMountVolume(path);
// 命令交给 NativeDaemonConnector::execute() 去发送
mConnector.execute(cmd);
//
NativeDaemonConnector::execute()
// 构造命令
makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);
//
// 向 socket 中写入命令
mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
【MountService 消息接收流程】:
// 监听套接字是通过 NativeDaemonConnector 类实现的,它在 MountService 的构造函数中创建并初始化的
NativeDaemonConnector::run()
mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
while (true) {
try {
// 监听套接字 vold
listenToSocket();
//创建 Vold socket
socket = new LocalSocket();
//向服务端发起连接请求
socket.connect(address);
//从连接的 socket 中得到输入输出流
InputStream inputStream = socket.getInputStream();
/
// 对本次连接请求做一些回调处理, 连接成功回调处理
mCallbacks.onDaemonConnected();
//
//
MountService::onDaemonConnected()
/
// 创建一个工作线程处理回调
new Thread("MountService#onDaemonConnected")
{
run()
{
// 向vold查询所有的存储设备
final String[] vols = NativeDaemonEvent.filterMessageList(
mConnector.executeForList("volume", "list"),
VoldResponseCode.VolumeListResult);
/
//判断存储设备状态
for (String volstr : vols)
/
// 更新 Volume 状态, 存储设备状态更新:
updatePublicVolumeState(usbotgVolume, state);
for (int i = mListeners.size() -1; i >= 0; i--)
// 调用已注册的 MountServiceBinderListener 来通知存储设备状态改变
bl.mListener.onStorageStateChanged(path, oldState, state);
///
// 这里调用的是 StorageManager::MountServiceBinderListener
StorageManager::MountServiceBinderListener()
for (int i = 0; i < size; i++)
/
// 私有类: 位于 StorageManager
// ListenerDelegate 的 sendStorageStateChanged()
mListeners.get(i).sendShareAvailabilityChanged(available);
StorageManager::ListenerDelegate::sendStorageStateChanged()
StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
// 给某个线程发送消息?
mHandler.sendMessage(e.getMessage());
//进入闭环数据读取模式
while (true) {
int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
//当读取的数据长度小于0时,表示连接已断开,跳出循环,重新向服务端发起新的连接请求
//解析读取到的数据,得到 NativeDaemonEvent
for (int i = 0; i < count; i++)
final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent);
//如果命令码code >= 600 && code < 700
if (event.isClassUnsolicited())
//将读取到的事件发送到 VoldConnector.CallbackHandler 线程中处理
mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent()));
///
///
// NativeDaemonConnector 类中实现的
NativeDaemonConnector::handleMessage()
//回调 MountService 的 onEvent 函数进行处理
mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))
/
/
// 回调处理接收到的消息,处理各种事件,主要是通知其他程序存储状态变化了
// 并发送命令给 vold 进行挂卸载
MountService::onEvent()
if (code == VoldResponseCode.VolumeStateChange)
。。。
notifyVolumeStateChange(
cooked[2], cooked[3], Integer.parseInt(cooked[7]),
Integer.parseInt(cooked[10]), bValue);
。。。
else if (code == VoldResponseCode.VolumeUuidChange)
。。。
else if (code == VoldResponseCode.VolumeUserLabelChange)
。。。
else if ((code == VoldResponseCode.VolumeDiskInserted) ||
(code == VoldResponseCode.VolumeDiskRemoved) ||
(code == VoldResponseCode.VolumeBadRemoval))
if (code == VoldResponseCode.VolumeDiskInserted)
new Thread("MountService#VolumeDiskInserted"){
public void run(){
//
// 进行实际挂载操作
doMountVolume(path)
if (!path.startsWith(EXTERNAL_OTG)) {
doSDSwapVolumeUpdate();
updateDefaultpath();
sendSDSwapIntent();
}
// 启动一个窗口?
mContext.startActivity(intent);
}
}
。。。
else {
//否则将改事件添加到响应队列中
mResponseQueue.add(event.getCmdNumber(), event);
}
}
}
}.start();
} catch (Exception e) {
loge("Error in NativeDaemonConnector: " + e);
SystemClock.sleep(5000);
}
}
*/
Vold 流程
/* vold 进程是从 init 进程通过 init.rc 启动的
vold进程:
管理和控制 Android 平台外部存储设备,包括 SD 插拨、挂载、卸载、格式化等;
vold 进程接收来自内核的外部设备消息
*/
service vold /system/bin/vold
class core
socket vold stream 0660 root mount // 语法:socket <name> <type> <perm> <user> <group>, 创建一个名字为 vold<name>,类别为 stream<type> //访问权限为 0660<perm> 用户为 root,用户组为 mount
ioprio be 2
/*
涉及相关类的概念:
/// C++ /
SocketClient // 代表一个套接字信息
SocketListener // 创建线程,监听, socket,每个套接字会创建一个 SocketClient 链入链表管理
// 【继承该类,会在接收到数据时,调用子类覆写的 onDataAvaible() 进行数据处理】
NetlinkListener: public SocketListener // 监听内核 netlink, 接收 uevent 消息,封装到 NetlinkEvent,然后调
// 用具体子类 onEvent() 处理
NetlinkHandler: public NetlinkListener // 具体 netlink 消息命令的处理类,与 VolumeManager 交互,实现磁盘挂卸载等操作
FrameworkListener: public SocketListener // 用于监听远程发过来的字符串命令, 执行具体子类 runCommand() 来执行命令
【CommandListener】: public FrameworkListener// 注册具体的命令子类,用来监听 /dev/socket/vold 上的数据发来的命令,
// 该套接字用来与 Framework 通信,用注册的具体的命令子类,执行 Framework 发来的命令
Volume // 分卷抽象
【DirectVolume】:public Volume // 一个实体磁盘设备在代码中的抽象。
NetlinkEvent // 解析 uevent 获得信息封装的类
/
// 接收内核发来的消息, 解析转换成 NetlinkEvent 对象;再将此 NetlinkEvent
// 对象传递给 VolumeManager 处理, 他会传给具体的 DirectVolume 磁盘设备类处理
【NetlinkManager】
{
// 实现单实例模式用
NetlinkManager
NetlinkListener: public SocketListener
NetlinkHandler: public NetlinkListener
SocketListener
}
/
// 此模块管理所有挂载的设备节点以及相关操作执行
【VolumeManager】
{
// 实例单例模式使用
VolumeManager
// 链表结构
AsecIdCollection
VolumeCollection
SocketListener
}
###########################################################################################################
Java
// 检测外部存储卡的插入/拔出事件,这些事件是由 MountServie 通过
// Intent 广播发出的,例如,外部存储卡插入后,MountService 就会发送 ACTION_MEDIA_MOUNTED 消息
class MountService extends IMountService.Stub // 很眼熟,Binder 通信机制,Stub 是服务类需要继承实现的
public MountService(Context context)
mPms = (PackageManagerService) ServiceManager.getService("package");
// 创建一个 HandlerThread
HandlerThread hthread = new HandlerThread(TAG);
hthread.start();
// Handler 类: 用于让某个线程的消息队列发送消息让其处理
// 创建一个 Handler,这个 Handler 使用 HandlerThread 的 Looper, 也就是说,派发给该 Handler
// 的消息将在另外一个线程中处理
mHandler = new MountServiceHandler(hthread.getLooper());
// NativeDaemonConnector 用于 Socket 通信,第二个参数 vold 表示将和 vold 通信,也就是和 CommandListener 模块
// 中的那个 socket 建立通信连接,第二个参数为 INativeDaemonConnectorCallbacks 接口,它提供两个回调接口函数:
// onDaemonConnected() // 当 NativeDaemonConnector 连接上 Vold 后回调
// onEvent() // 当 NativeDaemonConnector 收到来自 Vold 数据后回调
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
// 再启动一个线程用于和 Vold 通信
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
###########################################################################################################
//
// 内核发来 uevent 消息举例:【SD 卡插入】
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0
ACTION=add // 设备插入,还有 remove/change 动作
DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0 // 该设备在 /sys 中的设备路径
SUBSYSTEM=block // 设备类型:block/character 等
MAJOR=179 // 主次设备号
MINOR=0
DEVNAME=mmcblk0
DEVTYPE=disk // 设备类型为磁盘
NPARTS=3 // 该 SD 卡有 3 个分区
SEQNUM=1357 // 序号
// SD 卡分区的 uevent
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0/mmcb1 k0p1
ACTION=add // 设备插入,还有 remove/change 动作
DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0/mmcblk0p1 // 该设备在 /sys 中的设备路径
SUBSYSTEM=block // 设备类型:block/character 等
MAJOR=179 // 主次设备号
MINOR=1
DEVNAME=mmcblk0p1
DEVTYPE=partition // 设备类型为分区
NPARTS=1 // 该 SD 卡有 3 个分区
SEQNUM=1358 // 序号
SocketListener 类具体实现/
// 监听 socket 的实现:调用具体子类 onDataAvaible() 处理
SocketListener
入口函数:
static void *threadStart(void *obj);
SocketListener::runListener()
while(1)
{
// 添加请求监听套接字描述符
FD_SET(mSock, &read_fds);
// 监听管道读端
FD_SET(mCtrlPipe[0], &read_fds);
// 遍历所有链表上 SocketClient,这个数据结构里保存了监听的套字信息
for (it = mClients->begin(); it != mClients->end(); ++it) {
int fd = (*it)->getSocket();
// 添加数据通信的套接字描述符
FD_SET(fd, &read_fds);
if (fd > max)
max = fd;
}
///
// 通过 select 监听添加的文件描述符,看是否有数据送过来
select(max + 1, &read_fds, NULL, NULL, NULL)
// 如果管道上有数据传来的,则
if (FD_ISSET(mCtrlPipe[0], &read_fds))break;
// 如果连接请求监听套按字
if (mListen && FD_ISSET(mSock, &read_fds))
do {
alen = sizeof(addr);
// 接受连接请求
c = accept(mSock, &addr, &alen);
SLOGV("%s got %d from accept", mSocketName, c);
} while (c < 0 && errno == EINTR);
// 创建一个套接字客户端 SocketClient 去处理双方的数据通信
// 这里仅将创建的客户端链入链表中管理
mClients->push_back(new SocketClient(c, true, mUseCmdNum));
// 将所有有数据的客户端,添加到 pendingList 链表中
pendingList->clear();
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
int fd = (*it)->getSocket();
if (FD_ISSET(fd, &read_fds)) {
pendingList->push_back(*it);
}
}
// 遍历的所有有数据的客户端
while (!pendingList->empty()) {
// 从链表中取出一项
it = pendingList->begin();
SocketClient* c = *it;
pendingList->erase(it);
///
// 核心:调用 【onDataAvaible()】 函数处理数据,onDataAvaible() 是抽象函数,
// 所以是动态绑定的,有则子类处理,无则父类处理
if (!onDataAvailable(c) && mListen) {
// onDataAvailable() 出错,则返回 false 从链表中删除
for (it = mClients->begin(); it != mClients->end(); ++it) {
if (*it == c) {
mClients->erase(it);
break;
}
}
// Remove our reference to the client
c->decRef();
}
}
}
// FrameworkListener 类具体实现 //
// 继承自 SocketListener,用于监听远程发过来的字符串命令, 执行自己实现的命令子类,调用具体子类的 runCommand()
FrameworkListener: public SocketListener
继承 SocketListener, 主要覆写 onDataAvaible() 来处理数据
onDataAvaible()
// 调用 read() 来接收数据
len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer+last_offset, sizeof(buffer)-last_offset))
for (i = 0; i < len; i++) {
if (buffer[i] == '\0') {
// IMPORTANT: dispatchCommand() expects a zero-terminated string
// 分发命令给具体的命令子类处理
dispatchCommand(c, buffer + offset);
// 解析发过来的字符串命令
// 遍历已注册的命令集
for (i = mCommands->begin(); i != mCommands->end(); ++i) {
FrameworkCommand *c = *i;
if (!strcmp(argv[0], c->getCommand())) {
///
// 调用具体的命令子类, 具体的命令子类需要继承 FrameworkCommand 类, 并需要注册进链表
// 实现其 runCommand() 方法,这里添加了一些继承 VoldCommand,具体命令子类继承 VoldCommand
if (c->runCommand(cli, argc, argv)) {
SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
}
goto out;
}
}
offset = i + 1;
}
}
//
// 注册具体的继承 FrameworkCommand 的命令子类,仅是简单的添加到链表中
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
mCommands->push_back(cmd);
}
// CommandListener 类具体实现 //
// 注册具体的命令子类,用来监听 /dev/socket/vold 上的数据发来的命令,
// 该套接字用来与 Framework 通信,用注册的具体的命令子类,执行 Framework 发来的命令
CommandListener : public FrameworkListener
// 监听 /dev/socket/vold 并注册具体的命令子类
CommandListener::CommandListener() :
FrameworkListener("vold", true) // 1. 注册监听 /dev/socket/vold 套接字,与 Framework 通信
{
// 2. 注册具体的命令子类,当从 Framework 层有命令来时,就会调用具体命令子类的 runCommand
registerCmd(new DumpCmd()); // 用于输出各种信息
registerCmd(new VolumeCmd()); // 用于磁盘卷管理
registerCmd(new AsecCmd()); // 用于将 .apk 安装到外部存储设备如 SD 卡上
registerCmd(new ObbCmd()); // 不程春明二进制数据块,数据加密用
registerCmd(new StorageCmd()); // 用于查询哪些进程正在使用某个磁盘设备
registerCmd(new XwarpCmd());
registerCmd(new CryptfsCmd()); // 存储区加密
registerCmd(new FstrimCmd());
//M{
#ifndef MTK_EMULATOR_SUPPORT
registerCmd(new USBCmd());
#endif
registerCmd(new CDROMCmd());
//}M
#if defined (ENG_BUILD_ENG)
registerCmd(new SilkRoad());
#endif
}
/// NetlinkListener 类具体实现 /
// 继承自 SocketListener,用于监听内核发来的 uevent 事件,调用 NetlinkEvent 解析后
// 再调用 NetlinkListener 具体的子类 onEvent() 处理
NetlinkListener: public SocketListener
继承 SocketListener, 主要覆写 onDataAvaible() 来处理数据
onDataAvailable()
// 接收来自内核的 uevent 消息
count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(socket, mBuffer, sizeof(mBuffer), &uid))
// 创建一个 NetlinkEvent 对象解析处理消息
NetlinkEvent *evt = new NetlinkEvent();
// 调用 NetlinkEvent::decode() 解析命令
evt->decode(mBuffer, count, mFormat)
NetlinkEvent::decode()
// 根据命令类型是二进制的还是 ascii 类型的分别解析
if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
// Parse an binary message from a NETLINK_ROUTE netlink socket.
return parseBinaryNetlinkMessage(buffer, size);
} else {
// 处理 uevent 消息如:add/remove/change 等
// 解析后的信息保存在 NetlinkEvent::{mAction/mSeq/mSubsystem/mParames} 中
return parseAsciiNetlinkMessage(buffer, size);
}
//
// 虚函数,调用具体的继承了 NetlinkListener() 子类实现的 onEvent() 处理消息
// 如会调用 NetlinkHandler:onEvent() 处理
onEvent(evt);
// NetlinkManager 类具体实现 //
// 接收内核发来的消息, 解析转换成 NetlinkEvent 对象;再将此 NetlinkEvent
// 对象传递给 VolumeManager 处理
【NetlinkManager】
{
// 实现单实例模式用
NetlinkManager
SocketListener # 会调用子类 onDataAvailable() 处理接收到的数据
NetlinkListener: public SocketListener # 调用子类 onEvent() 处理接收到的 uevent 事件
NetlinkHandler: public NetlinkListener // 实现的 onEvent()
SocketListener
}
【启用 NetLink 监听函数流程】:
NetlinkManager::start()
// 创建 netlink 用来监听内核消息
mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)
// 绑定 netlinck 到文件描述符中
bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)
// 创建一个 NetlinkHandler 类对象
mHandler = new NetlinkHandler(mSock)
// NetlinkHandler 继承 NetlinkListener 并实现了其 onEvent() 函数,会在 NetlinkManager::onDataAvailable()
// 用来处理具体的 uevent 事件
NetlinkHandler: public NetlinkListener
mHandler->start()
//
NetlinkHandler::start()
SocketListener::startListener()
// android_get_control_socket - simple helper function to get the file
// descriptor of our init-managed Unix domain socket. `name' is the name of the
// socket, as given in init.rc. Returns -1 on error.
//
// This is inline and not in libcutils proper because we want to use this in
// third-party daemons with minimal modification.
// 从环境变量在获得已有的 socket 文件描述符, 这是在 init.rc 中注册的,用来与 framework 通信用的 /dev/socket/vold
mSock = android_get_control_socket(mSocketName)
// 监听套接字
listen(mSock, 4)
// 添加到 SocketListener 类的 mClients 链表中管理
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum)
// 创建用于退出使用的管道
pipe(mCtrlPipe)
// 创建线程进行监听
pthread_create(&mThread, NULL, SocketListener::threadStart, this)
SocketListener::threadStart(void *obj)
// 子类转为父类
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
me->runListener();
// 调用 SocketListener::runListener()
// 具体参见上面 SocketListener 类具体实现,收到 socket 信息,则调用
#####################################################
// 【SocketListener 的子类 onDataAvaible() 进行处理】
# 即 NetlinkListener::onDataAvaible()
# 再调用 NetlinkListener 的子类覆写的 onEvent()
# 即 NetlinkHandler::onEvent()
#####################################################
// 如果收到 pipe 管道信息,则退出线程
【处理内核传来 uevent 数据流程】:
// 在 NetlinkListener 中被调用,传入参数为解析好的 uevent 数据封装的 NetlinkEvent 类
// 【然后调用 volumeManager 类进行处理 】
NetlinkHandler::onEvent(NetlinkEvent *evt)
// 单实例模式
VolumeManager *vm = VolumeManager::Instance()
// 获得是什么子系统上报的 uevent
const char *subsys = evt->getSubsystem()
if (!strcmp(subsys, "block"))
// 调用 volumeManager 模块中的函数,进行具体的磁盘挂卸载操作
// 【1】. 更新磁盘状态
vm->updatePullOutState(evt);
// 获得 uevent 事件类型: add/remove/change
int action = evt->getAction();
VolumeCollection::iterator it;
// 遍历的所有已有分卷 Volume 类对象 updatePullOutState() 函数,更新各个分卷状态
for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
///
// updatePullOutState() 是一个虚函数,所以会调用具体子类 DirectVolume 处理
(*it)->updatePullOutState(evt);
DirectVolume::updatePullOutState()
// 获得要更新的设备路径及行为
int action = evt->getAction();
const char *dp = evt->findParam("DEVPATH");
// 遍历所有已经注册管理的磁盘的设备
for (it = mPaths->begin(); it != mPaths->end(); ++it)
if (!strncmp(dp, *it, strlen(*it)))
if (action == NetlinkEvent::NlActionAdd)
mIsHwPullOut = false;
else if (action == NetlinkEvent::NlActionRemove)
mIsHwPullOut = true;
}
// 【2】. 设置热插拔标志位
vm->setHotPlug(true);
mIsHotPlug = isPlug;
// 【3】. 处理 uevent 事件: add/remove/change 设备
vm->handleBlockEvent(evt);
// 遍历的所有已经注册管理的卷列表,卷列表根据配置文件 /etc/vold.fstab 创建添加
// 在函数 process_config() 中创建添加的
for (it = mVolumes->begin(); it != mVolumes->end(); ++it)
/
// Volume::handleBlockEvent() 是一个虚函数,所以会调用具体子类 DirectVolume 处理
// 调用 DirectVolume::handleBlockEvent()
(*it)->handleBlockEvent(evt)
DirectVolume::handleBlockEvent()
// 获得磁盘变更路径
const char *dp = evt->findParam("DEVPATH");
// 遍历该设备的所有分区?
for (it = mPaths->begin(); it != mPaths->end(); ++it)
// 获得要执行的操作: add/remove/change 以及设备类型:disk/partition
int action = evt->getAction();
const char *devtype = evt->findParam("DEVTYPE");
###########################
// 添加设备
###########################
if (action == NetlinkEvent::NlActionAdd)
// 获得要创建的设备节点主次设备号
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
// 要创建的节点路径
snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", major, minor);
// 创建设备节点
createDeviceNode(nodepath, major, minor)
Volume::createDeviceNode()
mode_t mode = 0660 | S_IFBLK;
dev_t dev = (major << 8) | minor;
// 创建节点
mknod(path, mode, dev)
///
// 当前创建的节点代表一个磁盘
///
if (!strcmp(devtype, "disk"))
handleDiskAdded(dp, evt)
/
DirectVolume::handleDiskAdded()
mDiskMajor = atoi(evt->findParam("MAJOR"));
mDiskMinor = atoi(evt->findParam("MINOR"));
const char *tmp = evt->findParam("NPARTS");
// 针对磁盘上的每个分区分别处理,将发送信息给 MountService
for (int i = 0; i < MAX_PARTITIONS; i++)
mPartMinors[i] = -1;
// 没有分区
if (mDiskNumParts == 0)
setState(Volume::State_Idle);
// 有分区
else
setState(Volume::State_Pending)
// 当前创建的节点代表一个分区 ,对于有分区的 SD 卡,会先收到 disk 消息,再收到 partition 分区消息
else
handlePartitionAdded(dp, evt);
DirectVolume::handlePartitionAdded()
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
const char *tmp = evt->findParam("PARTN");
if (getState() != Volume::State_Formatting && (part_rescan_wait == WAIT_ON_NO_EVENT))
setState(Volume::State_Idle);
if(mVm->getIpoState() == VolumeManager::State_Ipo_Start)
if (mRetryMount == true)
mRetryMount = false;
// 调用 Volume::mountVol() 执行挂载分区
mountVol()
Volume::mountVol()
// 通过 CommandListener 给套接字 /dev/socket/vold 发送消息给 Framework 层
snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media",
getLabel(), getFuseMountpoint());
//
// 调用 VolumeManager 中的 Broadcaster->CommandListener() 发送此 msg
// 发送消息通知 Framework 层是在 SocketListener 中完成
//
// 这里工作的 SocketListener 是 VolumeManager 的,SocketListener 的派生类 CommandListener,
// 用来与 Framework 交互的,监听 Socket 消息。通过 VolumeManager 中调用 sendBroadcast,
// 与 CommandListener 模块进行交互
//
// 这里的调用关系为:
// VolumeManger 模块调用
// CommandListener 模块函数 sendBroadcast()
// 通过给套接字 /dev/socket/vold 发消息给 Framework 层
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeMountFailedNoMedia,
SocketListener::sendBroadcast()
for (i = mClients->begin(); i != mClients->end(); ++i)
(*i)->sendMsg(code, msg, addErrno, false)
SocketListener::sendBroadcast()
// 遍历所有已经注册管理的 SocketClient
for (i = mClients->begin(); i != mClients->end(); ++i)
(*i)->sendMsg(code, msg, addErrno, false)
SocketClient::sendMsg()
sendData(msg, strlen(msg) + 1)
int rc = sendDataLocked(data, len);
// 通过套接字发消息给 Framework 层?
send(mSocket, p, brtw, MSG_NOSIGNAL);
// 这里会对挂载标志进行处理
// 挂载分区,也是创建相应的设备节点
snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",
new_major, new_minor);
// 通过 mknode 创建节点
createDeviceNode(nodepath, new_major, new_minor)
// 更新 DirectVolume 设备状态
updateDeviceInfo(nodepath, new_major, new_minor);
// 遍历的所有分区
for (i = 0; i < n; i++)
#################################################################
// 挂载 Fat 分区,这里只支持 Fat 分区
// 先将设备挂载到 /mnt/secure/staging 目录
Fat::doMount(devicePath, SEC_STGDIR, false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)
// 将挂载点从 /mnt/secure/staging 移动 Framework 指定目录
// 如 SD 卡则为:/mnt/sdcard
doMoveMount(SEC_STGDIR, getMountpoint(), false)
// 将存储卡上的 .android_secure() 目录挂载到
// /mnt/secure/asec 目录下,同时对 .android_secure
// 进行一些特殊处理,这样没权限用户
// 就无法更改破坏更改 .andoird_secure 目录的内容了
mountAsecExternal(SEC_STGDIR)
// 设置状态为 State_Mounted, 这个函数将发送信息给 MountService
setState(Volume::State_Mounted, Fat::isFat32(fd))
#################################################################
if(part_rescan_wait == WAIT_ON_ADD_EVENT)
// 发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行
pthread_cond_signal(&part_rescan_cond);
// 如果磁盘上所有分区都找到了,在上面的 setState() 函数中设备的状态的
if ((getState() == Volume::State_Idle) && (mVm->getIpoState() == VolumeManager::State_Ipo_Start))
// 准备消息给 Framework 通知设备状态变化
snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(),
getFuseMountpoint(), mDiskMajor, mDiskMinor);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false)
###########################
// 卸载设备,与挂载类似处理
###########################
else if (action == NetlinkEvent::NlActionRemove)
if (!strcmp(devtype, "disk"))
handleDiskRemoved(dp, evt);
else
handlePartitionRemoved(dp, evt);
###########################
// 改变设备,与挂载类似处理
###########################
else if (action == NetlinkEvent::NlActionChange)
if (!strcmp(devtype, "disk"))
handleDiskChanged(dp, evt);
else
handlePartitionChanged(dp, evt);
// 【4】. 设置热插拔标志位
vm->setHotPlug(false);
##################################################################################################################
main 流程总结:
main()
// 【1】创建 vold 设备文件夹
mkdir("/dev/block/vold", 0755);
// Create our singleton managers
// 【2】创建 VolumeManager 对象: 单实例模式
vm = VolumeManager::Instance())
// 【3】创建 NetlinkManager 对象: 用于监听内核发来的 uevent 信息,然后交给 VolumeManager 处理
nm = NetlinkManager::Instance())
/
// CommandListener 创建 vold socket 监听上层消息
// CommandListener: 监听来自 UNIX 本地套接字(/dev/socket/vold)上的数据
// 继承自 FrameworkListener,可以用于分发字符串命令,处理字符串命令由子类
// DumpCmd, VolumeCmd, AsecCmd, ObbCmd, StorageCmd, XwarpCmd 和 CryptfsCmd 等去完成
cl = new CommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
//
// 【4】根据配置文件 /etc/vold.fstab 初始化 VolumeManager, 用来管理 DirectVolume(磁盘抽象对象)
process_config(vm)
// 解析 fstab 配置文件,保存到 fstab 数据结构中
fstab = fs_mgr_read_fstab(fstab_filename);
// 遍历 fstab 配置文件中的所有选项,根据 fs_mgr_flags 文件管理标志判断是否需要将其添加到 volumeManager 管理
for (i = 0; i < fstab->num_entries; i++)
// 如果需要添加到 volumeManager 管理,则添加管理
if (fs_mgr_is_voldmanaged(&fstab->recs[i]))
// 创建 DirectVolume 对象 相关的挂载点设备的操作
dv = new DirectVolume(vm, &(fstab->recs[i]), flags);
//添加挂载点设备路径
dv->addPath(fstab->recs[i].blk_device)
//将 DirectVolume 添加到 VolumeManager 管理
vm->addVolume(dv)
/
// 【5】启动 NetlinkManager socket 监听内核发送 uevent, 获得具体内核消息,它会将其封装成 NetlinkEvent 信息
// 然后调用 NetlinkHandler::onEvent() 【然后调用 volumeManager 类进行处理 】
// 【这里是作服务器用的】
nm->start()
NetlinkManager::start()
// 创建 PF_NETLINK 地址簇的 socket,目前只支持 SOCK_DGRAM 类型,
// 第三个参数,NETLINK_KOBJECT_UEVENT 表示要接收内核的 Uevent 事件
mSock = socket(PF_NETLINK, SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)
// 设置 Socket 接收缓冲区大小
setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz))
// 必须对 socket 执行 bind 操作
bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr))
// 创建一个 NetlinkHandler 类对象监听处理内核 netlinck 消息
// 它将根据接收的消息,调用具体的 VolumeManager 模块中的函数时行处理,如挂卸载
mHandler = new NetlinkHandler(mSock)
//
// 调用 NetlinkHandler::start() ,他会创建一个线程进行监听内核 netlink 发来的消息
// 消息处理流程为:
// Kernel = uevent => NetlinkManagerModule ==> VolumeManager ==> DirectVolume(磁盘抽象类)
//
// 监听线程
// // 检查 socket 上是否有数据
// SocketListener # 调用子类覆写的 onDataAvaible() 进行数据处理
// // 接收 socket 上的数据,将 uevent 数据解析封装成 NetlinkEvent, 调用 volumeManager 模块处理挂卸载
// NetlinkListener::onDataAvaible() // NetlinkListener: public SocketListener, # 调用子类覆写的 onEvent() 进行数据处理
// // 调用 volumeManager 模块处理挂卸载
// NetlinkHandler::onEvent()
// // VolumeManager 模块调用具体的磁盘 DirectVolume 类处理挂卸载
// VolumeManager::handleBlockEvent()
// // 具体磁盘类 DirectVolume 处理挂卸载
// DirectVolume::handleBlockEvent()
// 1. 创建设备节点
// 2. 挂卸载文件系统
// 3. 发送套接字消息,通知 Framework 层
mHandler->start()
//
//【6】向 /sys/block/ 目录下所有设备 uevent 文件写入 “add\n”,
//触发内核 sysfs 发送 uevent 消息
coldboot("/sys/block");
DIR *d = opendir(path);
do_coldboot(d, 0);
dfd = dirfd(d);
fd = openat(dfd, "uevent", O_WRONLY);
write(fd, "add\n", 4);
// 递归写所有子目录
while((de = readdir(d)))
fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
d2 = fdopendir(fd);
do_coldboot(d2, lvl + 1);
/
// 【7】启动 CommandListener 用来监听 /dev/socket/vold 上的数据发来的命令,
// 该套接字用来与 Framework 通信,用注册的具体的命令子类,执行 Framework 发来的命令
cl->startListener()
// 调用父类函数
SocketListener::startListener()
// 上面有介绍,创建一个线程监听从 init.rc 中创建的 /dev/socket/vold 套接字,用来与 framework 通信
// 执行 Framework 发来的命令
/
// 【8】死循环,成为监听线程
// Eventually we'll become the monitoring thread
while(1) {
sleep(1000);
}
// 分析一下 SD 卡插入事件的检测:
数据控制路径为:
Kernel Uevent
SocketListener
NetlinkListener::onDataAvaible()
NetlinkHandler::onEvent()
VolumeManager::handleBlockEvent()
// 具体磁盘类 DirectVolume 处理挂卸载
DirectVolume::handleBlockEvent()
1. 创建设备节点
2. 挂卸载文件系统
3. 发送套接字消息,通知 Framework 层 : 消息为: Volume sdcard disk inserted (179:0)
======= Java =
SD 卡插入:
Kernel 发出 uevent 消息
add@/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0
ACTION=add // 设备插入,还有 remove/change 动作
DEVPATH=/devices/platform/msm_sdcc.2/mmc_host/mmc1/mmc1:c9f2/block/mmcblk0 // 该设备在 /sys 中的设备路径
SUBSYSTEM=block // 设备类型:block/character 等
MAJOR=179 // 主次设备号
MINOR=0
DEVNAME=mmcblk0
DEVTYPE=disk // 设备类型为磁盘
NPARTS=3 // 该 SD 卡有 3 个分区
SEQNUM=1357 // 序号
// Vold //
// 检查 socket 上是否有数据
SocketListener # 调用子类覆写的 onDataAvaible()
// 接收 socket 上的数据,将 uevent 数据解析封装成 NetlinkEvent, 调用 volumeManager 模块处理挂卸载
NetlinkListener::onDataAvaible() // NetlinkListener: public SocketListener # 调用子类覆写的 onEvent()
// 调用 volumeManager 模块处理挂卸载
NetlinkHandler::onEvent()
// VolumeManager 模块调用具体的磁盘 DirectVolume 类处理挂卸载
VolumeManager::handleBlockEvent()
// 具体磁盘类 DirectVolume 处理挂卸载
DirectVolume::handleBlockEvent()
1. 创建设备节点
2. 挂卸载文件系统
3. 发送套接字消息,通知 Framework 层 : 消息为: Volume sdcard disk inserted (179:0)
// Java
MountService::onEvent()
if (code == VoldResponseCode.VolumeStateChange)
...
else if (code == VoldResponseCode.VolumeUuidChange)
...
...
else if ((code == VoldResponseCode.VolumeDiskInserted) ||
(code == VoldResponseCode.VolumeDiskRemoved) ||
(code == VoldResponseCode.VolumeBadRemoval))
// 磁盘设备插入
if (code == VoldResponseCode.VolumeDiskInserted)
// 收到 handleDiskAdded() 发送的 VolumeDiskInserted 消息了
// 单独启动一个线程来处理这个消息
new Thread("MountService#VolumeDiskInserted"){
public void run()
// 调用 doMountVolume 处理
rc = doMountVolume(path)
// 【参考 Android 2.2】,在 4.4 上未找通,太晚了,不找了
// 通过 NativeDaemonConnector 给 Vold 发送请求
mConnector.doCommand()
/// C++ //
// CommandListener 从 /dev/socket/vold 中接收到这个请求
// 命令内容为:volume mount /mnt/sdcard
// 调用具体的命令子类执行
CommandListener::VolumeCmd::runCommand()
VolumeManager *vm = VolumeManager::Instance();
。。。
else if (!strcmp(argv[1], "mount"))
// 调用 VolumeManager 模块的 mountVolume() 来处理 mount 命令
// 参数为 /mnt/sdcard
rc = vm->mountVolume(argv[2]);
VolumeManager::mountVolume()
Volume *v = lookupVolume(label);
v->mountVol()
Volume::mountVol()
// 最终调用具体文件系统的挂载函数,实现挂载
Fat::doMount()
}.start()
*/