一
install.cpp中调用updater:
const char* binary = "/tmp/update_binary";
const char** args = (const char**)malloc(sizeof(char*) * 5);
args[0] = binary;
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
char* temp = (char*)malloc(10);
sprintf(temp, "%d", pipefd[1]);
args[2] = temp;
args[3] = (char*)path;
args[4] = NULL;
pid_t pid = fork();
if (pid == 0) {
umask(022);
close(pipefd[0]);
execv(binary, (char* const*)args);
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno)); //updater执行正确永远不会被调用
_exit(-1);
}
close(pipefd[1]);
#include <
unistd.h
>
int execv(const char *progname, char *const argv[]);
1.2 用法介绍
execv会停止执行当前的进程, 并且以progname应用进程替换被停止执行的进程,进程ID没有改变 。
progname: 被执行的应用程序。
argv: 传递给应用程序的参数列表, 注意这个数组的第一个参数应该是应用程序名字本身(即argv[0] = progname), 并且最后一个参数应该为NULL ,不能将多个参数合并为一个参数放入数组。
1.3 返回值
如果应用程序正常执行完毕, 那么execv是永远不会返回的;当execv在调用进程中返回时,那么这个应用程序应该出错了 (可能是程序本身没找到,权限不够等), 此时它的返回值应该是-1,具体的错误代码可以通过全局变量errno查看,还可以通过stderr得到具体的错误描述字符串。
调用updater的3个参数:
1 recovery API: the version number for this interface
2 一个管道的fd,updater向这个管道写,用于更新进度条 an fd to which the program can write in order to update the progress bar
int pipefd[2];
pipe(pipefd);
char* temp = (char*)malloc(10);
sprintf(temp, "%d", pipefd[1]); //把pipefd[1]代表的管道的fd,作为字符串参数传给updater
args[2] = temp;
args[3] = (char*)path;
args[4] = NULL;
pid_t pid = fork();
if (pid == 0) {
umask(022);
close(pipefd[0]); //updater中关闭pipefd[0]
execv(binary, (char* const*)args);
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
close(pipefd[1]); //recovery中关闭pipefd[1]
FILE* from_child = fdopen(pipefd[0], "r"); //recovery从管道接收来自updater的信息
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
3 升级包路径 the name of the package zip file
二 recovery/updater.c中:
int
main(
int
argc,
char
** argv) {
// Various things log information to stdout or stderr more or less
// at random (though we've tried to standardize on stdout). The
// log file makes more sense if buffering is turned off so things
// appear in the right order.
setbuf
(stdout, NULL);
// 创建子进程时,父进程的缓冲区也被复制到子进程了。所以子进程在printf时,就一起printf出来了,因为recovery中已经将 stdout stderr重定向到了文件中,所以这里把输出缓冲区设置为无缓冲,直接从流输出数据
setbuf
(stderr, NULL);
if
(argc != 4) {
printf
(
"unexpected number of arguments (%d)\n"
, argc);
return
1;
}
char
* version = argv[1];
if
((version[0] !=
'1'
&& version[0] !=
'2'
&& version[0] !=
'3'
) ||
version[1] !=
'\0'
) {
// We support version 1, 2, or 3.
printf
(
"wrong updater binary API; expected 1, 2, or 3; "
"got %s\n"
,
argv[1]);
return
2;
}
// Set up the pipe for sending commands back to the parent process.
// 将recovery传递的字符串格式的pipe[1]的fd,转换为fd,再打开这个管道
int
fd =
atoi
(argv[2]);
FILE
* cmd_pipe = fdopen(fd,
"wb"
);
setlinebuf(cmd_pipe);
// Extract the script from the package.
const
char
* package_filename = argv[3]; //argv[3]就是升级包完成路径
MemMapping map;
if
(sysMapFile(package_filename, &map) != 0) { //将升级包映射到内存中
printf
(
"failed to map package %s\n"
, argv[3]);
return
3;
}
ZipArchive za;
int
err;
err = mzOpenZipArchive(map.addr, map.length, &za); //根据内存中的起始地址和长度,打开这个文件
if
(err != 0) {
printf
(
"failed to open package %s: %s\n"
,
argv[3],
strerror
(err));
return
3;
}
const
ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); //在文件中查找升级脚本这个entry
if
(script_entry == NULL) {
printf
(
"failed to find %s in %s\n"
, SCRIPT_NAME, package_filename);
return
4;
}
char
* script =
malloc
(script_entry->uncompLen+1)
;
// 根据升级脚本的实际大小分配一段内存,将升级脚本所有内容读到script中
if
(!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
printf
(
"failed to read script from package\n"
);
return
5;
}
script[script_entry->uncompLen] =
'\0'
;
// Configure edify's functions.
RegisterBuiltins();
RegisterInstallFunctions();
RegisterBlockImageFunctions();
RegisterDeviceExtensions();
FinishRegistration();
// Parse the script.
Expr* root;
struct Expr {
Function fn;
char* name;
int argc;
Expr** argv;
int start, end;
};
int
error_count = 0;
int
error = parse_string(script, &root, &error_count); //解析脚本
if
(error != 0 || error_count > 0) {
printf
(
"%d parse errors\n"
, error_count);
return
6;
}
struct
selinux_opt seopts[] = {
{ SELABEL_OPT_PATH,
"/file_contexts"
}
};
sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
if
(!sehandle) {
fprintf
(cmd_pipe,
"ui_print Warning: No file_contexts\n"
);
}
// Evaluate the parsed script.
UpdaterInfo updater_info;
typedef struct {
FILE* cmd_pipe;
ZipArchive* package_zip;
int version;
uint8_t* package_zip_addr;
size_t package_zip_len;
UpdaterInfo;
updater_info.cmd_pipe = cmd_pipe; //updater_info.cmd_pipe取得了updater打开的管道
updater_info.package_zip = &za; //updater_info.package_zip 内存中的zip升级包
updater_info.version =
atoi
(version); //updater_info.version recovery api版本
updater_info.package_zip_addr = map.addr; //updater_info.package_zip_addr zip升级包在内存中的起始地址
updater_info.package_zip_len = map.length; // updater_info.package_zip_len zip升级包在内存中的长度
State state;
typedef struct {
// Optional pointer to app-specific data; the core of edify never
// uses this value.
void* cookie;
// The source of the original script. Must be NULL-terminated,
// and in writable memory (Evaluate may make temporary changes to
// it but will restore it when done).
char* script;
// The error message (if any) returned if the evaluation aborts.
// Should be NULL initially, will be either NULL or a malloc'd
// pointer after Evaluate() returns.
char* errmsg;
} State;
state.cookie = &updater_info;
state.script = script; //现在state.script指向的就是脚本内容
state.errmsg = NULL;
char
* result = Evaluate(&state, root); //执行脚本
if
(result == NULL) {
if
(state.errmsg == NULL) {
printf
(
"script aborted (no error message)\n"
);
fprintf
(cmd_pipe,
"ui_print script aborted (no error message)\n"
);
}
else
{
printf
(
"script aborted: %s\n"
, state.errmsg);
char
* line =
strtok
(state.errmsg,
"\n"
);
while
(line) {
fprintf
(cmd_pipe,
"ui_print %s\n"
, line);
line =
strtok
(NULL,
"\n"
);
}
fprintf
(cmd_pipe,
"ui_print\n"
);
}
free
(state.errmsg);
return
7;
}
else
{
fprintf
(cmd_pipe,
"ui_print script succeeded: result was [%s]\n"
, result);
free
(result);
}
if
(updater_info.package_zip) {
mzCloseZipArchive(updater_info.package_zip);
}
sysReleaseMap(&map);
free
(script);
return
0;
}
三 recovery/edify/expr.c
typedef struct {
int type;
ssize_t size;
char* data;
} Value;
struct Expr {
Function fn;
char* name;
int argc;
Expr** argv;
int start, end;
};
typedef struct {
void* cookie;
char* script;
char* errmsg;
} State;
char
* Evaluate(State* state, Expr* expr) {
Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
typedef Value* (*Function)(const char* name, State* state, int argc, Expr* argv[]);
if
(v == NULL)
return
NULL;
if
(v->type != VAL_STRING) {
ErrorAbort(state,
"expecting string, got value type %d"
, v->type);
FreeValue(v);
return
NULL;
}
char
* result = v->data;
free
(v);
return
result;
}
Evaluate()函数主要是调用了expr的fn()函数,参数expr的类型是Expr,定义如下:
1. struct Expr {
2. Function fn;
3. char* name;
4. int argc;
5. Expr** argv;
6. int start, end;
7. };
从Expr的定义中可以看到它有一个字段argv,这个字段是Expr指针的指针类型,它实际上会指向一个Expr指针的数组对象,表示Expr对象的所有下一级对象。通过这个字段,脚本解析后得到的所有命令都串接在一起,而且命令的执行函数还会调用Ecaluate()来继续执行argv中的Expr对象,因此,虽然Evaluate()中只调用了root对象的fn()函数,但是实际上会执行脚本中的所有命令。
// args:
// - block device (or file) to modify in-place
// - transfer list (blob)
// - new data stream (filename within package.zip)
// - patch stream (filename within package.zip, must be uncompressed)
Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
Value* blockdev_filename;
Value* transfer_list_value;
char* transfer_list = NULL;
Value* new_data_fn;
Value* patch_data_fn;
bool success = false;
if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
&new_data_fn, &patch_data_fn) < 0) {
return NULL;
}
脚本中调用block_image_update("/dev/block/bootdevice/by-name/system", package_extract_file("system.transfer.list"), "system.new.dat", "system.patch.dat");
就会执行BlockImageUpdateFn函数
1 ReadValueArgs取得脚本中的/dev/block/bootdevice/by-name/system,package_extract_file("system.transfer.list"),system.new.dat", "system.patch.dat"这四个参数,赋值给blockdev_filename ,transfer_list_value, new_data_fn,patch_data_fn
typedef struct {
int type;
ssize_t size;
char* data;
} Value;
2
标签:script,--,package,argv,char,int,源码,updater,android From: https://blog.51cto.com/u_16248677/7384722