StashRecvDataToBuffer函数功能分析

函数功能概述

StashRecvDataToBuffer函数是OTA升级过程中的核心数据存储函数,负责将接收到的升级数据缓存到内存或写入到存储设备的HAL层。

函数签名

1
static int StashRecvDataToBuffer(unsigned char *buffer, unsigned int startAddr, unsigned int endAddr)

参数说明

  • buffer: 要存储的数据缓冲区
  • startAddr: 数据的起始地址(相对于当前组件的偏移)
  • endAddr: 数据的结束地址(相对于当前组件的偏移)

函数执行流程

1. 信息组件处理分支

1
2
3
4
5
6
if (g_currentDloadComp.isInfoComp) {
if (CopyToDloadCompBuffer(buffer, (endAddr - startAddr)) != OHOS_SUCCESS) {
printf("StashRecvDataToBuffer HotaHalWrite failed,\r\n");
return OHOS_FAILURE;
}
}

功能: 当前下载的是信息组件时,将数据复制到内存缓冲区g_infoCompBuff中。
用途: 信息组件包含升级包的元数据,需要先完整接收并验证后才能处理其他组件。

2. 非信息组件处理分支

1
2
3
4
5
6
7
8
9
10
11
12
13
else {
int partition = PARTITION_ERROR;
GetCurrentDloadCompPartition(&partition);
if (HotaHalWrite(partition, buffer, startAddr - g_currentDloadComp.offset,
endAddr - startAddr) != OHOS_SUCCESS) {
printf("StashRecvDataToBuffer HotaHalWrite failed, partition = %d .\r\n", partition);
ReportErrorCode(HOTA_DATA_WRITE_ERR);
UpdateStatus(HOTA_FAILED);
return OHOS_FAILURE;
}
// calc Hash
HotaHashCalc(buffer, endAddr - startAddr);
}

功能:

  1. 获取当前组件对应的分区ID
  2. 调用HAL层写入函数将数据写入对应分区
  3. 计算数据的哈希值用于后续验证

3. 状态更新

1
2
g_currentDloadComp.remainSize -= (endAddr - startAddr);
g_currentDloadComp.currentSize += (endAddr - startAddr);

功能: 更新当前组件的下载进度信息。

Partition可选项分析

基于Hi3861平台的Partition定义

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef enum {
PARTITION_PASS_THROUGH = 0, // 透传分区
PARTITION_BOOTLOADER = 2, // Bootloader分区
PARTITION_KERNEL_A = 3, // 内核A分区
PARTITION_KERNEL_B = 4, // 内核B分区
PARTITION_ROOTFS = 5, // 根文件系统分区
PARTITION_APP = 6, // 应用程序分区
PARTITION_DATA = 7, // 数据分区
PARTITION_OTA_TAG = 8, // OTA标签分区
PARTITION_OTA_CONFIG = 9, // OTA配置分区
PARTITION_ROOTFS_EXT4 = 10, // EXT4根文件系统分区
PARTITION_MAX
} HotaPartition;

特殊分区定义

1
2
#define PARTITION_ERROR         -1     // 错误分区
#define PARTITION_INFO_COMP 1 // 信息组件分区

分区组件映射表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static const ComponentTableInfo g_componentTable[] = {
{ PARTITION_PASS_THROUGH, "", "/sdcard/update/ota_pkg_pass_through.bin", 0},
{ PARTITION_INFO_COMP, "", "/sdcard/update/infocomp.bin", 0},
{ PARTITION_BOOTLOADER, "bootloader", "/sdcard/update/u-boot.bin", 0},
{ PARTITION_KERNEL_A, "kernel_A", "/sdcard/update/kernel.bin", 0},
{ PARTITION_KERNEL_B, "kernel_B", "", 0},
{ PARTITION_ROOTFS, "rootfs", "/sdcard/update/rootfs.img", 0},
{ PARTITION_APP, "app", "", 0},
{ PARTITION_DATA, "data", "", 0},
{ PARTITION_OTA_TAG, "ota_tag", "/sdcard/update/OTA.tag", 0},
{ PARTITION_OTA_CONFIG, "config", "/sdcard/update/config", 0},
{ PARTITION_ROOTFS_EXT4, "rootfs_ext4", "/sdcard/update/rootfs_ext4.img", 0},
{ PARTITION_MAX, NULL, NULL, 0}
};

Partition对OTA的影响

1. 数据路由影响

分区选择机制:

  • 通过GetCurrentDloadCompPartition函数,根据组件名称映射到具体的分区ID
  • 不同的分区ID决定了数据最终写入的物理位置

2. 双分区升级机制

KERNEL_A vs KERNEL_B:

  • PARTITION_KERNEL_A (3): 当前运行的内核分区
  • PARTITION_KERNEL_B (4): 备用内核分区,用于A/B分区升级
  • 支持无缝升级和快速回滚

3. 信息组件特殊处理

PARTITION_INFO_COMP (1):

  • 特殊处理,不直接写入存储
  • 数据缓存在内存中,用于验证和解析升级包信息
  • 包含组件列表、版本信息、签名数据等

4. HAL层写入行为

1
2
3
4
5
6
7
8
9
10
11
12
13
int HotaHalWrite(int partition, unsigned char *buffer, unsigned int offset, unsigned int buffLen)
{
if (partition == PARTITION_INFO_COMP) {
printf("partition == PARTITION_INFO_COMP, skip it.");
return OHOS_SUCCESS; // 信息组件跳过HAL写入
}
hi_u32 result = hi_upg_transmit(offset, buffer, buffLen);
if (result != HI_ERR_SUCCESS) {
printf("hi_upg_transmit failed. retCode = %x.\r\n", result);
return OHOS_FAILURE;
}
return OHOS_SUCCESS;
}

不同分区的写入行为:

  • 信息组件: 跳过HAL写入,仅在内存中处理
  • 其他组件: 通过hi_upg_transmit写入到对应的Flash分区

5. 错误处理影响

分区错误的影响:

  • PARTITION_ERROR (-1): 表示分区映射失败
  • 导致升级失败,系统状态回到HOTA_FAILED
  • 触发错误回调HOTA_DATA_WRITE_ERR

6. 升级策略影响

不同分区的升级策略:

  1. Bootloader: 通常需要特殊的升级保护机制
  2. Kernel: 支持A/B分区无缝升级
  3. RootFS: 文件系统级别的升级
  4. App: 应用程序更新
  5. Data: 用户数据分区,通常保持不变

总结

StashRecvDataToBuffer函数通过partition参数实现了灵活的数据路由机制:

  1. 信息组件:内存缓存,用于元数据解析和验证
  2. 系统组件:写入对应的Flash分区,支持A/B分区升级
  3. 错误处理:通过分区ID验证确保升级安全性
    Partition的选择直接影响了:
  • 数据的物理存储位置
  • 升级策略(A/B分区、原地升级等)
  • 系统的启动行为
  • 升级失败时的恢复机制
    这种设计确保了OTA升级过程的灵活性和安全性,支持不同类型组件的差异化处理。