Android5.0挂载子系统

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为只读问题




你可能感兴趣的:(Android5.0挂载子系统)