简介
系统在执行升级操作时,执行指令reboot updater,对misc分区写入相关信息,然后重启系统进行分区切换操作,加载updater分区并执行OTA升级,本文仅介绍reboot的操作原理,以下内容主要基于v3.0-Release版进行分析。
代码路径
base\startup\init_lite\services\cmds\reboot\init_cmd_reboot.c
base\startup\init_lite\interfaces\innerkits\reboot\init_reboot.c
base\startup\init_lite\services\src\init_reboot.c
目录结构
base/startup/init_lite/ # init组件
├── LICENSE
└── services
├── include # init组件头文件目录
├── src # init组件源文件目录
└── test # init组件测试用例源文件目录
└── unittest
vendor
└──huawei
└──camera
└──init_configs # init配置文件目录(json格式,镜像烧写后部署于/etc/init.cfg)
init_cmd_reboot.c文件位于init组件中,init组件负责处理从内核加载第一个用户态进程开始,到第一个应用程序启动之间的系统服务进程启动过程。启动恢复子系统除负责加载各系统关键进程之外,还需在启动的同时设置其对应权限,并在子进程启动后对指定进程实行保活(若进程意外退出要重新启动),对于特殊进程意外退出时,启动恢复子系统还要执行系统复位操作。
流程图
源码解读
1.init_cmd_reboot.c文件的main函数
在命令行输入reboot updater指令,会调用到下面的函数中:
int main(int argc, char* argv[])
{
if (argc > REBOOT_CMD_NUMBER) { //判断输入参数是否合法
printf("usage: reboot shutdown\n reboot updater\n reboot updater[:options]\n reboot\n");
return 0;
}
if (argc == REBOOT_CMD_NUMBER && strcmp(argv[1], "shutdown") != 0 &&
strcmp(argv[1], "updater") != 0 &&
strncmp(argv[1], "updater:", strlen("updater:")) != 0) {
printf("usage: reboot shutdown\n reboot updater\n reboot updater[:options]\n reboot\n");
return 0;
}
int ret;
if (argc == REBOOT_CMD_NUMBER) {
ret = DoReboot(argv[1]);
} else {
ret = DoReboot(NULL);
}
if (ret != 0) {
printf("[reboot command] DoReboot Api return error\n");
} else {
printf("[reboot command] DoReboot Api return ok\n");
}
while (1) {
pause();
}
return 0;
}
main函数中主要作用是识别reboot指令,执行DoReboot操作。
2.DoReboot函数中的libuv库
int DoReboot(const char *cmdContent)
{
uid_t uid1 = getuid();
uid_t uid2 = geteuid();//鉴权操作,reboot需要在root权限下执行
if (uid1 != 0 || uid2 != 0) {
INIT_LOGE("uid1=%d, uid2=%d, user MUST be root, error!", uid1, uid2);
return -1;
}
//省略部分不重要代码
/...
.../
if (snprintf_s(value, MAX_REBOOT_NAME_SIZE, MAX_REBOOT_NAME_SIZE - 1, "%s%s", "reboot,", cmdContent) < 0) {
IN