r **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = argv0; // use the same program name
char buf[MAX_ARG_LENGTH];
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
(*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
}
check_and_fclose(fp, COMMAND_FILE);
LOGI("Got arguments from %s\n", COMMAND_FILE);
}
}
......
set_bootloader_message(&boot); //回写BCB
这里需要说一下“BCB”,即bootloader control block, 中文可以呼之为“启动控制模信息块”**,位于/misc分区,从代码上看,就是一个struct 结构体 :
struct bootloader_message {
char command[32];
char status[32];
char recovery[1024];
};
bootloader_message 结构体包含三个字段,具体含义如下:
command 字段中存储的是命令,它有以下几个可能值:
- boot-recovery:系统将启动进入Recovery模式
- update-radia 或者 update-hboot:系统将启动进入更新firmware的模式,这个更新过程由bootloader完成
- NULL:空值,系统将启动进入Main System主系统,正常启动。
status 字段存储的是更新的结果。更新结束后,由Recovery或者Bootloader将更新结果写入到这个字段中。
recovery 字段存放的是recovry模块的启动参数,一般包括升级包路径。其存储结构如下:第一行存放字符串“recovery”,第二行存放路径信息“–update_package=/mnt/sdcard/update.zip”等。 因此,参数之间是以“\n”分割的。
2. update_package
ota升级包的存放路径,从BCB或者/cache/recovery/command里面解析得到的,升级包一般下载后存放在cache或sdcard分区,当然,也有一些是存放到U盘之类的外接存储设备中的。一般赋值格式如下:
--update_package=/mnt/sdcard/update.zip 或 --update_package=CACHE:update.zip
3. int install_package (const char path, int wipe_cache, const char* install_file)
int install_package(const char* path, int* wipe_cache, const char* install_file)
{
//install_file 为 /cache/recovery/last_install
FILE* install_log = fopen_path(install_file, "w");
if (install_log) {
fputs(path, install_log);
fputc('\n', install_log);
} else {
LOGE("failed to open last_install: %s\n", strerror(errno));
}
int result = really_install_package(path, wipe_cache);
if (install_log) {
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
fputc('\n', install_log);
fclose(install_log);
}
return result;
}
4. static int really_install_package(const char path, int wipe_cache)
really_install_package函数在install_package函数中被调用,函数的主要作用是调用ensure_path_mounted确保升级包所在的分区已经挂载,另外,还会对升级包进行一系列的校验,在具体升级时,对update.zip包检查时大致会分三步:
检验SF文件与RSA文件是否匹配;
检验MANIFEST.MF与签名文件中的digest是否一致;
检验包中的文件与MANIFEST中所描述的是否一致
通过校验后,调用try_update_binary函数去实现真正的升级。
5. static int try_update_binary(const char path, ZipArchive zip, int wipe_cache)
try_update_binary是真正实现对升级包进行升级的函数:
static int try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
......
const char* binary = "/tmp/update_binary";
unlink(binary);
int fd = creat(binary, 0755);
.....
//将升级包里面的update_binary解压到/tmp/update_binary
bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
close(fd);
mzCloseZipArchive(zip);
......
int pipefd[2];
pipe(pipefd);
const char** args = (const char**)malloc(sizeof(char*) * 5);
args[0] = binary; //update_binary存放路径
args[1] = EXPAND(RECOVERY_API_VERSION); // Recovery版本号
char* temp = (char*)malloc(10);
sprintf(temp, "%d", pipefd[1]);
args[2] = temp;
args[3] = (char*)path; //升级包存放路径
args[4] = NULL;
pid_t pid = fork();//fork一个子进程
if (pid == 0) {
close(pipefd[0]);
//子进程调用update-binary执行升级操作
execv(binary, (char* const*)args);
fprintf(stdout, "E:Can't run