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)endifLOCAL_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下。





更多相关文章

  1. [置顶] Android中以JAR形式封装控件或者类库
  2. Android修改system只读权限:remount
  3. Android 无须获取Root权限静默安装App
  4. Android应用商店——Splash页面的实现,Android运行时权限的使用
  5. Android权限管理之Permission权限机制及使用
  6. Android兼容性问题 -- WebP格式图片解码失败
  7. RK3326 Android 8.1 为自己的APK的服务默认开启无障碍权限,避免使
  8. Android初学习 - android:sharedUserId="android.uid.system" 应

随机推荐

  1. 我的Android进阶之旅------>Ubuntu下不能
  2. android安装包apk文件反编译代码
  3. Android -- android activity 各种布局方
  4. Android(安卓)demo--调用系统相机拍照并
  5. Android 音频管理器AudioManager类介绍
  6. android中的Handler(2)
  7. Android中如何解决editText一进入activit
  8. 易用的Android音视频高性能编码库Hardwar
  9. Android RadioGroup设置默认选中项
  10. 关于android中Email未设置账户的情况下发