Android External Storage support: Volume Daemon (VOLD)| part 1/2

When we insert any SD card or USB storage, the android system automatically mounts them for us. Vold(Volume Daemon), which is a native service is responsible for detecting, mounting, and unmounting of all the external and extended storage in our Android devices. Like SD card, USB, or CD ROM, etc.

In this article, we will discuss the Vold and its various sub components. We will also discuss, how fstab plays a role in mounting the sdcard or any other physical storage in android.

The vold process receives external storage device connection and disconnection message from the kernel to manage and control the external storage devices on the Android platform. Vold controls SD card mounting, unmounting, encrypting. and formatting.

Whenever there is a change in the external device, either connection or disconnection, the Kernel sends a message(uEvent) via Netlink to vold. For a userspace, program Netlink is a special socket-based communication mechanism which is asynchronous and used for bidirectional data transfer between the kernel and the user application.

Basic workflow diagram of android vold

The above figure shows the basic work flow model of how vold works and how its sub-components are involved in the process of mounting. 

What is Vold in Android?

Vold is a native process that acts as a control center for managing and controlling the external storage in the Android platform. It runs in the background and interacts with the JAVA layer i.e StorageManagerService. It receives uEvent messages from the kernel, processes it and then send it to upper layer.

Components of Vold in Android

Vold is composed of many components, some of them are:

  • VolumeManager
  • NetlinkManager
  • NetlinkHandler
  • NetlinkEvent
  • VolumeNativeService
  • VolumeBase
    1. PrivateVolume
    2. PublicVolume
  • fstab file
  • etc. . .

Let's see how vold works in Android platform in brief

Vold has broadly three modules which helps it in managing and controlling external storage. Those modules are NetlinkManager module, VolumeManager module and VolumeNativeService.

The NetlinkManager module specifically receives the uEvent message from the kernel and forwards the message to the VolumeManager.

The VolumeManager module processes this uEvent and sends the related information to the StorageManagerService with the help of VolumeNativeService.

The VolumeNativeService uses the IVoldListerner.aidl to communicate with the StorageManagerService. Previously this communication from vold to MountService(StorageManagerService was previously called) was done with the help of CommandListener. It was a module, internally encapsulates a Socket for cross-process communication. 

The StorageManagerService receives the information from the VolumeManager, processes it, and again send it to the VolumeManager though IVold.aidl

It will make more sense if we just go through the code and start with how uEvent and vold starts.

Code Analysis

Starting of uEvent and Vold daemon

During early-init uevent is started and on post-fs-data vold is started. This is all specified in init.rc file.

starting of uEvent
starting of vold

We can find the vold executable service inside /system/bin.

starting of vold service in android

The vold is implemented inside /syste/vold, and the entry point is /system/vold/main.cpp

android vold main.cpp part 1
android vold main.cpp part 2

Now, we’ll see the important steps at the vold start up.

1. Setting up the selinux for file context handle.

    sehandle = selinux_android_file_context_handle();
    if (sehandle) {
        selinux_android_set_sehandle(sehandle);
    } 

2. Creating the vold device folder

  mkdir("/dev/block/vold", 0755);

3. Initializing the VolumeManager and NetlinkManager.

 /* Create our singleton managers */
    if (!(vm = VolumeManager::Instance())) {
        LOG(ERROR) << "Unable to create VolumeManager";
        exit(1);
    }

    if (!(nm = NetlinkManager::Instance())) {
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    }

Note that these classes are initialized as a Singleton class. So only one object of it will be created.

4. Starting of those classes and VolumeNativeService.

   if (vm->start()) {
        PLOG(ERROR) << "Unable to start VolumeManager";
        exit(1);
    }
ATRACE_BEGIN("VoldNativeService::start"); if (android::vold::VoldNativeService::start() != android::OK) { LOG(ERROR) << "Unable to start VoldNativeService"; exit(1); } ATRACE_END(); LOG(DEBUG) << "VoldNativeService::start() completed OK"; ATRACE_BEGIN("NetlinkManager::start"); if (nm->start()) { PLOG(ERROR) << "Unable to start NetlinkManager"; exit(1); }

If you have noticed the main.cpp, there is a method called

process_config(vm, &has_adoptable, &has_quota, &has_reserved)

This method reads the fstab file and add a disk source to the VolumeManager

Now we will see how this trio, VolumeManager, NelinkManager, and VoldNativeService communicates. We will see things in order to understand better. We will start with NetlinkManager.

NetlinkManager

Netlink manager receives the uEvent from the Kernel and resolves it into a NetlinkEvent. This NetlinkEvent is then passed to VolumeManager for further processing.

