1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
目的 ................................................................................................... 错误!未定义书签。 适用范围 ........................................................................................... 错误!未定义书签。 参考文档 ........................................................................................... 错误!未定义书签。 缩写 ................................................................................................... 错误!未定义书签。 名词定义 ........................................................................................... 错误!未定义书签。 Recovery简介 .................................................................................................................... 2 Android手机一般有三种启动模式 ................................................................................. 2 Recovery涉及到的其他系统及文件 ................................................................................ 2 Recovery Case .................................................................................................................... 3 “apply update from sdcard”功能详解 ............................................................................ 4 Recovery模式流程 ............................................................................................................ 6 Recovery模式流程图 (网络上的参考流程) ................................................................... 9
1. Recovery简介
Android利用Recovery模式,进行恢复出厂设置,OTA升级,patch升级及firmware升级。
升级一般通过运行升级包中的META-INF/com/google/android/update-script脚本来执行自定义升级,脚本中是一组recovery系统能识别的UI控制,文件系统操作命令,例如write_raw_image(写FLASH分区),package_extract_dir(复制目录)。该包一般被下载至SDCARD和CACHE分区下。升级中还涉及到包的数字签名,签名方式和普通JAR文件签名差不多。公钥会被硬编译入recovery,编译时生成在:
out/target/product/brownstone/obj/PACKAGING/ota_keys_inc_intermediates/keys.inc Recovery功能实现主要需要的模块有:
1、 framework/base/core层:Power.java、PowerManager.java和Recoverysystem.java
等上层文件来管理和记录和Recovery有关的上层操作,例如FACTORY RESET和OTA升级。
2、 framework jni层主要有android_os_power.cpp提供上层OTA升级和RBOOT接
口函数。
3、 recovery系统层:实现recovery的具体操作。
4、 boot下brownstone.c通过判断按键信息和内存信息来确定启动方式,引导进入
recovery模式。
2. Android手机一般有三种启动模式
启动过程中通过boot下得brownstone.c中的magic_test()函数读取按键信息和上层写入的command来确定启动模式
MAGIC KEY:
menu + power:bootloader进入fastboot模式(也有使用camera + power来实
现的)
home + power:进入recovery模式 正常启动
Bootloader正常启动,又有三种方式,按照BCB(Bootloader Control Block)的command分类:
command == 'boot-recovery' → 启动recovery.img进入recovery模式 command == 'update-firmware' → 更新firmware(bootloader) 其他 → 启动boot.img
3. Recovery涉及到的其他系统及文件
CACHE分区文件
Recovery 工具通过NAND cache分区上的三个文件和主系统打交道。主系统(包括恢复出厂设置和OTA升级)可以写入recovery所需的命令,读出recovery过程中的LOG和intent。/cache/recovery/command: recovery命令,由主系统写入。所有命令如下:
--send_intent=anystring - write the text out to recovery.intent
--update_package=root:path - verify install an OTA package file --wipe_data - erase user data (and cache), then reboot --wipe_cache - wipe cache (but not user data), then reboot /cache/recovery/log:recovery过程日志,由主系统读出 /cache/recovery/intent:recovery输出的intent MISC分区内容
Bootloader Control Block (BCB) 存放recovery bootloader message。结构如下: struct bootloader_message { char command[32];
char status[32]; // 还未完全搞懂此变量的用途 char recovery[1024]; };
command可以有以下两个值 “boot-recovery”:标示recovery正在进行,或指示bootloader应该进入recovery mode “update-firmware”:由Recovery写入指示bootloader更新firmware recovery内容 “recovery\\n
其中recovery command为CACHE:/recovery/command命令 4. Recovery Case FACTORY RESET(恢复出厂设置) 1. 用户选择“恢复出厂设置” 2. 设置系统将\"--wipe_data\"命令写入/cache/recovery/command 3. 系统重启,并进入recover模式 4. get_args() 将 \"boot-recovery\"和\"--wipe_data\"写入BCB 5. erase_root() 格式化(擦除)DATA分区 6. erase_root() 格式化(擦除)CACHE分区 7. finish_recovery() 擦除BCB 8. 重启系统 OTA INSTALL(OTA升级) 1. 升级系统下载 OTA包到/cache/update.zip 2. 升级系统写入recovery命令\"--update_package=CACHE:update.zip\" 3. 重启,并进入recovery模式 4. get_args() 将\"boot-recovery\" 和 \"--update_package=...\" 写入BCB 5. install_package() 作升级 6. finish_recovery() 擦除 BCB 7. ** 如果安装包失败 ** prompt_and_wait() 等待用户操作,选择ALT+S或 ALT+W 升级或恢复出厂设置 8. main() 调用 maybe_install_firmware_update() 1) 如果包里有hboot/radio的firmware则继续,否则返回 2) 将 \"boot-recovery\" 和 \"--wipe_cache\" 写入BCB 3) 将 firmware image写入cache分区 4) 将 \"update-radio/hboot\" 和 \"--wipe_cache\" 写入BCB 5) 重启系统 6) bootloader自身更新firmware 7) bootloader 将 \"boot-recovery\" 写入BCB 8) erase_root() 擦除CACHE分区 9) 清除 BCB 9. main() 调用 reboot() 重启系统 Recovery 模式 开机过程中按住home+power键 Boot启动过程中判断magic_test()函数读取按键信息,选择启动Recovery 进入Recovery并通过ui显示Recovery功能选项: \"reboot system now\//用于重启系统 \"apply update from sdcard\ //通过sdcard卡的升级 \"wipe data/factory reset\擦出用户信息恢复出厂设置 \"wipe cache partition\ //清楚缓存 选择相应功能 系统进入recovery操作 5. “apply update from sdcard”功能详解 从ar0922e_gingerbread_beta1编译好的代码码树中提取一个update.zip所需要的所有资源, 从而最终构建一个可以在android recovery模式下刷机的update.zip包. 建立如下的update目录(用于生成update.zip): |\e\\ |-- META-INF | `-- com | `-- google | `-- android | |-- update-binary | `-- updater-script |-- system update-binary: 二进制文件, 相当于一个脚本解释器, 能识别 updater-script 中描述的操作。该文件由 ar0922e_gingerbread_beta1/out/target/product/brownstone/system/bin/updater重命名所得。具体用什么名字是由 ar0922e_gingerbread_beta1/bootable/recovery/install.c 文件中的宏 ASSUMED_UPDATE_BINARY_NAME 的值而定. updater-script: 该文件需要自己根据更新包需要更新的内容自行编写. 具体用什么名字是由 ar0922e_gingerbread_beta1/bootable/recovery/updater/updater.c 文件中的宏 SCRIPT_NAME 的值而定.(注意: 是updater-script, 而不是 update-script). system: 该目录下放需要更新的内容. 比如,只是需要添加几个系统软件, 则在此目录下添加一个 app 目录, 然后把待添加的系统软件copy进来即可. 如果你是要制作一个系统更新包. 那ar0922e_gingerbread_beta1/out/target/product/brownstone/system/ 中的所有文件copy到这个目录里来. ps:具体添加文件的名字和路径要和updater-script脚本相同。 一个更新包update.zip的制作步骤 $mkdir update ps:在任意目录下,创建一个叫update的目录 $cd upadte ps: 进入该目录 $mkdir –p META-INF/com/google/android/ && mkdir system ps:在update目录下, 创建2个子目录 $cp ar0922e_gingerbread_beta1/out/target/product/brownstone/system/bin/updater META-INF/ com/google/android/update-binary ps:获取update-binary文件 $cp ar0922e_gingerbread_beta1/out/target/product/brownstone /ramdisk.img ps: 获取更新ramdisk所需要的文件 $vim META-INF/com/google/android/updater-script ps:打开updater-script脚本, 根据需要更新的内容开始编写更新过程. $zip -qr ../update.zip ./ ps: 编辑完updater-script脚本后, 把update内的所有内容打成一个update.zip包. $java –jar ar0922e_gingerbread_beta1/out/host/linux-x86/framework/signapk.jar –w ar0922e_gingerbread_beta1/build/target/product/security/testkey.x509.pem /testkey.pk8 update.zip update_signed.zip 通过这条命令, 会对update.zip包进行签名, 然后输出一个update_signed.zip的签好名update包. 以此作为最终更新包。 这条命令需要5个条件: host机需装有java环境, ubuntu上为 sun-java5-jdk DEB包 signapk.jar 文件. 在编译好的 ar0922e_gingerbread_beta1/out/host/linux-x86/framework目录下 testkey.x509.pem 在源码的 ar0922e_gingerbread_beta1/build/target/product/security 目录下 testkey.pk8 在编译好的 ar0922e_gingerbread_beta1/build/target/product/security 目录下 update.zip 没有经过签名的ZIP包. PS:也可以使用签名工具进行签名。 updater-script 脚本的编写 updater-script 的内容其实为一行一行update-binery能识别的命令序列. 文件 ar0922e_gingerbread_beta1/bootable/recovery/update/install.c 末尾描述了所有可执行命令.部分命令的使用实例: mount : eg : mount(“MTD”, “system”, “/system”); 挂在 MTD的system分区到文件系统的 /system 目录下. ui_print : eg : ui_print(“Hello word!”); 在屏幕上打印提示信息. format : eg : format(“MTD”, “system”); 格式化MTD的system分区 package_extract_dir : eg : package_extract_dir(“system”, “/system”); 把update包中system中的内容全部拷贝到文件系统/system下 特别说明:固件升级(boot和radio)和其他软件升级的脚本有所不同,具体在“11.Recovery 模式流程”中详述。 6. Recovery模式流程 /init → init.rc → /sbin/recovery → main():recovery.c //main入口 ui_init():ui.c [UI initialize] //ui显示初始化 o gr_init():minui/graphics.c //set tty0 to graphic mode, open fb0// o ev_init():minui/events.c //open /dev/input/event*// o res_create_surface:minui/resource.c //create surfaces for all bitmaps used later, include icons, bmps// o create 2 threads: progress/input_thread //create progress show and input event handler thread// get_args():recovery.c //读取系统资源和信息 nd o get_bootloader_message():bootloader.c //read mtdblock0(misc partition) 2 page for commandline// o check if nand misc partition has boot message. If yes, fill argc/argv. o If no, get arguments from /cache/recovery/command, and fill argc/argv. o set_bootloader_message():bootloader.c //set bootloader message back to mtdblock0// Parser argv[] filled above register_update_commands():commands.c //注册系统命令 o registerCommand():commands.c Register command with name, hook, type, cookie. Commands, e.g: assert, delete, copy_dir, symlink, write_raw_image. o registerFunction():commands.c Register function with name, hook, cookie. Function, e.g: get_mark, matches, getprop, file_contains install_package(): //升级包安装 o translate_root_path():roots.c //EM:lib\" and turns it into a string like \"/system/lib\ mzOpenZipArchive():zip.c //open updater.zip file// o handle_update_package():install.c verify_jar_signature():verifier.c //verify signature with keys.inc key,verify manifest and zip package archive// verifySignature() //verify the signature file: CERT.sf/rsa.// digestEntry():verifier.c //get SHA-1 digest of CERT.sf file// RSA_verify(public key:keys.inc, signature:CERT.rsa, CERT.sf's digest):libc/rsa.c //Verify a 2048 bit RSA PKCS1.5 signature against an expected SHA-1 hash. Use public key to decrypt the CERT.rsa to get original SHA digest, then compare to digest of CERT.sf// verifyManifest() //Get manifest SHA1-Digest from CERT.sf. Then do digest to MANIFEST.MF. Compare them// verifyArchive() //verify all the files in update.zip with digest listed in MANIFEST.MF// find_update_script():install.c //find META-INF/com/google /android/updater script// handle_update_script():install.c // read cmds from script file, and do parser, exec// parseAmendScript():amend.c //call yyparse() to parse to command// exeCommandList():install.c exeCommand():execute.c //call command hook function// erase DATA/CACHE partition //擦出用户DATA和CACHE prompt_and_wait():recovery.c //wait for user select: 1) reboot 2) update.zip 3) wipe data/factory reset 4)wipe cach)// o 1) do nothing but reboot o 2) install_package('SDCARD:update.zip') o 3) erase_root() → format_root_device() DATA/CACHE o 4) only erase the CACHE o //****************************固件升级部分详述**********************start // ForUpdateFirmwareFn():\\bootable\\recovery\er\\install.c //is called by “mrvl_for_update_firmware()” command in the updater-script to stores the bootloader image to mmcblk0p11 partition, and write “update-firmware” command to MISC partition for bootloader message to let bootloader update itself after reboot o strlcpy(boot.command, \"update-firmware\“update-firmware”bootcommand to step to obm_update() in boot// o copy_bootfile_to_device(char* filename, char* devicename, int offset) //copy the file which used to update-firmware from \\cache\\ to the mmcblk0p11 ,a partition only used to update-firmware // reboot(RB_AUTOBOOT); // Perform a hard reset now// //-----在与Recovery配合update-firmware 的boot函数----start// obm_update():\\boot\\\board\\marvell\\brownstone.c //only in the bootloader// o mmc->block_dev.block_read(0, NTIM_BLK_ADDR, 3, buffer) //read the boot image from mmcblk0p11 to buffer// o mmc->block_dev.block_write(0, PARTITION_BURN_ADDR, 1, buffer) //burn the boot image to the boot address in emmc from buffer// //--在与Recovery配合update-firmware 的boot函数--end// o //****************************固件升级部分详述**********************end// finish_recovery():recovery.c //clear the recovery command and prepare to boot a (hopefully working) system, copy our log file to cache as well (for the system to read), and record any intent we were asked to communicate back to the system. // reboot() // 7. Recovery模式流程图 (网络上的参考流程) 以下流程图绘制了系统从启动加载bootloader后的行为流程。 因篇幅问题不能全部显示,请点此查看更多更全内容