联发科65894.4找不到vold.fstabb

vold.fstab怎么修改_百度知道
vold.fstab怎么修改
提问者采纳
platform/mnt/devices/sdcard 14 &#47第一步.2&#47。(不过有些不建议搬的还是算了吧;mmc_host&#47。第三步。第二步。或者用360手机助手或其他辅助软件的文件管理功能将这个文件导出到本地计算机,哈哈;sdcard的挂载点改成跟/mnt/文本编辑器&mmc_host&#47:用R;sdcard auto &#47,万一改错了好恢复.管理器将“&#47.4/mmc0即将/mmc0改成dev_mount emmc /msm_system/mmc0dev_mount sdcard /devices/HWUserData 14 /etc”目录挂载为“读写”属性。修改最后一行;mmc0dev_mount sdcard /mnt&#47:先存个备份,如果是导出来改的就再导进去覆盖原文件:点击该目录下的&quot:重启手机——软件可以搬家啦:保存退出.2/platform/HWUserData 14 /mmc_host&#47,选择用&quot,然后用“写字板”打开.fstab&打开;文件.E;devices/msm_sdcc,可能会影响开机自动运行;msm_platform/msm_sdcc,嘿嘿;HWUserData一样;platform&#47。第五步;mmc_host&#47,我的改之前是dev_mount emmc &#47。第四步,用“记事本”的话换行有问题.2/devices&#47
其他类似问题
为您推荐:
fstab的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁红米note移动4G版。内置存储与外置卡切换,如何修改路径?下面附图(vold.fstab)和系统信息,高手请进。_百度知道
红米note移动4G版。内置存储与外置卡切换,如何修改路径?下面附图(vold.fstab)和系统信息,高手请进。
/zhidao/pic/item/838ba61ea8d3fd1fe251f95ca5f2e:///zhidao/wh%3D600%2C800/sign=64afbbb2f8edabc70683fb/838ba61ea8d3fd1fe251f95ca5f2e.baidu.1<img class="ikqb_img" src="http://a型号 HM NOTE 1LTETD4.hiphotos
补充一下,手机已root,谢谢。
hiphotos://a.hiphotos,长按之./zhidao/pic/item/8435e5dde7b0a5cd1b9d16fcfa60fc,长按之,找到.jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink">安装RE管理器.com/zhidao/wh%3D600%2C800/sign=c9fcdfb6c0cec3fd8b6baf73e6b8f807/8435e5dde7b0a5cd1b9d16fcfa60fc:/system/etc/permissions/platform:///zhidao/wh%3D450%2C600/sign=e2abc1c2d73f2ae72b22c2/8435e5dde7b0a5cd1b9d16fcfa60fc:/system/etc/permissions/platform.xml,找到,取得ROOT权限,选择在文本编辑器中打开找到下面代码,照着图片改,首先,选择在文本编辑器中打开找到下面代码,照着图片改<a href="http
其他类似问题
为您推荐:
fstab的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁一 Vold工作机制分析
&&&&&&&& vold进程:管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等;
&&&&&&&& vold进程接收来自内核的外部设备消息。
Vold框架图如下:
&&&&&&&& Vold接收来自内核的事件,通过netlink机制。
&&&&&&&& Netlink 是一种特殊的 socket;
&&&&&&&& Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的socket API 就可以使用 netlink 提供的强大功能;
&&&&&&&& Netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中;
内核通过Netlink发送uEvent格式消息给用户空间程序;外部设备发生变化,Kernel发送uevent消息。
二 Vold进程启动过程
service vold /system/bin/vold
class core
socket vold stream 0660 root mount
ioprio be 2&
vold进程执行过程:
&&&&&&&& \system\vold\main.cpp
int main()
VolumeManager *
CommandListener *
NetlinkManager *
//创建vold设备文件夹
mkdir("/dev/block/vold", 0755);
//初始化Vold相关的类实例 single
vm = VolumeManager::Instance();
nm = NetlinkManager::Instance();
//CommandListener 创建vold socket监听上层消息
cl = new CommandListener();
vm-&setBroadcaster((SocketListener *) cl);
nm-&setBroadcaster((SocketListener *) cl);
//启动VolumeManager
vm-&start();
//根据配置文件/etc/vold.fstab 初始化VolumeManager
process_config(vm);
//启动NetlinkManager socket监听内核发送uevent
nm-&start();
//向/sys/block/目录下所有设备uevent文件写入&add\n&,
//触发内核sysfs发送uevent消息
coldboot("/sys/block");
//启动CommandListener监听vold socket
cl-&startListener();
// Eventually we'll become the monitoring thread
while(1) {
sleep(1000);
process_config解析vold.fstab文件:
static int process_config(VolumeManager *vm) {
//打开vold.fstab的配置文件
fp = fopen("/etc/vold.fstab", "r")
//解析vold.fstab 配置存储设备的挂载点
while(fgets(line, sizeof(line), fp)) {
const char *delim = " \t";
char *type, *label, *mount_point, *part, *mount_flags, *sysfs_
type = strtok_r(line, delim, &save_ptr)
label = strtok_r(NULL, delim, &save_ptr)
mount_point = strtok_r(NULL, delim, &save_ptr)
//判断分区 auto没有分区
part = strtok_r(NULL, delim, &save_ptr)
if (!strcmp(part, "auto")) {
//创建DirectVolume对象 相关的挂载点设备的操作
dv = new DirectVolume(vm, label, mount_point, -1);
dv = new DirectVolume(vm, label, mount_point, atoi(part));
//添加挂载点设备路径
while ((sysfs_path = strtok_r(NULL, delim, &save_ptr))) {
dv-&addPath(sysfs_path)
//将DirectVolume 添加到VolumeManager管理
vm-&addVolume(dv);
fclose(fp);
vold.fstab文件:
  导出一个我的手机里面的vold.fstab文件 内容:
dev_mount sdcard /mnt/sdcard
/devices/platform/goldfish_mmc.0 /devices/platform/mtk-sd.0/mmc_host
dev_mount external_sdcard /mnt/sdcard/external_sd auto /devices/platform/goldfish_mmc.1 /devices/platform/mtk-sd.1/mmc_host
  vold.fstab格式是:
&&&&&&&& type &&&&&&& label &&&&&& mount_point part &&&&&&& sysfs_path &&&& sysfs_path
  sysfs_path可以有多个 part指定分区个数,如果是auto没有分区
三 Vold中各模块分析
&&&&&&&& 在vold进程main函数中创建了很多的类实例,并将其启动。
int main()
vm-&start();
nm-&start();
cl-&startListener();
这些类对象之间是如何的,还需要现弄清楚每个类的职责和工作机制。
1 NetlinkManager模块
  NetlinkManager模块接收从Kernel发送的Uevent消息,解析转换成NetlinkEvent对象;再将此NetlinkEvent对象传递给VolumeManager处理。
此模块相关的类结构:
下面从start开始,看起如何对Kernel的Uevent消息进行监控的。
NetlinkManager start:
int NetlinkManager::start() {
//netlink使用的socket结构
struct sockaddr_
//初始化socket数据结构
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
nladdr.nl_groups = 0xffffffff;
//创建socket PF_NETLINK类型
mSock = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
//配置socket 大小
setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz);
setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on);
//bindsocket地址
bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr);
//创建NetlinkHandler 传递socket标识,并启动
mHandler = new NetlinkHandler(mSock);
mHandler-&start();
NetlinkHandler start:
int NetlinkHandler::start() {
    //父类startListener
    return this-&startListener();
NetlinkListener start:
int SocketListener::startListener() {
   //NetlinkHandler mListen为false
if (mListen && listen(mSock, 4) & 0) {
return -1;
} else if (!mListen){
//mListen为false 用于netlink消息监听
//创建SocketClient作为SocketListener 的客户端
mClients-&push_back(new SocketClient(mSock, false, mUseCmdNum));
//创建匿名管道
pipe(mCtrlPipe);
//创建线程执行函数threadStart
pthread_create(&mThread, NULL, SocketListener::threadStart, this);
线程监听Kernel netlink发送的UEvent消息:& & &
void *SocketListener::threadStart(void *obj) {
//参数转换
SocketListener *me = reinterpret_cast&SocketListener *&(obj);
me-&runListener();
pthread_exit(NULL);
return NULL;
SocketListener 线程消息循环:
void SocketListener::runListener() {
//SocketClient List
SocketClientCollection *pendingList = new SocketClientCollection();
while(1) {
fd_set read_
//mListen 为false
if (mListen) {
FD_SET(mSock, &read_fds);
//加入一组文件描述符集合 选择fd最大的max
FD_SET(mCtrlPipe[0], &read_fds);
pthread_mutex_lock(&mClientsLock);
for (it = mClients-&begin(); it != mClients-&end(); ++it) {
int fd = (*it)-&getSocket();
FD_SET(fd, &read_fds);
if (fd & max)
pthread_mutex_unlock(&mClientsLock);
//监听文件描述符是否变化
rc = select(max + 1, &read_fds, NULL, NULL, NULL);
//匿名管道被写,退出线程
if (FD_ISSET(mCtrlPipe[0], &read_fds))
//mListen 为false
if (mListen && FD_ISSET(mSock, &read_fds)) {
//mListen 为ture 表示正常监听socket
//接收客户端连接
c = accept(mSock, &addr, &alen);
} while (c & 0 && errno == EINTR);
//此处创建一个客户端SocketClient加入mClients列表中,异步延迟处理
pthread_mutex_lock(&mClientsLock);
mClients-&push_back(new SocketClient(c, true, mUseCmdNum));
pthread_mutex_unlock(&mClientsLock);
/* Add all active clients to the pending list first */
pendingList-&clear();
//将所有有消息的Client加入到pendingList中
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);
pthread_mutex_unlock(&mClientsLock);
//处理所有消息
while (!pendingList-&empty()) {
it = pendingList-&begin();
SocketClient* c = *
pendingList-&erase(it);
//处理有数据发送的socket 虚函数
if (!onDataAvailable(c) && mListen) {
//mListen为false
Netlink消息处理:
  在消息循环中调用onDataAvailable处理消息,onDataAvailable是个虚函数,NetlinkListener重写了此函数。
NetlinkListener onDataAvailable消息处理:
bool NetlinkListener::onDataAvailable(SocketClient *cli)
//获取socket id
int socket = cli-&getSocket();
//接收netlink uevent消息
count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv(
socket, mBuffer, sizeof(mBuffer), &uid));
//解析uevent消息为NetlinkEvent消息
NetlinkEvent *evt = new NetlinkEvent();
evt-&decode(mBuffer, count, mFormat);
//处理NetlinkEvent onEvent虚函数
onEvent(evt);
&&  将接收的Uevent数据转化成NetlinkEvent数据,调用onEvent处理,NetlinkListener子类NetlinkHandler重写了此函数。
NetlinkHandler NetlinkEvent数据处理:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
//获取VolumeManager实例
VolumeManager *vm = VolumeManager::Instance();
//设备类型
const char *subsys = evt-&getSubsystem();
//将消息传递给VolumeManager处理
if (!strcmp(subsys, "block")) {
vm-&handleBlockEvent(evt);
    NetlinkManager通过NetlinkHandler将接收到Kernel内核发送的Uenvet消息,
  转化成了NetlinkEvent结构数据传递给VolumeManager处理。
2 VolumeManager模块
  此模块管理所有挂载的设备节点以及相关操作执行;下面是VolumeManager模块类结构图:
    DirectVolume:一个实体存储设备在代码中的抽象。
    SocketListenner:创建线程,监听socket。
  这里VolumeManager构造的SocketListenner与NetlinkManager构造的SocketListenner有所不同的:
    NetlinkManager构造的SocketListenner:Kernel与Vold通信;
    VolumeManager构造的SocketListenner:Native Vold与Framework MountService 通信;
  VolumeManager构造的SocketListenner,由vold进程main函数中创建的CommandListener:
int main() {
CommandListener *
cl = new CommandListener();
vm-&setBroadcaster((SocketListener *) cl);
//启动CommandListener监听
cl-&startListener();
VolumeManager工作流程:
//从main函数中的start开始:
int VolumeManager::start() {
  NetlinkManager接收到Kernel通过netlink发送的Uevent消息,转化成了NetlinkEvent消息,再传递给了VolumeManager处理。
NetlinkManager与VolumeManager交互流程图:
VolumeManager处理消息 handleBlockEvent:
  从NetlinkManager到VolumeManager代码过程
  函数执行从onEvent到handleBlockEvent:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
//将消息传递给VolumeManager处理
if (!strcmp(subsys, "block")) {
vm-&handleBlockEvent(evt);
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
//有状态变化设备路径
  const char *devpath = evt-&findParam("DEVPATH");
  //遍历VolumeManager中所管理Volume对象(各存储设备代码抽象)
  for (it = mVolumes-&begin(); it != mVolumes-&end(); ++it) {
  if (!(*it)-&handleBlockEvent(evt)) {
  hit = true;
   break;
将消息交给各个Volume对象处理:DirectVolume
  从VolumeManager到所管理的Volume对象
    这里的Volume为其派生类DirectVolume。
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
//有状态变化设备路径
const char *dp = evt-&findParam("DEVPATH");
PathCollection::
for (it = mPaths-&begin(); it != mPaths-&end(); ++it) {
//匹配 设备路径
if (!strncmp(dp, *it, strlen(*it))) {
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"));
char nodepath[255];
//设备节点路径名称
snprintf(nodepath,sizeof(nodepath), "/dev/block/vold/%d:%d",
major, minor);
//创建设备节点
createDeviceNode(nodepath, major, minor);
if (!strcmp(devtype, "disk")) {
//添加disk
handleDiskAdded(dp, evt);
//添加分区
handlePartitionAdded(dp, evt);
} else if (action == NetlinkEvent::NlActionRemove) {
} else if (action == NetlinkEvent::NlActionChange) {
SLOGW("Ignoring non add/remove/change event");
&    为什么要让VolumeManager中的每一个Volume对象都去处理SD状态变换消息,
  每一个Volume可能对应多个Path;即一个挂载点对应多个物理设备。
抽象存储设备DirectVolume 动作状态变化处理:
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
//主次设备号
mDiskMajor = atoi(evt-&findParam("MAJOR"));
mDiskMinor = atoi(evt-&findParam("MINOR"));
//设备分区情况
const char *tmp = evt-&findParam("NPARTS");
  mDiskNumParts = atoi(tmp);
if (mDiskNumParts == 0) {
//没有分区,Volume状态为Idle
setState(Volume::State_Idle);
//有分区未加载,设置Volume状态Pending
setState(Volume::State_Pending);
//格式化通知msg:"Volume sdcard /mnt/sdcard disk inserted (179:0)"
char msg[255];
snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
//调用VolumeManager中的Broadcaster&&&CommandListener 发送此msg
mVm-&getBroadcaster()-&sendBroadcast(ResponseCode::VolumeDiskInserted,
msg, false);
消息通知Framework层存储设备状态变化:
  类继承关系:
  发送消息通知Framework层是在SocketListener中完成;
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
pthread_mutex_lock(&mClientsLock);
//遍历所有的消息接收时创建的Client SocketClient
// SocketClient将消息通过socket(&vold&)通信
for (i = mClients-&begin(); i != mClients-&end(); ++i) {
(*i)-&sendMsg(code, msg, addErrno, false);
pthread_mutex_unlock(&mClientsLock);
  这里工作的SocketListener是VolumeManager的,SocketListener的派生类CommandListener,
用来与Framework交互的,监听Socket消息。通过VolumeManager中调用sendBroadcast,与CommandListener模块进行交互。
由此需要清楚CommandListener模块工作流程。
3 CommandListener模块
  CommandListener监听Socket,使Vold与Framework层进行进程通信;
其相关类继承结构图如下:
CommandListener工作流程:
int main()
  VolumeManager *
  CommandListener *
   NetlinkManager *
//CommandListener 创建vold socket监听上层消息
  cl = new CommandListener();
  //作为VolumeManager与NetlinkManager的Broadcaster
  vm-&setBroadcaster((SocketListener *) cl);
   nm-&setBroadcaster((SocketListener *) cl);
//启动CommandListener监听
  cl-&startListener();
CommandListener实例的创建:构造函数
&&&&&&&& CommandListener构造函数:
  CommandListener::CommandListener() :
FrameworkListener("vold", true) {
//注册Framework发送的相关命令 Command模式
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new XwarpCmd());
registerCmd(new CryptfsCmd());
FrameworkListener构造函数:
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
mCommands = new FrameworkCommandCollection();
mWithSeq = withS
注册Command:
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
mCommands-&push_back(cmd);
SocketListener构造函数:
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
//mListen = true 正常的socket监听
//socket 名称&vold&
mSocketName = socketN
mSock = -1;
mUseCmdNum = useCmdN
//初始化锁
pthread_mutex_init(&mClientsLock, NULL);
//构造Listener Client List
mClients = new SocketClientCollection();
CommandListener启动 startListener:
int SocketListener::startListener() {
//mSocketName = &Vold&
mSock = android_get_control_socket(mSocketName);
//NetlinkHandler mListen为true 监听socket
if (mListen && & 0) {
return -1;
} else if (!mListen){
mClients-&push_back(new SocketClient(mSock, false, mUseCmdNum));
//创建匿名管道
pipe(mCtrlPipe);
//创建线程执行函数threadStart 参数this
pthread_create(&mThread, NULL, SocketListener::threadStart, this);
void *SocketListener::threadStart(void *obj) {
SocketListener *me = reinterpret_cast&SocketListener *&(obj);
me-&runListener();
void SocketListener::runListener() {
//SocketClient List
SocketClientCollection *pendingList = new SocketClientCollection();
while(1) {
fd_set read_
//mListen 为true
if (mListen) {
FD_SET(mSock, &read_fds);
//加入一组文件描述符集合 选择fd最大的max select有关
FD_SET(mCtrlPipe[0], &read_fds);
pthread_mutex_lock(&mClientsLock);
for (it = mClients-&begin(); it != mClients-&end(); ++it) {
int fd = (*it)-&getSocket();
FD_SET(fd, &read_fds);
if (fd & max)
pthread_mutex_unlock(&mClientsLock);
//监听文件描述符是否变化
rc = select(max + 1, &read_fds, NULL, NULL, NULL);
//匿名管道被写,退出线程
if (FD_ISSET(mCtrlPipe[0], &read_fds))
//mListen 为true
if (mListen && FD_ISSET(mSock, &read_fds)) {
//mListen 为ture 表示正常监听socket
c = accept(mSock, &addr, &alen);
} while (c & 0 && errno == EINTR);
//创建一个客户端SocketClient,加入mClients列表中 到异步延迟处理
pthread_mutex_lock(&mClientsLock);
mClients-&push_back(new SocketClient(c, true, mUseCmdNum));
pthread_mutex_unlock(&mClientsLock);
/* Add all active clients to the pending list first */
pendingList-&clear();
//将所有有消息的Client加入到pendingList中
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);
pthread_mutex_unlock(&mClientsLock);
/* Process the pending list, since it is owned by the thread,*/
while (!pendingList-&empty()) {
it = pendingList-&begin();
SocketClient* c = *
//处理有数据发送的socket
if (!onDataAvailable(c) && mListen) {
//mListen为true
  CommandListener启动的线程监听Socket消息,接收到的消息处理onDataAvailable。
CommandListener父类FrameworkCommand重写了此函数。
CommandListener监听Socket消息处理:
bool FrameworkListener::onDataAvailable(SocketClient *c) {
char buffer[255];
//读取socket消息
len = TEMP_FAILURE_RETRY(read(c-&getSocket(), buffer, sizeof(buffer)));
for (i = 0; i & i++) {
if (buffer[i] == '\0') {
//根据消息内容 派发命令
dispatchCommand(c, buffer + offset);
offset = i + 1;
return true;
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
char *argv[FrameworkListener::CMD_ARGS_MAX];
//解析消息内容 命令 参数
//执行对应的消息
for (i = mCommands-&begin(); i != mCommands-&end(); ++i) {
FrameworkCommand *c = *i;
//匹配命令
if (!strcmp(argv[0], c-&getCommand())) {
//执行命令
c-&runCommand(cli, argc, argv);
Command执行处理:以VolumeCommand为例 
CommandListener::VolumeCmd::VolumeCmd() :
VoldCommand("volume") {
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
//获取VolumeManager实例
VolumeManager *vm = VolumeManager::Instance();
//Action判断 传递给VolumeManager处理
if (!strcmp(argv[1], "list")) {
return vm-&listVolumes(cli);
} else if (!strcmp(argv[1], "debug")) {
vm-&setDebug(!strcmp(argv[2], "on") ? true : false);
} else if (!strcmp(argv[1], "mount")) {
rc = vm-&mountVolume(argv[2]);
} else if (!strcmp(argv[1], "unmount")) {
rc = vm-&unmountVolume(argv[2], force, revert);
} else if (!strcmp(argv[1], "format")) {
rc = vm-&formatVolume(argv[2]);
} else if (!strcmp(argv[1], "share")) {
rc = vm-&shareVolume(argv[2], argv[3]);
} else if (!strcmp(argv[1], "unshare")) {
rc = vm-&unshareVolume(argv[2], argv[3]);
} else if (!strcmp(argv[1], "shared")) {
    CommandListener使用Command模式。
  CommandListener接收到来自Framework层得消息,派发命令处理,再传递给VolumeManager处理。
VolumeManager中Action处理:
int VolumeManager::unmountVolume(const char *label) {
  //查找Volume
  Volume *v = lookupVolume(label);
  //Volume执行动作
return v-& unmountVol ();
//VolumeAction处理:
int Volume::unmountVol(bool force, bool revert) {
doUnmount(Volume::SEC_STG_SECIMGDIR, force);
int Volume::doUnmount(const char *path, bool force) {
//systemcall
umount(path);
整个Vold处理过程框架图如下:
阅读(...) 评论()Posts - 162,
Articles - 0,
Comments - 1335
11:01 by Terry_龙, ... 阅读,
前段时间对Android 的SDCard unmount 流程进行了几篇简短的分析,由于当时只是纸上谈兵,没有实际上的跟进,可能会有一些误导人或者小错误。今天重新梳理了头绪,针对mount的流程再重新分析一次。
android 系统如何开机启动监听mount服务
默认设备节点在Android 系统的哪个目录
vold.fstab 配置文件的分析&
vold 里面启动页面main做了些什么
android 系统如何开机启动监听mount服务
android sdcard 热插拔监测和执行操作是由一个启动文件vold &所统领的,系统开机会读取初始化配置文件init.rc,该文件位于比如我的板子是:device/ti/omap3evm/init.rc,具体根据自己平台查找。里面有一个是默认启动vold 服务的代码,如下:
service&vold&/system/bin/vold
&&&&socket&vold&stream&0660&root&mount
& & ioprio&be&2&
&如果要对该文件做出修改之类,要重新编一下boot.img 镜像文件,烧录进android 系统,之后可以在android的文件系统根目录找到init.rc文件。上述代码为启动vold 启动文件,也可以在init.rc 增加多一些我们想要的文件目录,比如增加一个可以存放多分区挂载的目录等,这个是后话。
&默认设备节点在Android 系统的哪个目录
&usbdisk 或者 sdcard 热插拔的时候,kernel 会发出命令执行mount或者unmount 操作,但这都是驱动级的。而mount 目录会在android 的文件系统目录下:/dev/block/vold 这个目录由vold 生成,用来存放所有的usbdisk 或者 sdcard 的设备节点。代码位于main里面最优先执行:
mkdir("/dev/block/vold",&0755);&
&可以根据这个目录找到如下节点:
sh-4.1#&ls&/dev/block/vold/
179:0&&179:1&&8:0&&&&8:1&&&&8:2&&&&8:3&&&&8:4&
节点的小介绍:
0代表当前的整个设备,1代码当前设备的分区名称代号。
所以你会发现,sdcard只有一个分区它却生成了两个如:179:0 179:1
而usbdisk 有四个分区,它会生成五个设备节点:&8:0&&&&8:1&&&&8:2&&&&8:3&&&&8:4 &就是这个原因。
&vold.fstab 配置文件的分析
vold 里面会通过指定文件来读取预先配置好的sdcard或者多分区配置文件,该文件位于
/system/core/rootdir/etc/vold.fstab
如以下的配置文件为:
dev_mount&sdcard&/mnt/sdcard&auto&/devices/platform/goldfish_mmc.0&/devices/platform/msm_sdcc.2/mmc_host/mmc1
&dev_mount 代表挂载格式
&sdcard 代表挂载的标签
/mnt/sdcard 代表挂载点
&auto 为自定义选项可以为任何,但必须在main 里面自己判断比如这里的意思为自动挂载
后面两个目录为设备路径,第一个如果被占用会选择第二个
配置文件可以根据自己的需要编写,并不是固定的,但最好遵循google vold 启动文件代码的格式编写,要不然会给我们修改代码或者增加多分区功能带来不小的麻烦,如以下我自己编写的多分区挂载支持vold.fstab 配置文件:
&dev_mount&sdcard&external&/mnt/sdcard&auto&/devices/platform/mmci-omap-hs.0/mmc_host/mmc0&/devices/platform/mmci-omap-hs.0/mmc_host/mmc1
dev_mount&usb1&external&/mnt/usbdisk/usb1-disk%d&all&/devices/platform/ehci-omap.0/usb1/1-2/1-2.1/
dev_mount&usb2&external&/mnt/usbdisk/usb2-disk%d&all&/devices/platform/ehci-omap.0/usb1/1-2/1-2.2/
dev_mount&usb3&external&/mnt/usbdisk/usb3-disk%d&all&/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/
&该文件修改后经系统编译会在android 系统目录里/system/etc/vold.fstab找到。&/devices/platform/ehci-omap.0/usb1/1-2/1-2.1/ &代表要挂载的USB口。vold.fstab 只是一个单纯的配置文件,具体的读取和取数据还 是要靠main里面的process_config函数。看代码,里面正有一段用来读取配置文件:& if&(!(fp&=&fopen("/etc/vold.fstab",&"r")))&{&&&&&&&&return&-1;&&&&}在这个函数里面会根据读取到的数据存放起来,然后满足条件时执行操作。比如代码里面的:&if&(!strcmp(type,&"dev_mount"))&{&&&&&&&&&&&&DirectVolume&*dv&=&NULL;&&&&&&&&&&&&char&*&&&&&&&&&&&&if&(!(part&=&strtok_r(NULL,&delim,&&save_ptr)))&{&&&&&&&&&&&&&&&&SLOGE("Error&parsing&partition");&&&&&&&&&&&&&&&&goto&out_&&&&&&&&&&&&}&&&&&&&&&&&&if&(strcmp(part,&"auto")&&&&atoi(part)&==&0)&{&&&&&&&&&&&&&&&&SLOGE("Partition&must&either&be&'auto'&or&1&based&index&instead&of&'%s'",&part);&&&&&&&&&&&&&&&&goto&out_&&&&&&&&&&&&}&&&&&&&&&&&&if&(!strcmp(part,&"auto"))&{&&&&&&&&&&&&&&&&dv&=&new&DirectVolume(vm,&label,&mount_point,&-1);&&&&&&&&&&&&}&else&{&&&&&&&&&&&&&&&&dv&=&new&DirectVolume(vm,&label,&mount_point,&atoi(part));&&&&&&&&&&&&}&&&&&&&&&&&&while&((sysfs_path&=&strtok_r(NULL,&delim,&&save_ptr)))&{&&&&&&&&&&&&&&&&if&(*sysfs_path&!=&'/')&{&&&&&&&&&&&&&&&&&&&&/*&If&the&first&character&is&not&a&'/',&it&must&be&flags&*/&&&&&&&&&&&&&&&&&&&&break;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&if&(dv-&addPath(sysfs_path))&{&&&&&&&&&&&&&&&&&&&&SLOGE("Failed&to&add&devpath&%s&to&volume&%s",&sysfs_path,&&&&&&&&&&&&&&&&&&&&&&&&&label);&&&&&&&&&&&&&&&&&&&&goto&out_&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&&&&&/*&If&sysfs_path&is&non-null&at&this&point,&then&it&contains&&&&&&&&&&&&&*&the&optional&flags&for&this&volume&&&&&&&&&&&&&*/&&&&&&&&&&&&if&(sysfs_path)&&&&&&&&&&&&&&&&flags&=&parse_mount_flags(sysfs_path);&&&&&&&&&&&&else&&&&&&&&&&&&&&&&flags&=&0;&&&&&&&&&&&&dv-&setFlags(flags);&&&&&&&&&&&&vm-&addVolume(dv);&&&&&&&&}&
DirectVolume后面会讲到,执行mount 和unmount 都是它在做。另外,有时后读取配置文件会有问题,这是因为它读取是通过指标下标递增的方式在读,如果有问题可以跟踪打印一下配置文件,看哪里需要修改。&
&vold 里面启动页面main做了些什么main 主要是初始化socket 连接监听数据变化,在系统起来时第一时间启动,并且通过读取配置文件来识别usb口或者sdcard 的设备地址,来mount 或者unmount 。其它执行mount 、 unmount &或者删除节点等操作都是由上层或者framework 发送命令给main让其通知volumeManage 执行相应的操作。}

我要回帖

更多关于 vold.fstab修改教程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信