当前位置:   article > 正文

[SA8155] 探索QNX Hypervisor如何管理Android系统的AB分区(一)_安卓查看ab分区

安卓查看ab分区

本文建议在对高通8155车机系统有一定的了解下进行阅读

高通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分区状态下运行
  • 根据配置文件名,可以推断此配置的两个使用条件:
    1. 动态分区被使能
    2. 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为空的情况,让bankswdl_slot状态一致

那么:

  • context中的成员变量swdl_slot应该代表Host QNX的slot状态,
  • context中的成员变量bank应该代表Guest Android的slot状态,
  • swdl_slotbank分别从哪儿获取赋值的呢

还是在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的获取接口(注:代码中bankslot都指的是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.hcheck_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介绍(部分内容)

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/937133
推荐阅读
相关标签
  

闽ICP备14008679号