[SA8155] 探索QNX Hypervisor怎样管理Android体系的AB分区(一)

[复制链接]
发表于 2026-2-18 16:40:50 | 显示全部楼层 |阅读模式
本文发起在对高通8155车机体系有肯定的相识下举行阅读
    文章目次
  前言
  一、VMM中的关键LOG
  二、VMM中的关键CODES
  1.VMM状态机管理
  2.QNX的slot状态
  3.Android的slot状态
  总结
  参考
  
  
  前言

  高通SA8155的基建默认接纳的是A/B体系升级作为OTA升级方案。
而在假造化体系中,怎样包管Host QNX和Guest Android两个差别体系的AB分区同等是个值得探究的题目。
本文探索了,Host QNX中的资源管理模块VMM(Virtual Machine Manager)在启动Android假造机的时间是怎样获取Android体系的AB分区信息。

一、VMM中的关键LOG

关于高通的假造机资源管理器VMM见文末参考,这里以该模块打印的log作为引子。
在启动Android假造机的log中,一行来自vmm_service的关键log提示了Host QNX和Guest Android的slot状态(A/B升级体系中用slots表现ab分区聚集状态,参考Android OTA A/B system update):
   Jan 01 00:00:07.830        vmm.868420        default  16130  vmm_service[vmm_fsm.c:762]:
  guest target slot : a host current slot: b Config slot/mnt/vm/images/la_dp_enabled_a.config
  根据这行log中,我们可以获取以下信息:


  • 打印来自VMM模块的vmm_fsm.c文件
  • guest指的是Android体系,目标slot为a
  • host指的是QNX体系,当前slot为b
  • guest slot设置文件名为/mnt/vm/images/la_dp_enabled_a.config
从中可以推测出以下信息:


  • QNX和Android可以处于差别的AB分区状态下运行
  • 根据设置文件名,可以推断此设置的两个使用条件:

    • 动态分区被使能
    • slot为a的分区设置被接纳

二、VMM中的关键CODES

通过以上分析可以发现,在Android假造机启动的过程中,VMM模块加入了安卓AB分区的管理。
让我们进一步举行探索:
1.VMM状态机管理

由获取的信息定位到这行关键的log在vmm_fsm.c文件的位置:
  1. static int launch_gvm(struct gvm_context *ctx)
  2. {
  3.     ...
  4.     if (ctx->vm_avb_version == 2) {
  5.         pthread_barrier_wait(&ctx->config_barrier);
  6.         if (!ctx->bank || ctx->slot_switch_config == SYMMETRIC_SLOT_SWITCH) {
  7.             ctx->bank = ctx->swdl_slot;
  8.         }
  9.         ...
  10.         /* Dynamic Parition is Enabled only for LA GVM */
  11.         if (ctx->vmid == 2) {
  12.             if (ctx->qvb.is_dp_enabled == true) {
  13.                 _argv[3] = (ctx->bank == 'a')? ctx->qvb.dp_enabled_a_conf_fname: ctx->qvb.dp_enabled_b_conf_fname;
  14.                 vmm_info("guest target slot : %c host current slot: %c Config slot :%s ",ctx->bank, ctx->swdl_slot, _argv[3]);
  15.                 ctx->swdl_slot = '\0';
  16.             } else {
  17.                 _argv[3] = ctx->qvb.dp_disabled_conf_fname;
  18.             }
  19.         }
  20.     } else if (ctx->vm_avb_version == 1 && ctx->is_recovery) {
  21.         ...
  22.     } else {
  23.         ...
  24.     }
  25.     ...
  26. }
复制代码
该log来自launch_gvm接口,从相干代码中,可以获取到以下信息:


  • 启动GVM的时间,VMM会根据Android体系的功能的使能状态,传入启动所需的差别设置
  • 动态分区功能是针对Android假造机特殊处置惩罚的
  • 动态分区在非使能的条件下,有对应的设置文件作为入参
  • 动态分区在使能的条件下,根据context中的bank值为a还是b,接纳对应的设置文件作为入参
  • 当bank为空的环境,让bank与swdl_slot状态同等
那么:


  • context中的成员变量swdl_slot应该代表Host QNX的slot状态,
  • context中的成员变量bank应该代表Guest Android的slot状态,
  • swdl_slot与bank分别从哪儿获取赋值的呢
还是在vmm_fsm.c文件中,可以搜索到相干代码。在加载启动镜像的时间,QNX和Android的slot状态被提取出来:
  1. void* vm_load_img(void *data)
  2. {
  3.     struct gvm_context *ctx = (struct gvm_context *)data;
  4.     ...
  5.     char bank = '\0';
  6.     ...
  7.     while (1){
  8.         ...
  9.         ret = get_gvm_boot_slot_info(ctx);
  10.         if (ret == -1) {
  11.             goto err;
  12.         }
  13.         ctx->qvb.slot_data = NULL;
  14.         ctx->swdl_slot = get_swdl_bank_info();
  15.         if (ctx->swdl_slot) {
  16.             if (!ctx->bank ||  ctx->slot_switch_config == SYMMETRIC_SLOT_SWITCH) {
  17.                 bank = ctx->swdl_slot;
  18.             } else{
  19.                 bank = ctx->bank;
  20.             }
  21.             ...
  22.             ret = verify_load_img(&ctx->qvb, (const char * const*)requested_partition, ctx->vmid, bank, is_avb_enforced);
  23.         } else {
  24.             vmm_err("Error while reading the swdl_slot");
  25.             ctx->config = NULL;
  26.         }
  27.         ...
  28.     }
  29. err:
  30.     return NULL;
  31. }
复制代码
2.QNX的slot状态

先看看成员变量swdl_slot的获取接口(注:代码中bank和slot都指的是ab分区状态,基建中会混用,但是只要区分好属于哪个体系的ab分区状态就行了):
  1. ...
  2. #include <amss/core/qc_sysinfo.h>
  3. ...
  4. static char get_swdl_bank_info(void)
  5. {
  6.     bank_t bank_id;
  7.     char bank = '\0';
  8.     bank_id = _get_active_bank();
  9.     bank = bank_id == BANK_A ? 'a' : 'b';
  10.     vmm_info("VMM System banked to %c", bank);
  11.     return bank;
  12. }
复制代码
根据实现,成员变量swdl_slot确实来自QNX体系中slot状态,而且有以下两个信息:


  • 返回值存在‘a’和'b'两种状态
  • 调用了来自头文件qc_sysinfo.h的_get_active_bank()接口(无法搜到具体实现)
成员变量swdl_slot确认完毕。
3.Android的slot状态

再看看成员变量bank的获取接口:
  1. ...
  2. #include "amss/lcm_utils.h"
  3. ...
  4. int get_gvm_boot_slot_info(struct gvm_context* ctx)
  5. {
  6.     int ret = 0;
  7.     struct boot_slot_info slot_info;
  8.     ...
  9.     if (ctx->misc_partition_name == NULL) {
  10.         vmm_info("misc partition is empty for vmid : %d",ctx->vmid);
  11.         ...
  12.         goto err;
  13.     }
  14.     ret = check_for_recovery_boot_slot_info(ctx->misc_partition_name, ctx->vmid, &slot_info);
  15.     if (ret == -1) {
  16.         vmm_err("Failure in boot slot check");
  17.         ret = -1;
  18.         goto err;
  19.     }
  20.     ...
  21.     if (slot_info.target_slot == 'a' || slot_info.target_slot == 'b')
  22.         ctx->bank = slot_info.target_slot;
  23.     else
  24.         ctx->bank = '\0';
  25.     ...
  26. err:
  27.     return ret;
  28. }
复制代码
根据实现,成员变量bank来自misc分区,同样的有以下两个信息:


  • 返回值存在‘a’,'b','\0'三种状态('\0'为空)
  • 调用了来自头文件lcm_utils.h的check_for_recovery_boot_slot_info()接口(来自LCM模块)
但是,QNX和Android体系都存在misc分区,那么这里的misc分区是不是安卓的呢?
从VMM模块中的驱动文件vmm_drv.c,可以找到相干逻辑:
  1. static int parse_gvm_list_and_populate_ctx(struct vmm_dev_t *vmm_dev)
  2. {
  3.     struct gvm_context *ctx;
  4.     ...
  5.     vmm_dev->num_gvms = fdt_get_num_vm();
  6.     list_initialize(&vmm_dev->gvm_ctx_head);
  7.     while (count < vmm_dev->num_gvms) {
  8.         ctx = calloc(1, sizeof(*ctx));
  9.         ...
  10.         if (ctx->vm_avb_version == 2) {
  11.             ...
  12.             vm_partition_prefix = fdt_get_vm_partition_prefix(vmid);
  13.             if (vm_partition_prefix == NULL){
  14.                 vmm_err("Failed to get vm_partition_prefix for vmid: %d", vmid);
  15.                 goto gvm_vm_partition_prefixget_error;
  16.             }
  17.             if (strstr(vm_partition_prefix, "la1")) {
  18.                 ctx->get_config = &get_config_la1;
  19.                 ctx->qvb.is_dp_enabled = check_for_partition("/dev/disk/la1_super");
  20.                 ctx->misc_partition_name = check_for_partition("/dev/disk/la1_misc")? "la1_misc": NULL;
  21.             } else if (strstr(vm_partition_prefix, "la")) {
  22.                 ctx->get_config = &get_config_la;
  23.                 ctx->qvb.is_dp_enabled = check_for_partition("/dev/disk/la_super");
  24.                 ctx->misc_partition_name = check_for_partition("/dev/disk/la_misc")? "la_misc": NULL;
  25.             } else if (strstr(vm_partition_prefix, "agl")) {
  26.                 ctx->get_config = &get_config_lv;
  27.                 ctx->qvb.is_dp_enabled = check_for_partition("/dev/disk/agl_super");
  28.                 ctx->misc_partition_name = check_for_partition("/dev/disk/agl_misc")? "agl_misc": NULL;
  29.             } else if (strstr(vm_partition_prefix, "lv")) {
  30.                 ctx->get_config = &get_config_lv;
  31.                 ctx->qvb.is_dp_enabled = check_for_partition("/dev/disk/lv_super");
  32.                 ctx->misc_partition_name = check_for_partition("/dev/disk/lv_misc")? "lv_misc": NULL;
  33.             } else if (strstr(vm_partition_prefix, "qnx")) {
  34.                 ctx->get_config = &get_config_qnx1;
  35.                 ctx->qvb.is_dp_enabled = false;
  36.                 ctx->misc_partition_name = NULL;
  37.             } else {
  38.                 vmm_err("Failed to set the function pointer");
  39.                 goto func_pointer_alloc_failed;
  40.             }
  41.             ...
  42.         } else {
  43.             ...
  44.         }
  45.         if (ctx->qvb.is_dp_enabled == true) {
  46.             ...
  47.             dp_enabled_a_conf_fname = fdt_get_dp_enabaled_a_config(vmid);
  48.             ...
  49.             dp_enabled_b_conf_fname = fdt_get_dp_enabaled_b_config(vmid);
  50.             ...
  51.         } else {
  52.             ...
  53.             dp_disabled_conf_fname = fdt_get_dp_disabled_config(vmid);
  54.             ...
  55.         }
  56.         ...
  57.         count++;
  58.     }
  59.     ...
  60.     return -1;
  61. }
复制代码
接口parse_gvm_list_and_populate_ctx的重要功能是剖析假造机的装备树设置文件。
在接口的实现中,一眼就可以找到为成员变量misc_partition_name赋值的代码段。
这段“朴素无华”的代码思量了差别假造机体系的环境,此中,“la”指的是Linux Android,因此misc_partition_name获取的是Android的misc分区名。
别的,分区设置文件名的获取逻辑也在此接口的实现中。
至此,成员变量bank确认完毕。

总结

在启动Android假造机的时间,QNX中的VMM模块会获取两个体系的slot状态,然后根据Android的ab分区状态,传入启动所需的设置文件。
Host QNX的slot状态是通过高通体系接口获取的;而Guest Android的slot状态是通过剖析Android的misc分区获取的。
回到关于怎样包管两个差别体系ab分区同等的题目,我们可以基于本文分析出的相干信息,做进一步的探索。

参考

VMM:[SA8155] 假造机管理器VMM先容(部门内容)


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表