Android—— 4.2 Vold挂载管理_mmcblk内置-双sdcard (八)

Vold的学习过了一段时间了,才想着把mmcblock内置成sdcard的方法记录一下。

当初就是因为要做这个功能才去学习Vold机制,贴出之前的博客:

Android—— 4.2 Vold挂载管理_主体构建main (一)

Android—— 4.2 Vold挂载管理_CommandListener (二)

Android—— 4.2 Vold挂载管理_VolumeManager (三)

Android—— 4.2 Vold挂载管理_NetlinkManager (四)

Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)

Android—— 4.2 Vold挂载管理_MountService (六)

Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)

个人认为把上面的脉络理清了,Vold应该算是基本掌握了,其中的细节部分就需要另行研究了。

撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/39692953

一.准备:

不同平台的mmc分区方案和烧写emmc方式不一样,总之划分一块区域用来当sdcard挂载,并且记住block序号,android的分区类型在linux下制作一般都是ext4格式。

可在BoardCondif.mk中添加宏控制:

BOARD_MMCBLK_AS_SDCARD := 13
#jscese open mmcblk0p13 as sdcard to mount 140724#

并且在/system/vold/Android.mk 中添加编译选项:

ifneq ($(BOARD_MMCBLK_AS_SDCARD),)
  common_cflags := -DMMCBLK_AS_SDCARD=$(BOARD_MMCBLK_AS_SDCARD)
endif

LOCAL_CFLAGS := $(common_cflags)

二.Vold挂载:

在/system/vold/VolumeManager.cpp 中的 handleBlockEvent 中添加特殊处理。

核心添加如下:

    const char *devtype = evt->findParam("DEVTYPE");
    const char *dn = evt->findParam("DEVNAME");

    int major = -1;
    int minor = -1;

    bool isRawDisk = false;
    bool isPartition = false;

    int partIdx = -1;
    bool isSDCard = false;

    major = atoi(evt->findParam("MAJOR"));
    minor = atoi(evt->findParam("MINOR"));

 if (major == 179) {

        if (strncmp(dn,"mmcblk0",7) == 0) {//判断是否为mmc的block
#ifndef MMCBLK_AS_SDCARD
            return;
#endif
        }
       if (strcmp(dn,"mmcblk0p13") == 0)
        SLOGD("jscese display in vm - handle-isSDCard = true\n");
        isSDCard = true;
    }

    snprintf(device,255,"/dev/block/vold/%d:%d",major,minor);

  if (strcmp(devtype,"disk") == 0) { //根据设备类型就行判断
        const char *nparts = evt->findParam("NPARTS");
        if (nparts) {

            int diskNumParts = atoi(nparts);
            isRawDisk = (diskNumParts == 0);
        } else {
            return ;
        }
    } else {
        const char *tmp = evt->findParam("PARTN");
        if (tmp == NULL) {
            return;
        }

        partIdx = atoi(tmp);
//        if (strcmp(dn,"mmcblk0p14") == 0)
        SLOGD("jscese display in vm - handle- isPartition = true\n");
        isPartition = true;
    }

以上是对从kernel发过来的event信息进行一些筛选,下面就需要对device以及Volume进行特殊处理:

  if (isRawDisk || isPartition) {
        //first find uuid from cache
        UUIDCache::Entry *entry = uuidCache.searchEntry(device); /dev uuid缓存

        if (evt->getAction() == NetlinkEvent::NlActionAdd) {
            mode_t mode = 0660 | S_IFBLK;
            dev_t dev = (major << 8) | minor;

            //if device has been now added, not add again
            if (entry != NULL && entry->uuid != NULL) {
                return;
            }

            if (mknod(device, mode, dev) < 0) {//没有即创建节点
                if (errno != EEXIST) {
                    return ;
                }
            }
            if (!getVolumeUUID(device, uuid, 255)) {//获取uuid
        #ifdef NETLINK_DEBUG
                SLOGD("can not get the uuid of %s when device add",device);
        #endif

          return;

             }

      }

//Volume容器中添加处理,针对上面的uuid

        for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
            if (strcmp(uuid, (*it)->getLabel()) == 0) {

         (*it)->handleBlockEvent(evt);

          hit = true;

       if (evt->getAction() == NetlinkEvent::NlActionAdd) {
                    //if device was added at before, so cache its uuid and device path again
                    uuidCache.addEntry(device,uuid);
                    (*it)->setDevicePath(device);

                     }

         ...

       }

   }

 }

 if (!hit) {
        static char index = 'a'-1;
        char * mountPoint = NULL;
        const char *dp = NULL;
        DirectVolume * volume = NULL;

    #ifdef NETLINK_DEBUG

        SLOGW("No volumes handled block event for '%s'", devpath);
    #endif

        if (evt->getAction() != NetlinkEvent::NlActionAdd)
        {

          return;

         }

        dp = evt->findParam("DEVPATH");
        if (dp == NULL) {
            return;
        }

           SLOGD("jscese display in vm  for 1 mVolumes and isSDCard ==%d, isPartition+=%d \n",isSDCard,isPartition);
        /* Determine its mount point */
        if (isSDCard) {   //根据上面来的筛选
            if (isRawDisk) {
                asprintf(&mountPoint,"/mnt/sdcard_external");
            } else if (isPartition) {
#ifdef MMCBLK_AS_SDCARD
                if (partIdx == MMCBLK_AS_SDCARD) { //根据boardconfig中定义的block来设置挂载点
                    asprintf(&mountPoint,"/mnt/sdcard");
                    SLOGD("jscese display set mountpoint fuck mmcblock %d as sdcard\n",partIdx);
                }

#else
                if (partIdx == 1) { //外部的SD卡挂载点 改为 /mnt/sdcard_external
                    asprintf(&mountPoint,"/mnt/sdcard_external");
                } else {
                    asprintf(&mountPoint,"/mnt/usb/%s",dn);
                }
#endif
            }
        }

      volume = new DirectVolume(this,uuid,mountPoint,partIdx);
        //cache the device path of device
        volume->setDevicePath(device);
        free(mountPoint);

        mVolumesLock.lock();
        addVolume(volume);
        mVolumesLock.unlock();

        //cache the uuid of device
        uuidCache.addEntry(device, uuid);

        if ( volume->handleBlockEvent(evt) !=0 ) {
            SLOGD("New add volume fail to handle the event of %s",devpath);
        }

     }

