kernel cmdline 轉換 properity過程


        之前遇到一個有關“androidboot.slot_suffix”的問題,發現該kernel cmdline作為后綴會被用來拼接位於fastab中的分區名(如vendor、oem分區等)。如果該cmdline的值傳遞不正確會使fstab中的分區掛載點出錯,導致無法正確掛載分區。通過閱讀源碼定位到更新fstab中分區后綴的代碼位於/ system/ core/ fs_mgr/ fs_mgr_boot_config.cpp中,其代碼實現為:
40 // Updates |fstab| for slot_suffix. Returns true on success, false on error.
41 bool fs_mgr_update_for_slotselect(struct fstab *fstab) {
42     int n;
43     std::string ab_suffix;
44
45     for (n = 0; n < fstab->num_entries; n++) {
46         if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
47             char *tmp;
48             if (ab_suffix.empty()) {
49                 ab_suffix = fs_mgr_get_slot_suffix();
50                 // Returns false as non A/B devices should not have MF_SLOTSELECT.
51                 if (ab_suffix.empty()) return false;
52             }
53             if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
54                 free(fstab->recs[n].blk_device);
55                 fstab->recs[n].blk_device = tmp;
56             } else {
57                 return false;
58             }
59         }
60     }
61     return true;
        上述代碼首先通過fatab中的參數判斷分區是否需要進行分區選擇,之后通過 fs_mgr_get_slot_suffix()獲取當前所啟動的slot后綴並完成拼接。 fs_mgr_get_slot_suffix()中主要調用了 fs_mgr_get_boot_config()來完成分區后綴的獲取功能,其中 fs_mgr_get_boot_config()的代碼實現為:
24 // Tries to get the boot config value in properties, kernel cmdline and
25 // device tree (in that order).  returns 'true' if successfully found, 'false'
26 // otherwise
27 bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
28     FS_MGR_CHECK(out_val != nullptr);
29
30     // first check if we have "ro.boot" property already
31     *out_val = android::base::GetProperty("ro.boot." + key, "");
32     if (!out_val->empty()) {
33         return true;
34  
35     }
36
37     // fallback to kernel cmdline, properties may not be ready yet
38     std::string cmdline;
39     std::string cmdline_key("androidboot." + key);
40     if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
41         for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
42             std::vector<std::string> pieces = android::base::Split(entry, "=");
43             if (pieces.size() == 2) {
44                 if (pieces[0] == cmdline_key) {
45                     *out_val = pieces[1];
46                     return true;
47                 }
48             }
49         }
50     }
51
52     // lastly, check the device tree
53     if (is_dt_compatible()) {
54         std::string file_name = kAndroidDtDir + "/" + key;
55         // DT entries terminate with '\0' but so do the properties
56         if (android::base::ReadFileToString(file_name, out_val)) {
57             return true;
58         }
59
60         LINFO << "Error finding '" << key << "' in device tree";
61     }
62
63     return false;
        獲取分區后綴的先后次序為:property > kernel cmdline > dt。通過測試發現系統一般是獲取ro.slot_suffix這個property值,並且ro.slot_suffix這個property也是通過androidboot.slot_suffix所轉換得到的。繼續閱讀源碼,定位到在init進程中有一處調用 process_kernel_cmdline(),繼續追蹤發現其內部調用了 import_kernel_cmdline()並傳入了 import_kernel_nv()回調函數。其中 import_kernel_cmdline()的實現為:
275 void import_kernel_cmdline(bool in_qemu,
276                            const std::function<void(const std::string&, const std::string&, bool)>& fn) {
277     std::string cmdline;
278     android::base::ReadFileToString("/proc/cmdline", &cmdline);
279
280     for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
281         std::vector<std::string> pieces = android::base::Split(entry, "=");
282         if (pieces.size() == 2) {
283             fn(pieces[0], pieces[1], in_qemu);
284         }
285     }
286 }
        上述代碼的功能是將傳入的cmdline進行分割,並將其傳入 import_kernel_nv()中進行轉換。 import_kernel_nv()的代碼實現為:
440 static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
441     if (key.empty()) return;                                                                       
442                                                                                                    
443     if (for_emulator) {                                                                            
444         // In the emulator, export any kernel option with the "ro.kernel." prefix.                 
445         property_set(StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());            
446         return;                                                                                    
447     }                                                                                              
448                                                                                                    
449     if (key == "qemu") {                                                                           
450         strlcpy(qemu, value.c_str(), sizeof(qemu));                                                
451     } else if (android::base::StartsWith(key, "androidboot.")) {                                   
452         property_set(StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(), value.c_str());         
453     }                                                                                              
454 } 
       import_kernel_nv()的功能就是將kernel cmdline中的“androidboot.*”參數轉化為"ro.boot.*"property。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM