Android Recovery OTA升级(二)—— Recovery源码解析

目录


概述

之前博客里一篇文章讲解了OTA包的生成原理,这篇文章主要是从Recovery源码的角度介绍一下Recovery是如何使用OTA包进行系统升级的。

为了防止泄密,本文源码都是基于Android4.4.2_r1版本进行分析。


Recovery源码解析

Recovery源码的入口位置为:bootable/recovery/recovery.cpp文件。下面我就来分析一下Recovery的源码。

static const char *CACHE_LOG_DIR = "/cache/recovery";
static const char *COMMAND_FILE = "/cache/recovery/command";
static const char *INTENT_FILE = "/cache/recovery/intent";
static const char *LOG_FILE = "/cache/recovery/log";

注释里英文写的很清楚:

The recovery tool communicates with the main system through /cache files.
/cache/recovery/command - INPUT - command line for tool, one arg per line
/cache/recovery/log - OUTPUT - combined log file from recovery run(s)
/cache/recovery/intent - OUTPUT - intent that was passed in

同时,代码里还有一段对Recovery识别命令的注释描述:

The arguments which may be supplied in the command file:
1. –send_intent=anystring - write the text out to recovery.intent
2. –update_package=path - verify install an OTA package file
3. –wipe_data - erase user data (and cache), then reboot
4. –wipe_cache - wipe cache (but not user data), then reboot


main函数

接下面,我们分析一下recovery.c的入口main函数。


输出重定向

static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"
int main(int argc, char **argv)
{
    time_t start = time(NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stdout);
    setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr);
    setbuf(stderr, NULL);
    // 打印启动recovery的时间
    printf("Starting recovery on %s", ctime(&start));
}

该部分的主要作用是:将标准输出和错误输出重定向到/tmp/recovery.log文件中。

填充fstab结构体

struct fstab {
    int num_entries;
    struct fstab_rec *recs;
    char *fstab_filename;
};
struct fstab_rec {
    char *blk_device;
    char *mount_point;
    char *fs_type;
    unsigned long flags;
    char *fs_options;
    int fs_mgr_flags;
    char *key_loc;
    char *verity_loc;
    long long length;
    char *label;
    int partnum;
    int swap_prio;
    unsigned int zram_size;
};
typdef struct fstab_rec Volume;

void load_volume_table()
{
    int i;
    int ret;

    // 解析/etc/recovery.fstab配置文件,填充fstab结构体
    fstab = fs_mgr_read_fstab("/etc/recovery.fstab");
    if (!fstab) {
        LOGE("failed to read /etc/recovery.fstab\n");
        return;
    }

    // 在fstab结构体中增加/tmp分区
    ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk", 0);
    if (ret < 0) {
        LOGE("failed to add /tmp entry to fstab\n");
        fs_mgr_free_fstab(fstab);
        fstab = NULL;
        return;
    }

    printf("recovery filesystem table\n");
    printf("=========================\n");
    for (i = 0; i < fstab->num_entries; i ++) {
        Volume* v = &fstab->recs[i];
        printf("  %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
                v->blk_device, v->length);
    }
    printf("\n");
}

int main(int argc, char **argv)
{
    load_volume_table();
}

该部分代码的主要作用是用recovery根目录下的/etc/recovery.fstab中的分区内容和/tmp分区内容来填充了fstab结构体,并没有真正的进行分区挂载。


挂载cache分区

源码分析如下:

typedef struct fstab_rec Volume;
#define LAST_LOG_FILE "/cache/recovery/last_log"

int ensure_path_mounted(const char* path)
{
    // 这里是在fstab结构体中找到挂载点为/cache的fstab_recs
    Volume* v = volume_for_path(path);
    if (v == NULL) {
        LOGE("unknown volume for path [%s]\n", path);
        return -1;
    }

    // ramdisk类型的分区是一直挂载的。
    if (strcmp(v->fs_type, "ramdisk") == 0) {
        return 0;
    }

    int result;
    result = scan_mounted_volumes();
    const MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
    if (mv) {
        // 说明当前分区已经被挂载了
        return 0;
    }

    // 下面是具体的挂载过程
    mkdir(v->mount_point, 0755);
    if (strcmp(v->fs_type, "yaffs2") == 0) {
        // .......不用管这个yaffs2分区类型了,目前基本是ext4的。
    } else if (strcmp(v->fs_type, "ext4"
  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值