UUID的cache接口如下:

static bool getVolumeUUID(const char* path, char* buf, int size) {
    blkid_cache cache = NULL;
    blkid_dev dev = NULL;
    blkid_tag_iterate iter = NULL;
    const char *type = NULL, *value = NULL;
    bool ret = false;

    if (path == NULL || buf == NULL || size < 0) {
        return false;
    }

    if (blkid_get_cache(&cache, NULL) < 0) {
        return false;
    }

    dev = blkid_get_dev(cache, path, BLKID_DEV_NORMAL);
    if (dev == NULL) {
        return false;
    }
    iter = blkid_tag_iterate_begin(dev);
    while (blkid_tag_next(iter, &type, &value) == 0) {
        if (strcmp(type,"UUID") == 0) {
            int n = strlen(value);
            if (n > size) {
                n = size;
            }
            ret = true;
            strncpy(buf,value,n);
            buf[n] = '\0';
        }
    }
    blkid_tag_iterate_end(iter);
    blkid_put_cache(cache);
    return ret;
}

class UUIDCache {
public:
    struct Entry {
        char *device;
        char *uuid;
    };

    UUIDCache() {
        uuidCache = new EntryCollection();
    }

    ~UUIDCache() {
        delete uuidCache;
    }

    void addEntry(const char *device, const char *uuid) {
        Entry *entry = NULL;
        if (device == NULL || uuid == NULL) {
            return;
        }

        entry = searchEntry(device);
        if (entry == NULL) {
            entry = new Entry();
            entry->device = strdup(device);
            uuidCache->push_back(entry);
        } else {
            if (entry->uuid != NULL) {
                free(entry->uuid);
            }
        }
        entry->uuid = strdup(uuid);
    }

    Entry *searchEntry(const char *device) {
        EntryCollection::iterator it;
        for (it = uuidCache->begin(); it != uuidCache->end(); ++it) {
            if ((*it)->device != NULL && strcmp((*it)->device, device) == 0) {
                return(*it);
            }
        }
        return NULL;
    }

private:
    typedef android::List<Entry *> EntryCollection;
    EntryCollection *uuidCache;
};

static UUIDCache uuidCache;

调入到DirectVolume中,不再做分析,前文有解析。

最后执行到挂载的Volume.cpp中的 mountVol 中。修改添加如下:

  if (primaryStorage) {
            // Special case the primary SD card.
            // For this we grant write access to the SDCARD_RW group.
            gid = AID_SDCARD_RW;
        } else {
            // For secondary external storage we keep things locked up.
            gid = AID_MEDIA_RW;
        }
        SLOGE("jscese display in Volume-mountVol devicepath==%s , gid ==%d \n",devicePath,gid);
        bool isFatFs = true;
        bool isNtfsFS = true;
        bool isExtFs = true;
        if(isFatFs) {
             SLOGE("jscese Fat::doMount \n");
        if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,
                    AID_SYSTEM, gid, 0002, true)) {
            SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
                isFatFs = false;
            } else {
                isNtfsFS = false;
                isExtFs = false;
            }
        }
