我们通常对一个文件可以直接读写操作,或者普通的分区(没有文件系统)也是一样,直接对/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") ==