recovery uncrypt功能解析(bootable/recovery/uncrypt/uncrypt.cpp)

本文详细解析了Android OTA更新过程中,如何在不挂载data分区的情况下,利用bootable/recovery/uncrypt/uncrypt.cpp源码实现从/dev/block/data获取升级包升级。uncrypt.cpp的核心功能包括生成稀疏列表、处理加密数据、建立block.map文件等,使得可以直接从设备存储读取解密后的升级包数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们通常对一个文件可以直接读写操作,或者普通的分区(没有文件系统)也是一样,直接对/dev/block/boot直接读写,就可以获取里面的数据内容了。

当我们在ota升级的时候,把升级包下载到cache/data分区,然后进入recovery系统后,把cache/data分区mount之后,即可从对应的分区获取zip升级包升级了, 前提是我们需要挂载对应的分区cache或者data,这样才能给读升级包升级,如果不挂载分区,我们能给直接从/dev/block/data获取升级包升级吗?

这就是我们今天讨论的主题,不挂载data分区,如何从/dev/block/data获取升级包升级, 这个依赖bootable/recovery/uncrypt/uncrypt.cpp下面的代码实现了,我们通过获取update.zip升级包, 是如何在/dev/block/data存储的。 我们知道了update.zip如何在/dev/block/data存储的,那么就可以直接从/dev/block/data读取升级包升级了。下面对uncrypt.cpp源码分析:

static constexpr int WINDOW_SIZE = 5;
static constexpr int FIBMAP_RETRY_LIMIT = 3;

// uncrypt provides three services: SETUP_BCB, CLEAR_BCB and UNCRYPT.
//
// SETUP_BCB and CLEAR_BCB services use socket communication and do not rely
// on /cache partitions. They will handle requests to reboot into recovery
// (for applying updates for non-A/B devices, or factory resets for all
// devices).
//
// UNCRYPT service still needs files on /cache partition (UNCRYPT_PATH_FILE
// and CACHE_BLOCK_MAP). It will be working (and needed) only for non-A/B
// devices, on which /cache partitions always exist.
static const std::string CACHE_BLOCK_MAP = "/cache/recovery/block.map";
static const std::string UNCRYPT_PATH_FILE = "/cache/recovery/uncrypt_file";
static const std::string UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
static const std::string UNCRYPT_SOCKET = "uncrypt";

WINDOW_SIZE = 5; 每次当有5个block size大小的数据,就写一次。

FIBMAP_RETRY_LIMIT = 3;  调用 ioctl(fd, FIBMAP, block) 尝试的次数。

CACHE_BLOCK_MAP = "/cache/recovery/block.map"  关于升级包的存储信息及稀疏块列表的描述文件。

UNCRYPT_PATH_FILE = "/cache/recovery/uncrypt_file";  存储原始升级包的路径。

UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";  对升级包uncrypt操作的状态结果。

UNCRYPT_SOCKET = "uncrypt";    使用 /dev/socket/uncrypt 通信

static int write_at_offset(unsigned char* buffer, size_t size, int wfd, off64_t offset) {
    if (TEMP_FAILURE_RETRY(lseek64(wfd, offset, SEEK_SET)) == -1) {
        PLOG(ERROR) << "error seeking to offset " << offset;
        return -1;
    }
    if (!android::base::WriteFully(wfd, buffer, size)) {
        PLOG(ERROR) << "error writing offset " << offset;
        return -1;
    }
    return 0;
}

写长度为size的buffer数据到wfd偏移offset地方

static void add_block_to_ranges(std::vector<int>& ranges, int new_block) {
    if (!ranges.empty() && new_block == ranges.back()) {
        // If the new block comes immediately after the current range,
        // all we have to do is extend the current range.
        ++ranges.back();
    } else {
        // We need to start a new range.
        ranges.push_back(new_block);
        ranges.push_back(new_block + 1);
    }
}

生成升级包的block块的稀疏列表, 比如1001 1004, 如果new block为1004, 则稀疏范围为1001 1005, 如果new block非1004,比如为1120, 则稀疏列表为 1001 1004, 1120 1121。

1001 1004表示为1001 1002 1003三个block,不包含1004

static struct fstab* read_fstab() {
    fstab = fs_mgr_read_fstab_default();
    if (!fstab) {
        LOG(ERROR) << "failed to read default fstab";
        return NULL;
    }

    return fstab;
}

读取分区挂载表

static const char* find_block_device(const char* path, bool* encryptable, bool* encrypted, bool *f2fs_fs) {
    // Look for a volume whose mount point is the prefix of path and
    // return its block device.  Set encrypted if it's currently
    // encrypted.

    // ensure f2fs_fs is set to 0 first.
    if (f2fs_fs)
        *f2fs_fs = false;
    for (int i = 0; i < fstab->num_entries; ++i) {
        struct fstab_rec* v = &fstab->recs[i];
        if (!v->mount_point) {
            continue;
        }
        int len = strlen(v->mount_point);
        if (strncmp(path, v->mount_point, len) == 0 &&
            (path[len] == '/' || path[len] == 0)) {
            *encrypted = false;
            *encryptable = false;
            if (fs_mgr_is_encryptable(v) || fs_mgr_is_file_encrypted(v)) {
                *encryptable = true;
                if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
                    *encrypted = true;
                }
            }
            if (f2fs_fs && strcmp(v->fs_type, "f2fs") == 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值