Android6.0 sdcard流程
2024-01-08 16:31:03 0 举报
文件系统完成流程图
作者其他创作
大纲/内容
case 'u':
android\\system\\vold\\Disk.cpp
创建工作线程,线程运行函数threadStart
vm = VolumeManager::Instance()
1
vol->create();
system/vold/CommandListener.cpp
创建匿名管道
PublicVolume::doMount()
else
nm->setBroadcaster((SocketListener *) cl);
mDiskSources.push_back(diskSource);
通过inotify机制观察/data/system/packages.list文件变化
NativeDaemonConnector.java
watch_package_list(&global)
cryptfs_revert_ext_volume(getId().c_str());
doUnmount()
//创建event socket
1. 设置挂载路径
Vold的service定义如下
readMetadata();
HandlerThread hthread = new HandlerThread(TAG);hthread.start();
创建单例对象NetlinkManager
android\\system\\vold\\VolumeBase.cpp
ForceUnmount(mFuseDefault);
mInternalEmulated->create()
if (cmd == \"shutdown\
建立连接后,回调MS.onDaemonConnected
PrivateVolume使用外置存储来模拟内置存储,需要挂载mDmDevPath作为存储设备(需要对数据进行加密/解密),然后对为该设备的media节点创建一个EmulatedVolume,来模拟外置存储使用。这里总结下EmulatedVolume, /data分区作为一个内置存储,如果使用模拟分区作为主存储则会创建一个EmulatedVolume来模拟外置存储,目录为/data/media。 其他的PrivateVolume下再这里创建一个EmulatedVolume,会通过MountService有模拟分区创建,如果该模拟分区是主存储分区,则会挂载该模拟分区,如果不是主分区,则不会挂载该模拟分区,为PrivateVolume创建EmulatedVolume,并不一定会被挂载,只有模拟的主分区才会被挂载。读者可以回过头来看看MountService中处理新家卷的时候对EmulatedVolume的处理,如果系统设置了使用PrivateVolume作为主存储的话,可以将主存储建迁移PrivateVolume对应的EmulatedVolume,我们在存储格式化的文章中将会看到这一点
mCommands->push_back(cmd);
fstab = fs_mgr_read_fstab(path.c_str());
EmulatedVolmue创建
else if (cmd == \"mount\" && argc > 2)
found.responses.put(response);
android::vold::ForceUnmount(path);
1023
2
3 创建相关的文件夹
while(1) { sleep(1000);}
NetlinkManager.cpp
PublicVolume::doCreate()
FrameworkListener::onDataAvailable(SocketClient *c)
mLabel = tmp;
if (mSystemReady && mDaemonConnected)
if (getMountFlags() & MountFlags::kPrimary)
new DiskSource对象,添加到mDiskSources中
this->startListener()
设置uevent的SO_PASSCRED选项
handleBlockEvent的逻辑实际上是比较简单的,从NetlinkEvent中获取主,次设备号,和ueventuevent对应的设备文件的/sys/block路径。对于add消息, 根据主设备号确定设备的类型是usb还是sd卡。从NetlinkEvent中获取uevent对应的设备文件的/sys/block路径,然后和DiskSource做比较,确定是不是对应voldmanaged标志的设备,如果是voldmanaged的设备就会创建Disk数据结构,再调用Disk.create()函数执行初始化。将初始化好的Disk数据结构保存起来。对于change消息,则重新读取设备的meta信息和分区信息。remove消息则调用Disk.destory()函数,从mDisks中移除Disk数据结构。
通知VolumeCreated事件
将新建的CommandListener对象赋值给mBroadcaster
ForceUnmount(mFuseWrite);
android\\system\\core\\sdcard\\sdcard.c
/dev下的设备路径
mCtrlPipe是匿名管道,这是一个二元数组,mCtrlPipe[0]从管道读数据,mCtrlPipe[1]从管道写数据。
??实际测试改目录没有任何文件
f (table == Table::kUnknown || !foundParts)
public void onStart()
PublicVolume.cpp
case 'm':
int NetlinkManager::start()
class CommandListener : public FrameworkListenerclass FrameworkListener : public SocketListener
android\\frameworks\\base\\services\\core\\java\\com\\android\\server\\MountService.java
if (mJustPartitioned)
FrameworkListener.cpp
if (cmd == \"mount\
PublicVolume : public VolumeBase
if (devType != \"disk\") return;
4 设置gid,保证拥有source_path的读写权限
通过socket向MountService发送创建volume的命令(650)
PublicVolume作为外置存储,先通过mount进行挂载,然后为了实现外置存储的读写权限,使用fuse来进行挂载。另外如果设备要对用户可见,就将/storage/${stable} 作为对外使用的路径,我们分析外置存储的时候会对这个路径加以说明。如果这个PublicVolume作为主存储,需要使用fuse的fullwrite模式,否则不使用该模式。
cl = new CommandListener();
main.cpp
转mountService的onEvent
publishBinderService(\"mount\
2 挂载对应的fuse目录
等待mConnectedSignal计数锁达到零
1 解析参数配置相应的变量值
readPartitions()
处理文件操作请求
coldboot(\"/sys/block\");
/解析socket服务端发送的event
?????读取分区信息
source_path = arg;
me->runListener();
分发MountService读取到的命令
warnOnNotMounted();
mRawPath = StringPrintf(\"/mnt/media_rw/%s\
status_t VolumeBase::mount()
setBroadcaster(SocketListener *sl)
创建这些对象 DumpCmd,VolumeCmd,AsecCmd,ObbCmd,StorageCmd,FstrimCmd,并都加入到mCommands队列
VolumeManager *VolumeManager::Instance()
卸载外部存储
if (cmd == \"\"partition\" && argc > 3\
Disk创建
用于监听Kernel发送过程的uevent事件
//调用PMS来加载ASECs
int VolumeManager::start()
//解析fstab.sun8w11p1内容
for (auto source : mDiskSources)
NetlinkHandler.cpp
Aciton:kAdd,这个函数先创建了设备,根据major和minor。从mDiskSources看是否有满足的DiskSource,然后获取其flags,然后新建Disk,调用create函数
getMountService().getSecureContainerList();
mFuseDefault = StringPrintf(\"/mnt/runtime/default/%s\
解析Fstab
PrivateVolume::doMount()
类型为CountDownLatch,用于多线程同步,阻塞await()直到计数器为零
这是用于分发从MountService发送过来的命令,针对不同的命令调用不同的类,总共有以下6类:DumpCmdVolumeCmdAsecCmdObbCmdStorageCmdFstrimCmd另外,在处理过程中遇到下面情况,则会直接发送响应吗500的应答消息给MountService,当无法找到匹配的类,则会直接向MountService返回响应码500,内容”Command not recognized”的应答消息;命令参数过长导致socket管道溢出,则会发送响应码500,内容”Command too long”的应答消息。
registerCmd(new DumpCmd());registerCmd(new VolumeCmd());registerCmd(new AsecCmd());registerCmd(new ObbCmd());registerCmd(new StorageCmd());registerCmd(new FstrimCmd());
启动响应命令的SocketListener监听器
if (source->matches(eventPath))
创建了一个DiskInfo数据结构
vol->setDiskId(getId());
FrameworkListener::registerCmd(FrameworkCommand *cmd)
创建CommandListener对象
disk->unmountAll();
Vold成为监听线程
sInstance = new VolumeManager();
handleDaemonConnected()
mSystemServiceManager.startService(MOUNT_SERVICE_CLASS); mountService = IMountService.Stub.asInterface( ServiceManager.getService(\"mount\"));
KillProcessesUsingPath(getPath());
Android存储系统之架构篇
1 准备fuse相关的文件夹
如果一个EmulatedVolume被挂载,它一定是一个主分区,没啥可说对mRawPath目录做fuse模拟。
cl.startListener
由继承关系可知,onDataAvaliable会回调到NetlinkListener和FrameworkListener的onDataAvailable方法
setuid(uid)
init.rc
sdcard.c
设备的唯一id,默认disk:${主设备号}😒{次设备号}
Disk::createPublicVolume(dev_t device)
coldboot实现的功能就是遍历path下所有的uevent文件,然后写入”add\“四个字节到uevent文件(175行)。uevent主要是udev协议的一部分,当设备进行热插拔的时候,上层应用程序可以通过netlink收到相应的add,remove,change等消息,这样就可以调用mknod在/dev/目录下创建对应的驱动设备文件,这样才可以使用设备文件来操作设备。 在vold的启动过程中,由于块设备早就准备好了,不会收到设备插拔的消息,没有办法对固有的设备来创建对应的Disk和Volume结构。好在udev提供了一套机制,就是可以通过写uevent来触发热插拔事件,这里写入add就代表触发一个设备插入事件。前面我们已经启动了NetlinkManager来监听netlink事件,这里来触发uevent的设备插入事件,VolumeManager就可以创建相应的Disk和Volume数据结构了。
status_t Disk::create()
android\\system\\vold\\NetlinkManager.cpp
kPackagesListFile = \"/data/system/packages.list\":使用inotify观察/data/system/packages.list文件删除事件,当安装或者卸载应用后,该文件就会重建
status_t VolumeBase::create()
mDevPath = StringPrintf(\"/dev/block/vold/%s\
强制卸载“/proc/mounts”中目录包含mnt或者storage的路径
onEvent(evt);
case 0x06:....
mbr分区表直接创建PublicVolume
mConnector.execute(\"volume\
case 'w':
auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
Disk.cpp
读取socket内容
mDevPath = StringPrintf(\"/dev/block/vold/%s\
(mount(\"/dev/fuse\
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
frameworks\\base\\services\\core\\java\\com\\android\\server\\pm\\PackageManagerService.java
android\\system\\vold\\NetlinkHandler.cpp
创建线程名为\"VoldConnector\"的线程,用于跟vold通信
创建Emulated内部存储
采用poll轮询方式等待底层上报该事件,直到1分钟超时(ReentrantLock和synchronized区别)
struct fuse_handler* handler = data;
android\\system\\core\\libsysutils\\src\\NetlinkListener.cpp
socket.connect(address);
int res = vol->mount();
setPath(StringPrintf(\"/storage/%s\
MountService 和vold 对外置存储的管理(2)
on post-fs-datastart vold //启动vold服务
VolumeBase.cpp
PublicVolume的创建首先创建一个PublicVolume实例,然后如果Disk刚刚进行分区,要先进行格式化。mJustPartitioned为true的情况进行格式化,这不是我们关注的重点。创建完PublicVolume实例后最重要的是调用create函数来创建
onVolumeCreatedLocked(vol);
mActivityManagerService.systemReady(new Runnable() { public void run() {mSystemServiceManager.startBootPhase( SystemService.PHASE_ACTIVITY_MANAGER_READY); }}
case kMajorBlockScsiA:.......
mVolumes.push_back(vol);
while (true) {listenToSocket();}
用于通知ASEC扫描已完成
NetlinkHandler::onEvent(NetlinkEvent *evt)
转VolumeManager::handleBlockEvent
case FUSE_OPEN:
const char* cpath = path.c_str();
socket = new LocalSocket();
int NetlinkHandler::start()
std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id)
创建单例对象VolumeManager
public void run()
handle_fuse_requests(struct fuse_handler* handler)
对于add消息, 根据主设备号确定设备的类型是usb还是sd卡。从NetlinkEvent中获取uevent对应的设备文件的/sys/block路径,然后和DiskSource做比较,确定是不是对应voldmanaged标志的设备,如果是voldmanaged的设备就会创建Disk数据结构,再调用Disk.create()函数执行初始化。将初始化好的Disk数据结构保存起来。对于change消息,则重新读取设备的meta信息和分区信息。remove消息则调用Disk.destory()函数,从mDisks中移除Disk数据结构。
vol->setSilent(true);vol->create();vol->format(\"auto\");vol->destroy();vol->setSilent(false);
std::string path(mSysPath + \"/device/manfid\");
EmulatedVolume::doUnmount()
int SocketListener::startListener()
mInternalEmulated的据类型为EmulatedVolume,设备路径为/data/media,id和label为“emulated”,mMountFlags=0。EmulatedVolume继承于VolumeBase
调用mknod 创建dev设备文件,目录为/dev/block/vold/。相当于vold实现了部分udev的功能
//通过getprop ro.hardware获取Fstab路径:./fstab.sun8iw11p1
frameworks\\base\\services\\java\\com\\android\\server\\SystemServer.java
mCommands = new FrameworkCommandCollection();
SocketListener *me = reinterpret_cast<SocketListener *>(obj);
label = \"emulated\"
mFuseRead = StringPrintf(\"/mnt/runtime/read/%s\
NetlinkManager的start方法
android\\system\\vold\\EmulatedVolume.cpp
2 将消息转成fuse_in_header + data 两部分
unmountAll();
if (!(mFusePid = fork()))
mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
cmd.push_back(kSgdiskPath);//\"/system/bin/sgdisk\";
mSock = socketFd;
setId(StringPrintf(\"public:%u:%u\
// 有写外置存储权限,只有在全写模式下树主才有写权限,否则只有读权限
mEventPath = eventPath;
waitForReady();
FgThread线程名为“\"android.fg\",创建IMountServiceListener回调方法
for (it = mClients->begin(); it != mClients->end(); ++it) {SocketClient* c = *it;pendingList.push_back(c);}
内部私有volume的路径为/data,该volume通过dumpsys mount是不会显示的
if (type == \"private\
case FUSE_WRITE:
uevent文件路径
for (auto line : output)
handleMessage(Message msg)
addInternalVolume();
根据命令找到对应卷,然后调用VolumeBase的mount方法进行挂载
PrivateVolume::doCreate()
std::string path(android::vold::DefaultFstabPath());
status_t res = doMount();
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
process_config(vm)
mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>( new android::vold::EmulatedVolume(\"/data/media\"));
final String[] list = PackageHelper.getSecureContainerList();
卸载内部存储
。。。。。
destroyAllVolumes();
MountServiceHandler::handleMessage(Message msg)
android\\system\\vold\\Utils.cpp
mFuseWrite = StringPrintf(\"/mnt/runtime/write/%s\
分区类型为Android扩展,创建一个私有分区
status_t VolumeBase::unmount()
frameworks\\base\\services\\core\\java\\com\\android\\server\\SystemServiceManager.java
创建dev设备
1 读取卷的信息
VolumeManager::handleBlockEvent(NetlinkEvent *evt)
分区类型为基础数据分区,代表一个PublicVolume
mPms.scanAvailableAsecs();
public void onBootPhase(int phase)
android\\system\\vold\\PrivateVolume.cpp
创建用于VoldConnector的NDC对象
NetlinkHandler继承于NetlinkListener,NetlinkListener继承于SocketListener。new NetlinkHandler(mSock)中参数mSock是用于与Kernel进行通信的socket对象。
private void listenToSocket()
卸载所有卷
read_package_list(global)
5 fork新进程启动sdcard
NetlinkEvent *evt = new NetlinkEvent()
mPath = StringPrintf(\"/mnt/expand/%s\
setState(State::kUnmounted);
public void onDaemonConnected()
nladdr.nl_pid = getpid();
case VoldResponseCode.DISK_CREATED:
Android存储系统-MountService 和vold 对外置存储的管理
CommandListener.cpp
class NetlinkHandler: public NetlinkListener
public String[] getSecureContainerList()
//有读外置存储权限。默认支持属主读权限和数组读写权限
监听vold的socket
mSequenceNumber初始化值为0,每执行一次该方法则进行加1操作
nm->start()
resetIfReadyAndConnectedLocked()
vm->setBroadcaster((SocketListener *) cl)
读取新的/data/system/packages.list文件
status_t res = doCreate();
PrivateVolume.cpp
mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));
return NativeDaemonEvent.filterMessageList(mConnector.executeForList(\"asec\
4 准备media目录,生成模拟卷,模拟media目录
3 准备目录
android\\system\\core\\libsysutils\\src\\SocketListener.cpp
handle_fuse_requests(handler);
创建CryptCommandListener对象
没有找到则创建相应的PendingCmd
创建socket通信的client端
table = Table::kGpt;
killMediaProvider();mDisks.clear();mVolumes.clear();
NetLinkManager主要设置套接字,然后传递给NetlinkHanler,调用NetllinkHandler来进行监听。 关于netlink主要就是通过套接字的形式和内核建立起链接,来接收内核发送上来的事件。对于Netlink事件的监听,在Android系统的libsysutils库里面提供了一套基础的实现,这个实现不是我们关注的重点,我们只简单进行介绍。 最关键的类为NetlinkListener类,这个类启动后监听netlink套接字,收到数据后会将数据解析封装成数据结构NetlinkEvent,然后调用该类下的虚函数 virtual void onEvent(NetlinkEvent *evt)来对事件进行处理。vold的NetlinkManager创建的NetlinkHandler就是NetlinkListener的子类,它实现了onEvent函数,我们来看下它的实现。
MountService和Vold的整体流程与架构设计
service.onBootPhase(mCurrentPhase);
static void* start_handler(void* data)
android 6.0sd卡内部存储 & 外部存储
Disk::readPartitions()
startOtherServices()
MountService.java
android\\system\\vold\\PublicVolume.cpp
5 设置uid,保证拥有source_path的读写权限
mHandler = new MountServiceHandler(hthread.getLooper());
char* arg = argv[i];
frameworks\\base\\services\\core\\java\\com\\android\\server\\NativeDaemonConnector.java
2 利用传参,调用run函数
final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent(rawEvent);
创建线程名为\"CryptdConnector\"的线程,用于加密
设置为非挂载状态
当没有挂载Primary卷设备,则弹出警告
auto vol = vm->findVolume(id);
flags |= android::vold::Disk::Flags::kSd;
3 处理请求
mInternalEmulated->unmount();
int flags = source->getFlags();//从source获取flags
该方法的主要功能是创建下面4个对象并启动:VolumeManagerNetlinkManager (NetlinkHandler)CommandListenerCryptCommandListener
mHandler->start()
创建NetlinkHandler
auto disk = vm->findDisk(id);
case FUSE_MKDIR:
用于读取分区创建Volume数据结构。是磁盘挂载的最重要步骤
NetlinkManager *NetlinkManager::Instance()
switch (evt->getAction())
mCallbacks.onDaemonConnected();
(vm->start()
else if (mFsType == \"f2fs\")
android\\system\\vold\\main.cpp
mId = StringPrintf(\"disk:%u:%u\
PackageManagerService.java
full_write = true;
如上图所示,Android的sdcard进程中有四个线程, 其中main线程在创建了其他三个线程后调用watch_package_list()函数,来读取/data/system/packages_list.xml文件的内容。sdcard进程通过读取/data/system/packages_list.xml的内容,来维护程序包名和uid的关系,针对外置存储下 ${user_id}/Android 目录的动态权限做处理,基本思路就是当应用程序读写${user_id}/Android/media|obb|data/${package_name} 下文件的时候,把该目录下的文件属主都改成应用程序的uid,作为文件的属主基本上就获得了文件的读写权限,这样应用程序就可以不需要获取外置存储读写权限来读写${user_id}/Android/media|obb|data/${package_name} 下的文件了(因为应用程序就是属主)。
case H_VOLUME_MOUNT:
3
service vold /system/bin/vold
绑定uevent socket
std::string path(mSysPath + \"/device/vendor\");
else if (table == Table::kGpt)
根据gpt分区表设置分区信息
if (mFsType == \"ext4\")
其中DEFAULT_TIMEOUT=1min,即命令执行超时时长为1分钟
pipe(mCtrlPipe)
if (major == kMajorBlockMmc) {
FILE* fp = setmntent(\"/proc/mounts\
SystemServer.java
case 'g':
void scanAvailableAsecs()
frameworks\\base\\services\\core\\java\\com\\android\\server\\MountService.java
VolumeManager.cpp
for (;;) {
将MountServiceInternalImpl登记到sLocalServiceObjects
const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
执行VolumeManager的start方法
对于其他的响应码则添加到mResponseQueue队列
if (!mListen)
启动NetlinkHandler
case H_SYSTEM_READY:handleSystemReady()
auto vol = disk->findVolume(id);
mMountService.systemReady();
MountService线程通过socket发送cmd事件给vold,对于vold守护进程在启动的过程,初始化CommandListener时通过pthread_create创建子线程vold来专门监听MountService发送过来的消息,当该线程接收到socket消息时,便会调用onDataAvailable()方法
std::string devType(evt->findParam(\"DEVTYPE\"))
Disk::readMetadata()
NetlinkListener.cpp
//建立与\"/dev/socket/vold\"的socket连接
android\\system\\core\\libsysutils\\src\\FrameworkListener.cpp
根据代码我们可以得出启动FUSE file-system daemon 的命令为:/system/bin/sdcard -u 1023 -g 1023 -m -w ${mRawPath} ${label} 这里-u 参数指定uid 为1023 是media账号的uid, -g指定gid是media组的gid, -m表示支持多用户, -w表示全写模式, mRawPath就是外置存储的目标目录,比如/data/media 。 ${label} 用于区分fuse 目录,比如/dev/fuse 会挂载到/mnt/runtime/write/${label},用于 ${mRawPath} 的写访问路径。 知道这些我们就来看看sdcard的代码吧,它是FUSE file-system daemon 的实现。
android\\system\\core\\logd\\CommandListener.cpp
switch (hdr->opcode)
mode_t mode = 0660 | S_IFBLK;
无外置存储权限,默认只支持执行权限
mClients = new SocketClientCollection();
createPublicVolume(partDevice);
mConnectedSignal.countDown();if (mConnectedSignal.getCount() != 0) {return;}
case NetlinkEvent::Action::kAdd:
记录当前进程的pid
setgid(gid)
/注册监听用户添加、删除的广播
table = Table::kMbr;
flags |= android::vold::Disk::Flags::kUsb
if (event.isClassUnsolicited()) {mCallbacks.onCheckHoldWakeLock(event.getCode())}
createPublicVolume(mDevice);
将/data为路径的private volume添加到mVolumes
转NativeDaemonConnector.java中的excuteForList
ccl = new CryptCommandListener();
fuse->fd = open(\"/dev/fuse\
case FUSE_LOOKUP:
mAsecsScanned.countDown();
mMountService = new MountService(getContext());
4 fork新进程启动sdcard
MountService(Context context)
创建用于CryptdConnector工作的NDC对象
mBroadcaster = sl;
SocketListener::runListener()
addVolume(vol);
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY)
void watch_package_list(struct fuse_global* global)
这里一个至关重要的参数fuse->fd是通过打开/dev/fuse得到的,它的作用类似一个上下文,绑定该目录到这个文件描述后,以后fuse 内核驱动上来的文件操作请求都会写入fuse->fd, 只要读取fuse->fd就能获得fuse 内核驱动上来的文件操作请求
VolumeInfo vol = (VolumeInfo) msg.obj;
NativeDaemonConnector.java:class ResponseQueue
4挂载设备
VolumeBase::create()
7 启动三个线程用于处理三个fuse目录的文件操作请求
vol->mount();
public void startBootPhase(final int phase)
VolumeManager *vm = VolumeManager::Instance();
2 挂载设备
当系统启动到阶段550,并且已经与vold守护进程建立连接,则执行reset
while((de = readdir(d)))
if (vol.type == VolumeInfo.TYPE_EMULATED)
while (1)
6 创建obb共享文件夹
android\\system\\core\ootdir\\init.rc
EmulatedVolume.cpp
设置uevent的SO_RCVBUFFORCE选项
向vold进程发送asec list命令
cl->startListener()
关于代码,我们可以知道readPartitions函数通过读取mbr或者gpt分区表,还获取分区的信息,创建相应的卷。对于mbr分区,全都调用createPublicVolume函数来创建PublicVolume分区。对于gpt分区,要根据分区的typeGuid来创建Volume, 如果typeGuid为kGptBasicData表示这是一个基础数据分区,所以并非一个Android特有的卷,使用createPublicVolume来创建PublicVolume。 对于typeGuid为kGptAndroidExpand的卷则表示这个卷为一个Android扩展的卷,在其他系统上是无法处理的,这对应一个vold的PrivateVolume,使用createPrivateVolume函数来创建。
d2 = fdopendir(fd);
disk->create();
mConnector.executeForList(\"asec\
if (PrepareDir(mPath + \"/app\
if (type == \"public\
IoThread线程名为\"android.io\",创建OBB操作的handler
创建“MountService”线程
3 // 取消特权组,只保留AID_PACKAGE_INFO组
将新创建的CommandListener对象sl赋值给vm对象的成员变量mBroadcaster
android\\system\\vold\\VolumeManager.cpp
调用/system/bin/sgdisk --android-dump /dev/block/vold/${disk_id}读取分区信息
switch (major(mDevice))
SocketListener.cpp
Android存储系统-使用fuse来管理外置存储
startListener(4)
static int process_config(VolumeManager *vm)
final int sequenceNumber = mSequenceNumber.incrementAndGet();
通过ioctl函数获取磁盘的大小,保存到mSize变量中,然后根据设备vendor或者manfid 获取Disk的mLabel
sInstance = new NetlinkManager();
//获取分区设备号。
CommandListener::CommandListener() :FrameworkListener(\"vold\
????跳转到mountService哪里
Linux Kernel:通过uevent向Vold的NetlinkManager发送Uevent事件;NetlinkManager:接收来自Kernel的Uevent事件,再转发给VolumeManager;VolumeManager:接收来自NetlinkManager的事件,再转发给CommandListener进行处理;CommandListener:接收来自VolumeManager的事件,通过socket通信方式发送给MountService;MountService:接收来自CommandListener的事件
setInternalPath(mRawPath);
2 设置路径
卸载所有设备,以提供最干净的环境
for (i = optind; i < argc; i++)
std::string mediaPath(mPath + \"/media\");
1 监听 fuse driver 发上来的请求,写入handler->request_buffer
FUSE_INIT
bool NetlinkListener::onDataAvailable(SocketClient *cli)
multi_user = true;
通过文件path来查看其所在进程,并杀掉相应进程
if (table == Table::kMbr)
mHandler = new NetlinkHandler(mSock)
while (!pendingList.empty()) {it = pendingList.begin();SocketClient* c = *it;onDataAvailable(c)}
2准备fuse相关的文件夹
mCallbacks = new Callbacks(FgThread.get().getLooper());
if (cmd == \"reset\
创建SocketClient对象,并加入到mClients队列
nm = NetlinkManager::Instance()
case kMajorBlockMmc::.......
之前的mDiskSources就是用来匹配的
//告知所有已经存在和启动的users
vm->handleBlockEvent(evt)
CommandListener::ObbCmd::runCommand
const struct fuse_in_header *hdr = (void*)handler->request_buffer
case VoldResponseCode.VOLUME_CREATED:
挂载
最后如果没有找到分区类型或者没有找到分区,尝试将整个设备作为一个分区去创建PublicVolume
ForceUnmount(mFuseRead);
//将cmd写入到socket的输出流
收藏
收藏
0 条评论
下一页