• 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 '' 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。
  • 相关阅读:
    poj 2021
    树状数组的修改+查询
    poj 1182
    windows网络模型之重叠IO(完成例程)的使用
    windows网络模型之重叠IO的使用
    python解析HTML之:PyQuery库的介绍与使用
    windows 网络通讯模型Overlapped (转)(未看)
    (转)写的非常好的一篇HTTP协议详解
    (转)Wireshark基本介绍和学习TCP三次握手
    http中COOKIE和SESSION有什么区别?(转知乎)
  • 原文地址:https://www.cnblogs.com/blackeyes/p/7692806.html
Copyright © 2020-2023  润新知