As you can see from the above code snippet, when NetlinkManager is started, it creates a socket and binds to that socket for receiving uEvents. Once this binding to the socket is done, NetlinkManager instantiates a NetlinkHandler object and starts it. The starting of the NetlinkHandler starts the socket listener to receive the kernel message(uEvent).

int NetlinkHandler::start() {
return this->startListener();
}

Upon receiving the uEvents from the SocketListener, NetlinkHandler checks whether these uEvents  are for block devices or not. If yes, then it will ask VolumeManager to handle these events.

VolumeManager

The VolumeManager processes these kernel messages(uEvents) and send it to upper layer i.e StorageManagerService through VoldNativeService. Let’s walkthrough the code and see what happens when VolumeManager is started.

int VolumeManager::start() {
ATRACE_NAME("VolumeManager::start");

// Always start from a clean slate by unmounting everything in
// directories that we own, in case we crashed.
unmountAll();

Devmapper::destroyAll();
Loop::destroyAll();

// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
CHECK(mInternalEmulated == nullptr);
mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
new android::vold::EmulatedVolume("/data/media"));
mInternalEmulated->create();

// Consider creating a virtual disk
updateVirtualDisk();

return 0;
}

As you can see from the code snippet, when VolumeManager starts, it will first unmount everything and then creates the emulated volume on internal storage.

uEvent Processing

We saw above, that Netlink module will call the onEvent method and pass the NetlinkEvent to VolumeManager for further processing. Lets see these things from code.

volumeManager::handleBlockEvent

Inside handleBlockEvent method, it tries to find the eventPath and devType from that Kernel message i.e NetlinkEvent. and only processes if the devType is disk.

Find the major and minor number and make the device out of it.

Remember, in main.cpp, processConfig() method reads the fstab file and stores all the disk sources in VolumeManager. In the above code when the action is add, every sources in the mDiskSources is matched to the eventPath.

 for (const auto& source : mDiskSources) {
     if (source->matches(eventPath)) {

Here source is the mount path that is read from the fstab file and eventPath is what Android is expecting. If both the path matches then the Disk will be created.

Depending on the type of events VolumeManager will add or remove these disks. Disk class is responsible for creating and managing the disk connection.

void VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {
    // For security reasons, if secure keyguard is showing, wait
    // until the user unlocks the device to actually touch it
    if (mSecureKeyguardShowing) {
        LOG(INFO) << "Found disk at " << disk->getEventPath()
          << " but delaying scan due to secure keyguard";
        mPendingDisks.push_back(disk);
    } else {
        disk->create();
        mDisks.push_back(disk);
    }
}

Disk.cpp

Lets see what Disk::create() method does.

disk create

Disk.cpp uses the AIDL (IVoldListener.aidl) to communicate to StorageManagerService. The Disk::create() method calls onDiskCreated() on listener object. This listener is nothing but the IVoldListener.

StorageManagerService set this listener from its connect().

storagemanagerservice lifecycle onstart

When StorageManagerService is started, its lifecycle method onStart() method will be called.

The Lifecycle#onStart() method will call StorageManagerService.onStart() which will eventually call connect() method.

private void connect() {
. . .
if (binder != null) {
mVold = IVold.Stub.asInterface(binder);
try {
mVold.setListener(mListener);
} catch (RemoteException e) {
mVold = null;
Slog.w(TAG, "vold listener rejected; trying again", e);
}
} else {
Slog.w(TAG, "vold not found; trying again");
}
}
voldnativeservice setListener

Okay now, coming back to our Disk creation part. First onDiskCreate() method will be called. Then metadata of the disk is extracted and onDiskMetadataChanged() is called. 

status_t Disk::readMetadata() {
mSize = -1;
mLabel.clear();
. . .

auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskMetadataChanged(getId(),
mSize, mLabel, mSysPath);
return OK;
}

After reading the metadata, partition of the disk is read.

read partition

For reading the partition of the disk, it first destroys all the volume then parse the partition table using SGDisk Executable. After that it creates a public volume or a private volume for the external storage and calls onDiskScanned() method.

android vold creating public volume

Thats all about the first part, we will see more things in details like, how public or private volume is created and mounted. 

Swetabh

Swetabh is an Android Developer and a Tech enthusiast. His enthusiasm drives him to know about various technologies. Now he wanted to share his knowledge to other enthusiast who are passionate to know-how and become a GIZMOMIND.

This Post Has One Comment

  1. Girish

    Hi Swetabh…nicely explained ..good job..it helped me…Thanks.

Leave a Reply