Android OTA 升级之五:updater
2013-11-12 13:35
357 查看
作者: 宋立新
Email:zjujoe@yahoo.com
Updater可以作为学习解释器/编译器的同学一个很好的实例,但是我们只关心产品化相关的内容,所以并不去深究lex/yacc相关的东西。
62
// Where in the package we expect to find the edify script to execute.
63
// (Note it's "updateR-script", not the older "update-script".)
64 #define
SCRIPT_NAME
"META-INF/com/google/android/updater-script"
65
这里定义脚本的位置,注释说明本updater支持edify格式的脚本。
66 int
main(int
argc, char**
argv) {
67
// Various things log information to stdout or stderr more or less
68
// at random. The log file makes more sense if buffering is
69
// turned off so things appear in the right order.
70
setbuf(stdout,
NULL);
71
setbuf(stderr,
NULL);
72
73 if (argc != 4) {
74
fprintf(stderr,
"unexpected number of arguments (%d)/n",
argc);
75 return 1;
76 }
77
78 char*
version =
argv[1];
79 if ((version[0]
!= '1' &&
version[0] != '2' &&
version[0] != '3') ||
80
version[1] !=
'/0') {
81
// We support version 1, 2, or 3.
82
fprintf(stderr,
"wrong updater binary API; expected 1, 2, or 3; "
83 "got %s/n",
84
argv[1]);
85 return 2;
86 }
87
获取 version 参数。
88
// Set up the pipe for sending commands back to the parent process.
89
90 int
fd =
atoi(argv[2]);
91
FILE* cmd_pipe =
fdopen(fd,
"wb");
92
setlinebuf(cmd_pipe);
93
获取命令管道(用于图形显示等,见前篇)
94
// Extract the script from the package.
95
96 char* package_data =
argv[3];
97
ZipArchive za;
98 int
err;
99
err =
mzOpenZipArchive(package_data, &za);
100 if (err != 0) {
101
fprintf(stderr,
"failed to open package %s: %s/n",
102 package_data,
strerror(err));
103 return 3;
104 }
105
106 const
ZipEntry* script_entry =
mzFindZipEntry(&za,
SCRIPT_NAME);
107 if (script_entry ==
NULL) {
108
fprintf(stderr,
"failed to find %s in %s/n",
SCRIPT_NAME, package_data);
109 return 4;
110 }
111
112 char*
script =
malloc(script_entry->uncompLen+1);
113 if (!mzReadZipEntry(&za,
script_entry,
script, script_entry->uncompLen)) {
114
fprintf(stderr,
"failed to read script from package/n");
115 return 5;
116 }
117
script[script_entry->uncompLen] =
'/0';
118
读入脚本 META-INF/com/google/android/updater-script
119
// Configure edify's functions.
120
121
RegisterBuiltins();
122
RegisterInstallFunctions();
123 RegisterDeviceExtensions();
124
FinishRegistration();
125
注册语句处理函数
126
// Parse the script.
127
128
Expr*
root;
129 int
error_count = 0;
130
yy_scan_string(script);
131 int
error =
yyparse(&root, &error_count);
132 if (error != 0 ||
error_count > 0) {
133
fprintf(stderr,
"%d parse errors/n",
error_count);
134 return 6;
135 }
136
调用yy* 库函数解析脚本。
137
// Evaluate the parsed script.
138
139
UpdaterInfo updater_info;
140 updater_info.cmd_pipe = cmd_pipe;
141 updater_info.package_zip = &za;
142 updater_info.version
= atoi(version);
143
144
State
state;
145
state.cookie = &updater_info;
146
state.script =
script;
147
state.errmsg =
NULL;
148
149 char*
result =
Evaluate(&state,
root);
150 if (result ==
NULL) {
151 if (state.errmsg
== NULL) {
152
fprintf(stderr,
"script aborted (no error message)/n");
153
fprintf(cmd_pipe,
"ui_print script aborted (no error message)/n");
154 } else {
155
fprintf(stderr,
"script aborted: %s/n",
state.errmsg);
156 char*
line =
strtok(state.errmsg,
"/n");
157 while (line)
{
158 fprintf(cmd_pipe,
"ui_print %s/n",
line);
159
line =
strtok(NULL,
"/n");
160 }
161
fprintf(cmd_pipe,
"ui_print/n");
162 }
163
free(state.errmsg);
164 return 7;
165 } else {
166
fprintf(stderr,
"script result was [%s]/n",
result);
167
free(result);
168 }
解释执行脚本。 核心函数是
Evaluate。它会调用其他callback函数,而这些callback函数又会调用Evaluate去解析不同的脚本片段。从而实现一个简单的解释器。
169
170
mzCloseZipArchive(&za);
171
free(script);
172
173 return 0;
174 }
还没开始,就结束了。代码非常简单,因为细节隐藏在那些callback函数里。我们看一下。
这些语句控制执行流程。
这些语句执行各种功能。基本上,我们只需要知道用法就可以了。值得注意的是,run_program原语允许我们去执行自定义程序,这应该足够满足我们的个性化需求了。
Email:zjujoe@yahoo.com
前言
可以说,前面分析的OTA升级的各部分代码都是在搭一个舞台,而主角现在终于登场,它就是updater. Google的代码架构设计非常好,各部分尽量松耦合。前面介绍升级脚本时,可知有两种类型的脚本,amend & edify. 他们各自对应一个updater. 这里,我们主要关注新的edify的updater.Updater可以作为学习解释器/编译器的同学一个很好的实例,但是我们只关心产品化相关的内容,所以并不去深究lex/yacc相关的东西。
入口函数 main
(from: bootable/recovery/updater/updater.c)62
// Where in the package we expect to find the edify script to execute.
63
// (Note it's "updateR-script", not the older "update-script".)
64 #define
SCRIPT_NAME
"META-INF/com/google/android/updater-script"
65
这里定义脚本的位置,注释说明本updater支持edify格式的脚本。
66 int
main(int
argc, char**
argv) {
67
// Various things log information to stdout or stderr more or less
68
// at random. The log file makes more sense if buffering is
69
// turned off so things appear in the right order.
70
setbuf(stdout,
NULL);
71
setbuf(stderr,
NULL);
72
73 if (argc != 4) {
74
fprintf(stderr,
"unexpected number of arguments (%d)/n",
argc);
75 return 1;
76 }
77
78 char*
version =
argv[1];
79 if ((version[0]
!= '1' &&
version[0] != '2' &&
version[0] != '3') ||
80
version[1] !=
'/0') {
81
// We support version 1, 2, or 3.
82
fprintf(stderr,
"wrong updater binary API; expected 1, 2, or 3; "
83 "got %s/n",
84
argv[1]);
85 return 2;
86 }
87
获取 version 参数。
88
// Set up the pipe for sending commands back to the parent process.
89
90 int
fd =
atoi(argv[2]);
91
FILE* cmd_pipe =
fdopen(fd,
"wb");
92
setlinebuf(cmd_pipe);
93
获取命令管道(用于图形显示等,见前篇)
94
// Extract the script from the package.
95
96 char* package_data =
argv[3];
97
ZipArchive za;
98 int
err;
99
err =
mzOpenZipArchive(package_data, &za);
100 if (err != 0) {
101
fprintf(stderr,
"failed to open package %s: %s/n",
102 package_data,
strerror(err));
103 return 3;
104 }
105
106 const
ZipEntry* script_entry =
mzFindZipEntry(&za,
SCRIPT_NAME);
107 if (script_entry ==
NULL) {
108
fprintf(stderr,
"failed to find %s in %s/n",
SCRIPT_NAME, package_data);
109 return 4;
110 }
111
112 char*
script =
malloc(script_entry->uncompLen+1);
113 if (!mzReadZipEntry(&za,
script_entry,
script, script_entry->uncompLen)) {
114
fprintf(stderr,
"failed to read script from package/n");
115 return 5;
116 }
117
script[script_entry->uncompLen] =
'/0';
118
读入脚本 META-INF/com/google/android/updater-script
119
// Configure edify's functions.
120
121
RegisterBuiltins();
122
RegisterInstallFunctions();
123 RegisterDeviceExtensions();
124
FinishRegistration();
125
注册语句处理函数
126
// Parse the script.
127
128
Expr*
root;
129 int
error_count = 0;
130
yy_scan_string(script);
131 int
error =
yyparse(&root, &error_count);
132 if (error != 0 ||
error_count > 0) {
133
fprintf(stderr,
"%d parse errors/n",
error_count);
134 return 6;
135 }
136
调用yy* 库函数解析脚本。
137
// Evaluate the parsed script.
138
139
UpdaterInfo updater_info;
140 updater_info.cmd_pipe = cmd_pipe;
141 updater_info.package_zip = &za;
142 updater_info.version
= atoi(version);
143
144
State
state;
145
state.cookie = &updater_info;
146
state.script =
script;
147
state.errmsg =
NULL;
148
149 char*
result =
Evaluate(&state,
root);
150 if (result ==
NULL) {
151 if (state.errmsg
== NULL) {
152
fprintf(stderr,
"script aborted (no error message)/n");
153
fprintf(cmd_pipe,
"ui_print script aborted (no error message)/n");
154 } else {
155
fprintf(stderr,
"script aborted: %s/n",
state.errmsg);
156 char*
line =
strtok(state.errmsg,
"/n");
157 while (line)
{
158 fprintf(cmd_pipe,
"ui_print %s/n",
line);
159
line =
strtok(NULL,
"/n");
160 }
161
fprintf(cmd_pipe,
"ui_print/n");
162 }
163
free(state.errmsg);
164 return 7;
165 } else {
166
fprintf(stderr,
"script result was [%s]/n",
result);
167
free(result);
168 }
解释执行脚本。 核心函数是
Evaluate。它会调用其他callback函数,而这些callback函数又会调用Evaluate去解析不同的脚本片段。从而实现一个简单的解释器。
169
170
mzCloseZipArchive(&za);
171
free(script);
172
173 return 0;
174 }
还没开始,就结束了。代码非常简单,因为细节隐藏在那些callback函数里。我们看一下。
RegisterBuiltins
415 void RegisterBuiltins() {
416 RegisterFunction("ifelse", IfElseFn);
417 RegisterFunction("abort", AbortFn);
418 RegisterFunction("assert", AssertFn);
419 RegisterFunction("concat", ConcatFn);
420 RegisterFunction("is_substring", SubstringFn);
421 RegisterFunction("stdout", StdoutFn);
422 RegisterFunction("sleep", SleepFn);
423
424 RegisterFunction("less_than_int", LessThanIntFn);
425 RegisterFunction("greater_than_int", GreaterThanIntFn);
426 }
这些语句控制执行流程。
RegisterInstallFunctions
1036
1037 void RegisterInstallFunctions() {
1038 RegisterFunction("mount", MountFn);
1039 RegisterFunction("is_mounted", IsMountedFn);
1040 RegisterFunction("unmount", UnmountFn);
1041 RegisterFunction("format", FormatFn);
1042 RegisterFunction("show_progress", ShowProgressFn);
1043 RegisterFunction("set_progress", SetProgressFn);
1044 RegisterFunction("delete", DeleteFn);
1045 RegisterFunction("delete_recursive", DeleteFn);
1046 RegisterFunction("package_extract_dir", PackageExtractDirFn);
1047 RegisterFunction("package_extract_file", PackageExtractFileFn);
1048 RegisterFunction("symlink", SymlinkFn);
1049 RegisterFunction("set_perm", SetPermFn);
1050 RegisterFunction("set_perm_recursive", SetPermFn);
1051
1052 RegisterFunction("getprop", GetPropFn);
1053 RegisterFunction("file_getprop", FileGetPropFn);
1054 RegisterFunction("write_raw_image", WriteRawImageFn);
1055
1056 RegisterFunction("apply_patch", ApplyPatchFn);
1057 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1058 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
1059
1060 RegisterFunction("read_file", ReadFileFn);
1061 RegisterFunction("sha1_check", Sha1CheckFn);
1062
1063 RegisterFunction("ui_print", UIPrintFn);
1064
1065 RegisterFunction("run_program", RunProgramFn);
1066 }
这些语句执行各种功能。基本上,我们只需要知道用法就可以了。值得注意的是,run_program原语允许我们去执行自定义程序,这应该足够满足我们的个性化需求了。
相关文章推荐
- Android OTA 升级之五:updater
- Android OTA 升级(五):updater
- Android OTA升级原理和流程分析(九)---updater-script脚本语法简介以及执行流程
- Android OTA 升级之五:updater
- Android OTA 升级之五:updater
- Android OTA升级包制作脚本详解(生成升级脚本updater-script)
- Android OTA升级原理和流程分析(九)---updater-script脚本语法简介以及执行流程
- Android OTA 升级(五):updater
- Android OTA 升级(五):updater
- Android OTA 升级之五:updater
- Android OTA升级包制作脚本详解(五,升级脚本updater-script的执行<1>)
- Android OTA 升级(五):updater
- Android OTA 升级之五:updater
- Android OTA升级包制作脚本详解(五,升级脚本updater-script的执行<2>)
- Android OTA 升级之五:updater
- Android OTA升级包制作脚本详解(四,生成升级脚本updater-script)
- Android OTA 升级之五:updater
- Android OTA 升级之五:updater
- Android OTA 升级之五:updater
- Android OTA 升级之五:updater