<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                Vold使用VM模塊的流程是: - 調用Instance創建一個VM對象。 - 調用setBroadcaster設置CL對象,這個函數和NM的setBroadcaster一樣,所以本節不再介紹它。 - 調用start啟動VM。 - 調用process_config配置VM。 現在來看除setBroadcaster之外的三個函數。 1. 創建VM和start的分析 VM的創建及start函數都非常簡單,代碼如下所示。 **VolumeManager.cpp** ~~~ VolumeManager *VolumeManager::Instance() { if(!sInstance) sInstance = new VolumeManager(); returnsInstance; } ~~~ 可以看到,VM也采用了單例的模式,所以全進程只會存在一個VM對象。 下面看VM的start: **VolumeManager.cpp** ~~~ int VolumeManager::start() { return 0; } ~~~ start很簡單,沒有任何操作。 2. process_config的分析 process_config函數會根據配置文件配置VM對象,其代碼如下所示: **Main.cpp** ~~~ static int process_config(VolumeManager *vm) { FILE*fp; int n= 0; charline[255]; //讀取/etc/vold.fstab文件 if(!(fp = fopen("/etc/vold.fstab", "r"))) { return -1; } while(fgets(line, sizeof(line), fp)) { char *next = line; char *type, *label, *mount_point; n++; line[strlen(line)-1] = '\0'; if(line[0] == '#' || line[0] == '\0') continue; if(!(type = strsep(&next, " \t"))) { goto out_syntax; } if(!(label = strsep(&next, " \t"))) { goto out_syntax; } if(!(mount_point = strsep(&next, " \t"))) { goto out_syntax; } if(!strcmp(type, "dev_mount")) { DirectVolume *dv = NULL; char *part, *sysfs_path; if (!(part = strsep(&next, " \t"))) { ...... goto out_syntax; } if (strcmp(part, "auto") && atoi(part) == 0) { goto out_syntax; } if (!strcmp(part, "auto")) { //①構造一個DirectVolume對象 dv = new DirectVolume(vm, label, mount_point, -1); } else { dv = new DirectVolume(vm, label, mount_point, atoi(part)); } while((sysfs_path = strsep(&next, " \t"))) { //②添加設備路徑 if (dv->addPath(sysfs_path)) { ...... goto out_fail; } } //為VolumeManager對象增加一個DirectVolume對象 vm->addVolume(dv); } ...... } ...... return-1; } ~~~ 從上面代碼中發現,process_config的主要功能就是解析/etc/vold.fstab。這個文件的作用和Linux系統中的fstab文件很類似,就是設置一些存儲設備的掛載點,我的HTC G7手機上這個文件的內容如圖9-3所示: :-: ![](http://img.blog.csdn.net/20150802164336050?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖9-3 我的手機上vold.fstab內容 從上圖的紅框中可知: - sdcard為volume的名字。 - /mnt/sdcard表示mount的位置。 - 1表示使用存儲卡上的第一個分區,auto表示沒有分區。現在有很多定制的ROM要求SD卡上存在多個分區。 - /devices/xxxx等內容表示MMC設備在sysfs中的位置。 根據G7的vold.fstab文件,可以構造一個DirectVolume對象。 注意,根據手機刷的ROM的不同,vold.fstab文件會有較大差異。 3. DirectVolume的分析 DirectVolume從Volume類派生,可把它看成是一個外部存儲卡(例如一張SD卡)在代碼中的代表物。它封裝了對外部存儲卡的操作,例如加載/卸載存儲卡、格式化存儲卡等。 下面是process_config函數中和DirectVolume相關的地方: - 一個是創建DirectVolume。 - 另一個是調用DirectVolume的addpath函數。 它們的代碼如下所示: **DirectVolume.cpp** ~~~ DirectVolume::DirectVolume(VolumeManager *vm,const char *label, const char*mount_point, int partIdx) : Volume(vm, label, mount_point) {//初始化基類 /* 注意其中的參數: label為”sdcard”,mount_point為”/mnt/sdcard”,partIdx為1 */ mPartIdx = partIdx; //PathCollection定義為typedef android::List<char *> PathCollection //其實就是一個字符串list mPaths= new PathCollection(); for(int i = 0; i < MAX_PARTITIONS; i++) mPartMinors[i] = -1; mPendingPartMap = 0; mDiskMajor = -1; //存儲設備的主設備號 mDiskMinor = -1; //存儲設備的次設備號,一個存儲設備將由主次兩個設備號標識。 mDiskNumParts = 0; //設置狀態為NoMedia setState(Volume::State_NoMedia); } //再來看addPath函數,它主要目的是添加設備在sysfs中的路徑,G7的vold.fstab上有兩個路 //徑,見圖9-3中的最后一行。 int DirectVolume::addPath(const char *path) { mPaths->push_back(strdup(path)); return0; } ~~~ 這里簡單介紹一下addPath的作用。addPath把和某個存儲卡接口相關的設備路徑與這個DirectVolume綁定到一起,并且這個設備路徑和Uevent中的DEVPATH是對應的,這樣就可以根據Uevent的DEVPATH找到是哪個存儲卡的DirectVolume發生了變動。當然手機上目前只有一個存儲卡接口,所以Vold也只有一個DirectVolume。 4. NM和VM交互 在分析NM模塊的數據處理時發現,NM模塊接收到Uevent事件后,會調用VM模塊進行處理,下面來看這塊的內容。 先回顧一下NM調用VM模塊的地方,代碼如下所示: **NetlinkHandler.cpp** ~~~ void NetlinkHandler::onEvent(NetlinkEvent *evt){ VolumeManager *vm = VolumeManager::Instance(); constchar *subsys = evt->getSubsystem(); ...... if (!strcmp(subsys, "block")) { vm->handleBlockEvent(evt); //調用VM的handleBlockEvent } elseif (!strcmp(subsys, "switch")) { vm->handleSwitchEvent(evt);//調用VM的handleSwitchEvent } ...... } ~~~ 在上面代碼中,如果Uevent是block子系統,則調用handleBlockEvent;如果是switch,則調用handleSwitchEvent。handleSwitchEvent主要處理SD卡掛載磁盤的通知,比較簡單。這里只分析handleBlockEvent事件。 **VolumeManager.cpp** ~~~ void VolumeManager::handleBlockEvent(NetlinkEvent*evt) { constchar *devpath = evt->findParam("DEVPATH"); /* 前面在process_config中構造的DirectVolume對象保存在了mVolumes中,它的定義如下: typedef android::List<Volume *>VolumeCollection,也是一個列表。 注意它保存的是Volume指針,而我們的DirectVolume是從Volume派生的 */ VolumeCollection::iterator it; boolhit = false; for (it = mVolumes->begin(); it !=mVolumes->end(); ++it) { //調用每個Volume的handleBlockEvent事件,就我的G7手機而言,實際上將調用 //DirectVolume的handleBlockEvent函數。 if(!(*it)->handleBlockEvent(evt)) { hit = true; break; } } } ~~~ NM收到Uevent消息后,DirectVolume也將應聲而動,它的handleBlockEvent的處理是: **DirectVolume.cpp** ~~~ int DirectVolume::handleBlockEvent(NetlinkEvent*evt) { constchar *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; //將Uevent的DEVPATH和addPath添加的路徑進行對比,判斷屬不屬于自己管理的范圍。 for(it = mPaths->begin(); it != mPaths->end(); ++it) { if(!strncmp(dp, *it, strlen(*it))) { int action = evt->getAction(); const char *devtype = evt->findParam("DEVTYPE"); if (action == NetlinkEvent::NlActionAdd) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char nodepath[255]; snprintf(nodepath, sizeof(nodepath),"/dev/block/vold/%d:%d", major, minor); //創建設備節點 if (createDeviceNode(nodepath, major, minor)) { ...... } if (!strcmp(devtype, "disk")) { handleDiskAdded(dp, evt);//添加一個磁盤 } else { /* 對于有分區的SD卡,先收到上面的“disk”消息,然后每個分區就會收到 一個分區添加消息。 */ handlePartitionAdded(dp,evt); } } else if (action == NetlinkEvent::NlActionRemove) { ...... } else if (action == NetlinkEvent::NlActionChange) { ...... } ...... return 0; } } errno= ENODEV; return-1; } ~~~ 關于DirectVolume針對不同Uevent的具體處理方式,后面將通過一個SD卡插入案例來分析。 5. VM模塊的總結 從前面的代碼分析中可知,VM模塊的主要功能是管理Android系統中的外部存儲設備。圖9-4描述了VM模塊的功能: :-: ![](http://img.blog.csdn.net/20150802164353303?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖9-4 VM模塊的職責 通過對上圖和前面代碼的分析可知: - SD卡的變動(例如熱插拔)將導致Kernel發送Uevent消息給NM模塊。 - NM模塊調用VM模塊處理這些Uevent消息。 - VM模塊遍歷它所持有的Volume對象,Volume對象根據addPath添加的DEVPATH和Uevent消息中的DEVPATH來判斷,自己是否可以處理這個消息。 至于Volume到底如何處理Uevent消息,將通過一個實例來分析。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看