http://www.itqun.net/content-detail/76360_2.html
【什么是Android系统Recovery?Android系统Recovery有什么功能?请参考:http://www.anzhuoba.com/thread-5984-1-1.html】! ^" ?2 p/ N- b- j0 I$ V; a
% |0 d$ w8 {4 G! M ^Android系统利用Recovery模式,进行恢复出厂设置,OTA升级,patch升级及firmware升级,系统备份等。Recovery模式功能的强弱跟Recovery Image软件版本有关系,也就是在制作Recovery Image时,开发者给Recovery添加功能的多少,这是一个完全可以裁减的工作。
1 D: n% h' r$ B9 }$ z, V3 k7 }" }- C; ]' h) \8 z- w( {
一、Recovery升级简介
. D' f3 ]. j+ D( P: ^* ]升级一般通过运行升级包中的META-INF/com/google/android/update-script脚本来执行自定义升级,脚本中是一组recovery系统能识别的UI控制,文件系统操作命令,例如write_raw_image(写FLASH分区),copy_dir(复制目录)。该包一般被下载至SDCARD和CACHE分区下。如果对该包内容感兴趣,可以从 http://forum.xda-developers.com/showthread.php?t=442480下载JF升级包来看看。3 D+ [5 X3 w0 x! y) `- F5 I
升级中还涉及到包的数字签名,签名方式和普通JAR文件签名差不错。公钥会被硬编译入recovery,编译时生成在:out/target/product/XX/obj/PACKAGING/ota_keys_inc_intermediates/keys.inc2 c. O- O! D) X: W& p7 ?* O( g
% J" b5 O# T$ Q% g5 } 二、Android系统三种启动模式
# `& G3 ?; h0 }8 M8 a9 c这里为了了解Recovery机制,我们以G1手机为例,后续的Android版本可能有些细微差别,但是大同小异。6 ]- G2 v! q) v, N" i
G1手机的Magic Key操作有:
* ?+ }* a; r9 V1 v% [& x(1) camera +power:bootloader模式,ADP里则可以使用fastboot模式
, B% J" X+ [! A(2) home + power:recovery模式
! @' G; L' c( r+ v; O& \: Q- k5 BG1手机有三种正常启动模式,或者说三种Bootloader正常启动。按照BCB(Bootloader Control Block, 下节介绍)中的command分类:
- O8 I+ o8 O! A2 U' V(1) command == 'boot-recovery' → 启动recovery.img。recovery模式
! N4 G e5 h/ J+ m2 Y(2) command =='update-radio/hboot' → 更新firmware(bootloader)
/ n- w4 G- m, _+ Y, [( ~8 V(3) 其他 → 启动boot.img
1 {6 B# a8 Z" [) @' f3 {# u' T/ r9 ]7 }6 b
三、Recovery涉及到的其他系统及文件
5 f- \3 C! P6 M0 T
d* ?! o/ N4 y2 _2 Z 1、CACHE分区文件
* D& ^5 `! [0 {2 F$ F* \* n' A* @' K Recovery 工具通过NAND cache分区上的三个文件和主系统打交道。主系统(包括恢复出厂设置和% |* r7 r" J" ?6 A2 U, Q
OTA升级)可以写入recovery所需的命令,读出recovery过程中的LOG和intent。3 m: Q0 w9 f! V, `# ^8 B" e
1)/cache/recovery/command: recovery命令,由主系统写入。所有命令如下:7 h6 e: E, ?/ k5 K
--send_intent=anystring - write the text out to recovery.intent
: C- c6 A6 [5 N' ^# X6 z- I/ d --update_package=root:path - verify install an OTA package file8 |, w7 I) a! t+ ~
--wipe_data - erase user data (and cache), then reboot9 c8 |' ]# C0 t+ F
--wipe_cache - wipe cache (but not user data), then reboot _5 w9 v/ z, y; P: R4 p* j" Q
2)/cache/recovery/log:recovery过程日志,由主系统读出
& m2 f1 s! O5 a. g6 Q0 o+ w y' A 3)/cache/recovery/intent:recovery输出的intent. r' ?2 z L7 e& O) k4 A u
& b O1 @: @7 j! w) ]) [
2、MISC分区内容, U1 T" d3 j! B) \8 ?! v j: t" E% _7 Y
Bootloader Control Block (BCB) 存放recovery bootloader message。 ) S6 `2 w3 G$ `/ H! v8 e# O
结构如下:
8 }* S. X0 j- U struct bootloader_message {
2 z) V" E( `& h9 F- N char command[32];9 Q1 t: f" p4 o! b6 f
char status[32]; // 未知用途; c: S. z! B9 X
char recovery[1024];7 d9 g4 d$ w* ?) k5 R/ o
};' P$ [, ?3 G* \' W1 `/ V0 m
command可以有以下两个值:
( ]( B. i/ O ^" B Z/ D" H4 H) N 1)boot-recovery:标示recovery正在进行,或指示bootloader应该进入recovery mode% f; L& q1 o. @9 G* z
2)update-hboot/radio:指示bootloader更新firmware
- ?0 L* V2 A0 j# u1 K$ V# z recovery的值:
8 _9 S# S, o( N9 L5 T2 n& L* L4 Z 1)<recovery command>
4 T" U1 W( o5 y: r# E; v" Y: P 其中recovery command为CACHE:/recovery/command命令。
( C9 g7 ] s6 P- z# z Z$ G4 T4 b1 n) r1 t( n, F7 W n
四、两种操作分析9 | ^7 l7 S- v9 G8 ]" y0 t% B
3 h) |# i9 y4 m 1、FACTORY RESET(恢复出厂设置)
" ?- y& e7 W$ r; ] J2 i) M 1)用户选择“恢复出厂设置”' e. l; l) c* |# s. K; G
2)设置系统将"--wipe_data"命令写入/cache/recovery/command
6 b+ W$ S' o2 ], r. {$ W 3)系统重启,并进入recover模式(/sbin/recovery)4 o1 S$ a. n1 l, f0 v a$ r
4)get_args() 将 "boot-recovery"和"--wipe_data"写入BCB(Bootloader Control Block) 2 N& i7 A6 E& f0 M6 Q2 i* O% t
5)erase_root() 格式化(擦除)DATA分区
" T. x; G0 s5 h$ {5 q 6)erase_root() 格式化(擦除)CACHE分区
5 q4 r0 Q: h' P/ _: ] 7)finish_recovery() 擦除BCB# B/ n2 _. Z6 a! o5 f3 o z
8)重启系统$ w& J0 X" M) k' c9 K2 ~
7 U* ]& {0 E4 P& A5 X' Q2 X9 H 2、OTA INSTALL(OTA升级)$ O V: ?- ?1 y' U: ]5 o
1)升级系统下载OTA包到/cache/some-filename.zip
; s! ^ j2 ^) L" ~6 y 2)升级系统写入recovery命令"--update_package=CACHE:some-filename.zip"/ d3 f% c" {' p
3)重启,并进入recovery模式7 k7 N4 j$ E3 ]! Q: {) n4 ~
4)get_args() 将"boot-recovery" 和 "--update_package=..." 写入BCB& U4 R! D7 e1 m6 j4 ^- O
5)install_package() 作升级' v! C8 F$ g9 S0 T( [5 S; y
6)finish_recovery() 擦除 BCB
* F* U/ f9 V7 M& z 7)** 如果安装包失败 ** prompt_and_wait() 等待用户操作,选择ALT+S或ALT+W 升级或恢复出厂设置4 Y& y8 _. o9 |" M$ \5 h
8)main() 调用 maybe_install_firmware_update()5 s) b" D1 F- J/ F b( N
8.1) 如果包里有hboot/radio的firmware则继续,否则返回& }# L0 K' Q- I% B$ g% I8 h
8.2) 将 "boot-recovery" 和 "--wipe_cache" 写入BCB
; E, p6 Y @. g5 W3 c 8.3) 将 firmware image写入cache分区: W& q4 K" x s y, i
8.4) 将 "update-radio/hboot" 和 "--wipe_cache" 写入BCB, M7 G1 j9 a2 Y' E* F
8.5) 重启系统
0 t" Z' f8 o. a 8.6) bootloader自身更新firmware
+ }5 d0 p7 p2 @: z3 \ 8.7)bootloader 将 "boot-recovery" 写入BCB
% x5 ]+ {2 S% F! S5 d( m, a6 ~% O 8.8)erase_root() 擦除CACHE分区& S+ w7 s) U, I6 K% A) N2 o
8.9)清除 BCB
6 z/ g$ ^1 Y* T' P 9)main() 调用 reboot() 重启系统
" n7 E e% B3 U/ D3 M0 Y0 m1 c- b1 a( z* K0 @1 i1 {
五、Recovery模式流程
3 p5 @2 h* e8 l' G' ?6 `2 U
. h3 T( H% S% I /init → init.rc → /sbin/recovery →
9 H7 [0 ^$ W' T9 Q/ f9 [ l. v6 f% ` v0 v' Y4 S
main():recovery.c:
8 V/ W$ p- G1 F% E' z3 _5 q& @% F ui_init():ui.c [UI initialize]
+ G0 s' O! A6 d gr_init():minui/graphics.c [set tty0 to graphic mode, open fb0]
k- x( ]' G, j ev_init():minui/events.c [open /dev/input/event*]
+ r, Z F+ o) Z+ e* R$ U res_create_surface:minui/resource.c [create surfaces for all bitmaps used
: U- Q. r6 o8 D2 n later, include icons, bmps]+ \& l. [. m1 [1 j# J
create 2 threads: progress/input_thread [create progress show and input event
" T3 s& o* M& |) e. D& a/ g handler thread]
* V; @% q A5 l get_args():recovery.c
) H! l# J* o1 ?1 W0 S) x _ get_bootloader_message():bootloader.c [read mtdblock0(misc partition) 2nd page
" J& G0 u: P2 n for commandline]
; s6 Z! D* X1 }; l+ ^: T check if nand misc partition has boot message. If yes, fill argc/argv.$ {- ]9 v" W) ?( b" }, u
If no, get arguments from /cache/recovery/command, and fill argc/argv.
8 M0 [9 j: { U# \ set_bootloader_message():bootloader.c[set bootloader message back to mtdblock0]
) q* `6 m8 U$ H Parser argv[] filled above F6 T& _. [1 _5 q7 p4 H( R
register_update_commands():commands.c [ register all commands with name + m2 C% v' v( b! b0 W8 v
and hook function ]
2 f2 A( m! G+ P; Y& H- k% k registerCommand():commands.c
9 n* `2 C& ^% _3 Z* F1 Y6 H Register command with name, hook, type, cookie.
# B, T+ b" _0 i, E! g8 ~3 O: D Commands, e.g: assert, delete, copy_dir, symlink, write_raw_image.
. Q3 H, j. k1 w C* x registerFunction():commands.c
% S4 W# B; l' S/ q3 |$ r" S8 V Register function with name, hook, cookie.
7 o1 L' w3 w0 [5 R) }; p1 s7 k" Z( j Function, e.g: get_mark, matches, getprop, file_contains( w- a+ i, i, [9 p( F( v
install_package():8 G" @9 S* N2 W- `" y
translate_root_path():roots.c [ "SYSTEM:lib" and turns it into a string l8 ^( j! R& O
like "/system/lib", translate the updater.zip path ]7 Z2 H" H: J+ I; u. {: E; c7 d9 K
mzOpenZipArchive():zip.c [ open updater.zip file (uncompass) ]
+ T+ X/ r; k9 T handle_update_package():install.c( h& {3 [. c# x6 D
verify_jar_signature():verifier.c [ verify signature with keys.inc key; verify
; _: m3 T5 K# T manifest and zip package archive ]" x3 H9 g0 g& y N7 I
verifySignature() [ verify the signature file: CERT.sf/rsa. ]& F9 M! T9 h }# P! `
digestEntry():verifier.c [ get SHA-1 digest of CERT.sf file ]
4 M. H* b& ^$ O( h6 M% T; \% I, P RSA_verify(public key:keys.inc, signature:CERT.rsa, CERT.sf's digest):/ m. D. z' ?. w7 c/ h+ s3 T
libc/rsa.c [ Verify a 2048 bit RSA PKCS1.5 signature against an expected . P/ b* P* r+ q
SHA-1 hash. Use public key to decrypt the CERT.rsa to get
! `3 `; ?& a' D3 f original SHA digest,then compare to digest of CERT.sf ]
3 w2 p) G# z, O, d$ d) k" | verifyManifest() [ Get manifest SHA1-Digest from CERT.sf. Then do digest to + `; y$ Z2 Y% Y: ^) o4 [9 o
MANIFEST.MF.Compare them ]
# O$ P: z, P0 n8 C+ F verifyArchive() [ verify all the files in update.zip with digest listed in 0 ]( A4 B8 `. T7 `/ c# g l- c
MANIFEST.MF ]7 i+ |1 G/ W! _2 V
find_update_script():install.c [ find META-INF/com/google/android/update-
! e& o0 K7 t2 o script updater script ]
! H( s4 \: v4 C/ g7 H( {' X handle_update_script():install.c [ read cmds from script file, and do parser,
: p: F4 p: u6 l+ W8 d& e exec ]( t& m6 H. R# l
parseAmendScript():amend.c [ call yyparse() to parse to command ]
; l4 k' |8 C& n2 P# j exeCommandList():install.c; L+ p) F" @, K7 U% g, c& x' K
exeCommand():execute.c [ call command hook function ]/ k- u6 T6 e0 A3 ~3 X
erase DATA/CACHE partition
9 B6 G- I6 m- i. g. |" U2 C6 ] prompt_and_wait():recovery.c [ wait for user input: 1) reboot 2) update.zip - S/ g. o# z, r. [) X3 q
3)wipe data ]
) w2 O5 R% P" f& x! ~6 e3 R* `* x+ f ui_key_xxx get ALT+x keys! [) i2 @* f0 g1 v1 t) O6 S/ B; ^8 t
1) do nothing
" M9 V) W& R# U! c4 n 2) install_package('SDCARD:update.zip')
$ C- v( r" y1 m4 Q; E% j 3) erase_root() → format_root_device() DATA/CACHE3 D2 X' H; t* r, \
may_install_firmware_update():firmware.c [ remember_firmware_update() is
7 Q7 l; h+ T R- I% L called by write_hboot/radio_image command, it stores the bootloader image
! Z1 V1 T# q- Q5 T- n# x3 h to CACHE partition, and write update-hboot/radio command to MISC partition
$ N7 \/ K5 K) E' f for bootloader message to let bootloader update itself after reboot ]
6 V# z! s* E/ v% O: d& n set_bootloader_message(); W; q/ o5 [9 j# v
write_update_for_bootloader():bootloader.c [ write firmware image into CACHE ( n! m$ ^: G7 t) B0 [# B' E9 L# l
partition with update_header, busyimage and failimage ]8 j: N& Q, J2 g! ]1 c& U# k
finish_recovery():recovery.c [ clear the recovery command and prepare to
h2 w. P$ R; v1 n" e# Z7 W: l- b5 O boot a (hopefully working) system, copy our log file to cache as well (for
" Q& y @ N: \ the system to read), and record any intent we were asked to communicate back
, b* q7 o( K0 k: j' `1 g to the system. ]. X: R) j4 a* E( D3 N$ s
! @8 [: ^# l$ X1 I% O
reboot()0 N% Y6 d5 X2 H
: ]- m3 N6 N4 o2 i8 D- ]# T+ h; q8 F- r( Q8 u/ F
% [7 X& }( y" b+ A* i
六、Recovery模式流程图
# o+ f5 ?/ Y7 h9 G6 ]& |) j以下流程图绘制了系统从启动加载bootloader后的行为流程。
, r8 ~3 z2 C* z3 b( B$ N
' N1 j4 R7 f; [5 o6 x5 T
$ ?: m& R, J M2 ?1 D# d" j: a
http://www.anzhuoba.com/thread-5985-1-1.html