logcat -s Vold MountService DirectVolume
虚拟SD卡相关:
Android虚拟SD卡
一、启动过程分析
1.应用程序API
frameworks/base/core/java/android/os/storage/StorageManager.java
2.MountService
frameworks/base/services/core/java/com/android/server/MountService.java
frameworks/base/services/core/java/com/android/server/storage/
public MountService(Context context) { mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25, null); //vold的socket,与CommandListener通信 }3.vold进程
system/vold/main.cpp
int main() { VolumeManager *vm; //管理挂载 CommandListener *cl; //与Android的MountService通信 NetlinkManager *nm; //与Linux的Kernel通信 cl = new CommandListener(); vm->setBroadcaster((SocketListener *) cl); //VolumeManager可以与MountService通信 nm->setBroadcaster((SocketListener *) cl); //NetlinkManager可以与MountService通信 }二、U盘挂载分析
1.vold进程获取内核U盘接入事件
system/core/libsysutils/src/SocketListener.cpp
void SocketListener::runListener() { if (!onDataAvailable(c)) { release(c, false); } } /* system/core/include/sysutils/NetlinkListener.h class NetlinkListener : public SocketListener { } */
system/core/libsysutils/src/NetlinkListener.cpp
bool NetlinkListener::onDataAvailable(SocketClient *cli) { int socket = cli->getSocket(); NetlinkEvent *evt = new NetlinkEvent(); if (evt->decode(mBuffer, count, mFormat)) { onEvent(evt); } 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"); } } /* system/vold/NetlinkHandler.h class NetlinkHandler: public NetlinkListener { } */
system/vold/NetlinkHandler.cpp
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")) { vm->handleBlockEvent(evt); }else if(!strcmp(subsys, "usb")) { vm->handleHidEvent(evt); } }
system/vold/VolumeManager.cpp
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { for (it = mVolumes->begin(); it != mVolumes->end(); ++it) { (*it)->handleBlockEvent(evt); } volume = new DirectVolume(this, &rec, flags); addVolume(volume); if ( volume->handleBlockEvent(evt) !=0 ) { SLOGD("New add volume fail to handle the event of %s",devpath); } }
2.向Android的MountServer发送U盘接入消息
system/vold/DirectVolume.cpp
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { handleDiskAdded(dp, evt); } void DirectVolume::handleDiskAdded(const char * /*devpath*/, NetlinkEvent *evt) { mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); } /* system/vold/DirectVolume.h class DirectVolume : public Volume { VolumeManager *mVm; } */
system/vold/VolumeManager.h
class VolumeManager { void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; } /* system/vold/main.cpp int main() { VolumeManager *vm; CommandListener *cl; NetlinkManager *nm; cl = new CommandListener(); vm->setBroadcaster((SocketListener *) cl); nm->setBroadcaster((SocketListener *) cl); } */ SocketListener *getBroadcaster() { return mBroadcaster; } }
system/vold/CommandListener.h
class CommandListener : public FrameworkListener { } /* system/core/include/sysutils/FrameworkListener.h class FrameworkListener : public SocketListener { } */
system/core/libsysutils/src/SocketListener.cpp
void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) { if (c->sendMsg(code, msg, addErrno, false)) { SLOGW("Error sending broadcast (%s)", strerror(errno)); } }
3.Android的MountServer接收到VolumeDiskInserted消息后处理
frameworks/base/services/core/java/com/android/server/MountService.java
public boolean onEvent(int code, String raw, String[] cooked) { if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } private int doMountVolume(String path) { mConnector.execute("volume", "mount", path); /* mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25, null); */ }
frameworks/base/services/core/java/com/android/server/NativeDaemonConnector.java
public NativeDaemonEvent execute(String cmd, Object... args) throws NativeDaemonConnectorException { final NativeDaemonEvent[] events = executeForList(cmd, args); } public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { return execute(DEFAULT_TIMEOUT, cmd, args); } public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { NativeDaemonEvent event = null; events.add(event); } public void add(int cmdNum, NativeDaemonEvent response) { found = new PendingCmd(cmdNum, null); mPendingCmds.add(found); }
4.vold进程接收Android的MountServer进程的volume的mount命令
system/core/libsysutils/src/SocketListener.cpp
void SocketListener::runListener() { if (!onDataAvailable(c)) { release(c, false); } }
system/core/libsysutils/src/FrameworkListener.cpp
bool FrameworkListener::onDataAvailable(SocketClient *c) { dispatchCommand(c, buffer + offset); } void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) { for (i = mCommands->begin(); i != mCommands->end(); ++i) { FrameworkCommand *c = *i; /* void FrameworkListener::registerCmd(FrameworkCommand *cmd) { mCommands->push_back(cmd); } system/core/include/sysutils/FrameworkListener.h class FrameworkListener : public SocketListener { } system/vold/CommandListener.h class CommandListener : public FrameworkListener { } system/vold/CommandListener.cpp CommandListener::CommandListener() : FrameworkListener("vold", true) { registerCmd(new DumpCmd()); registerCmd(new VolumeCmd()); //volume的mount命令 registerCmd(new AsecCmd()); registerCmd(new ObbCmd()); } */ if (c->runCommand(cli, argc, argv)) { SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno)); } } }
system/vold/CommandListener.cpp
int CommandListener::VolumeCmd::runCommand(SocketClient *cli, int argc, char **argv) { VolumeManager *vm = VolumeManager::Instance(); else if (!strcmp(argv[1], "mount")) { rc = vm->mountVolume(argv[2]); } }
system/vold/VolumeManager.cpp
int VolumeManager::mountVolume(const char *label) { Volume *v = lookupVolume(label); return v->mountVol(); }
/system/vold/Volume.cpp
int Volume::mountVol() { if (isNtfsFS) { if (Ntfs::doMount(devicePath, getMountpoint(), false, false, AID_MEDIA_RW, AID_MEDIA_RW, permMask)) { //实际调用Linux系统调用挂载 SLOGE("%s failed to mount via NTFS (%s)\n", devicePath, strerror(errno)); isNtfsFS = false; } else { isFatFs = false; isExtFs = false; isExfatFs = false; } } setState(Volume::State_Mounted); } void Volume::setState(int state) { mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange, msg, false); //同之前消息发送,不做分析;MountServer会收到VolumeStateChange消息 }
5.Android的MountServer收到VolumeStateChange消息通知应用
frameworks/base/services/core/java/com/android/server/MountService.java
public boolean onEvent(int code, String raw, String[] cooked) { if (code == VoldResponseCode.VolumeStateChange) { notifyVolumeStateChange( cooked[2], cooked[3], Integer.parseInt(cooked[7]), Integer.parseInt(cooked[10])); } } private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { else if (newState == VolumeState.Mounted) { if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); //广播通知应用挂载完毕 action = Intent.ACTION_MEDIA_MOUNTED; } if (action != null) { sendStorageIntent(action, volume, UserHandle.ALL); } }
三、项目问题
Android下开机启动后U盘经常不能自动挂载
Android媒体应用下不能将两个U盘间文件复制
Android5.0挂载NTFS为只读问题