/*===jscese add for format mmcblock ext4_type to vfat_type as sdcard 140805=====*/
#ifdef MMCBLK_AS_SDCARD
        if(!isFatFs)
        {
            char checkmmcblokPath[255];
//            sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]), MINOR(deviceNodes[i]));
            sprintf(checkmmcblokPath, "/dev/block/vold/%d:%d", SD_MAJOR,MMCBLK_AS_SDCARD);
            SLOGE("jscese Volume::mountvol format checkmmcblockpath= %s,  devicepath==%s , mountpoint==%s\n",checkmmcblokPath,devicePath,getMountpoint());
            if(!strcmp("/mnt/sdcard",getMountpoint()))
            {
                if(!strcmp(checkmmcblokPath,devicePath))
                {
                    setState(Volume::State_Idle);
                    SLOGE("jscese Volume::mountvol format 1 label== %s\n",getLabel());
                    if(formatVol()==0)
                    {
                        setState(Volume::State_Checking);
                        SLOGE("jscese Volume::mountvol format over \n");
                        if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,
                                        AID_SYSTEM, gid, 0002, true))
                        {
                            SLOGE("%s failed to mount via VFAT 2 (%s)\n", devicePath, strerror(errno));
                            isFatFs = false;
                        }
                        else
                        {
                            isFatFs=true;
                            isNtfsFS = false;
                            isExtFs = false;
                        }

                    }
                }
            }
        }
#endif
/*===============end================*/

首先进行FAT形式挂载,在系统第一次运行时,因为sdcard的block为ext4格式,肯定是会false返回,这个时候在代码中将其 formatVol 格式化,再进行FAT形式挂载!

因为我发现,如果以ext4形式挂载的/mnt/sdcard  这时分区中文件的创建权限只有创建者 才能有可读写权限,并不是根据/mnt/sdcard来规定权限。

此时各个应用进程在/mnt/sdcard创建的文件夹,其它用户就无权访问了,失去了sdcard应有的价值!

所以这里要先格式化成FAT,之后的分区中的创建权限全又挂载点也就是/mnt/sdcard来规定!

上层框架不用改动,这样就可以实现mmc的一个block内置成sdcard供应用程序使用,同时外部插入的sdcard将被挂载到/mnt/sdcard_external下。

时间: 2024-10-10 16:12:05

Android—— 4.2 Vold挂载管理_mmcblk内置-双sdcard (八)的相关文章

Android—— 4.2 Vold挂载管理_Kernel_USB_Uevent (七)

在前文Android-- 4.2 Vold挂载管理_NetlinkManager (四)中有解析到Vold 是从kernel中获取uevent事件,来获取device信息,其中是通过一个Netlink的套接字,目前整个Vold机制也分析完了, 上篇 Android-- 4.2 Vold挂载管理_MountService (六) 分析了机制中最上层的,这里分析一下最下层的kernel uevent事件的发送,以USB设备为例! 撰写不易,转载请注明出处:http://blog.csdn.net/j

Android—— 4.2 Vold挂载管理_NetlinkManager (四)

在前文Android-- 4.2 Vold挂载管理_主体构建main (一)中有结构图表示,Vold是kernel与用户层的一个交互管理模块, Android-- 4.2 Vold挂载管理_VolumeManager (三)简单介绍了核心VolumeManager的构建,这篇分析从kernel进程沟通到VolumeManager进程的关键:NetlinkManager 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/3858602

Android—— 4.2 Vold挂载管理_MountService (六)

整个Vold机制应该算system层,与framwork层的交互在Android-- 4.2 Vold挂载管理_CommandListener (二)中有提到过,是通过一个"vold"的socket进行通信的,这里分析一下framework中负责与Vold通信的:MountService 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38978387 一.MountService启动: 在/frameworks/bas

Android—— 4.2 Vold挂载管理_CommandListener (二)

在前一篇博客中介绍了个大体结构 Android-- 4.2 Vold挂载管理_主体构建 (一),按照代码的顺序结构来依次分析,这里来看看CommandListener这个类做了什么. 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38434263 一:CommandListener构造 在/system/vold/main.cpp的main函数中构建实例: cl = new CommandListener(); vm->setB

Android—— 4.2 Vold挂载管理_VolumeManager (三)

在Android-- 4.2 Vold挂载管理_主体构建main (一)中分析了大体的框架,这里分析一下核心VolumeManager,再次补上结构框架图如下: 可以看到VolumeManager就是整个Android 磁盘挂载Vold机制的核心调度,上下连接的中转站! 我从Vold main代码的顺序结构来一次分析,上一篇Android-- 4.2 Vold挂载管理_CommandListener (二)  中分析了与framework层交互的CommandListener的功能作用. 这里分

Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)

在前文Android-- 4.2 Vold挂载管理_VolumeManager (三) 中解析了VolumeManager是怎么样抽取Volume实例以及DirectVolume与Volume之间的关系,在上篇Android-- 4.2 Vold挂载管理_NetlinkManager (四)中从kernel开始调用到handleBlockEvent,这里解析一下Vold挂载的真正操作,也就是Volume的操作! 撰写不易,转载请注明出处:http://blog.csdn.net/jscese/a

android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人

要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上找对应ContentProvider的源码:https://github.com/android 有好多个,哪一个才是短信数据的ContentProvider呢? 在filters输入框:输入telephony. 现在只有一个了,打开: 装有git的话,可以选择clone到本地,没有的话,就选择下载

Android学习(十) SQLite 基于内置函数的操作方式

main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:or

Android学习笔记之使用意图打开内置应用程序组件

(1)布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" androi