本文来自:http://blog.sina.com.cn/s/blog_6b26569e0100ssgm.html
Android的开机流程
分类: Android
转:
1. 体系勾引bootloader
1) 源码:bootable/bootloader/*
2) 申明:加电后,CPU将先履行bootloader法度,此处有三种选择
a) 开机按Camera+Power启动到fastboot,即号令或SD卡烧写模式,不加载内核及文件体系,此处可以进行工厂模式的烧写
b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.img包含内核,根蒂根基的文件体系,用于工程模式的烧写
c) 开机按Power,正常启动体系,加载boot.img,boot.img包含内核,根蒂根基文件体系,用于正常启下手机(以下只解析正常启动的景象)
2. 内核kernel
1) 源码:kernel/*
2) 申明:kernel由bootloader加载
3. 文件体系及应用init
1) 源码:system/core/init/*
2) 设备文件:system/core/rootdir/init.rc,
3) 申明:init是一个由内核启动的用户级过程,它遵守init.rc中的设置履行:启动办事(这里的办事指linux底层办事,如adbd供给adb支撑,vold供给SD卡挂载等),履行号令和按此中的设备语句履行响应功能
4. 首要的后台法度zygote
1) 源码:frameworks/base/cmds/app_main.cpp等
2) 申明:zygote是一个在init.rc中被指定启动的办事,该办事对应的号令是/system/bin/app_process
source (service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start- system-server
socket zygote stream 666)
a) 建树Java Runtime,建树虚拟机
b) 建树Socket接管ActivityManangerService的恳求,用于Fork应用法度
c) 启动System Server
5. 体系办事system server
1) 源码:frameworks/base/services/java/com/android/server/SystemServer.java
2) 申明:被zygote启动,经由过程System Manager经管android的办事(这里的办事指frameworks/base/services下的办事,如卫星定位办事,剪切板办事等)
6. 桌面launcher
1) 源码:ActivityManagerService.java为进口,packages/apps/launcher*实现
2) 申明:体系启动成功后SystemServer应用xxx.systemReady()通知各个办事,体系已经伏贴,桌面法度Home就是在ActivityManagerService.systemReady()通知的过程中建树的,终极调用startHomeActivityLocked()启launcher
7. 解锁
1) 源码:
frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
2) 申明:体系启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,终极经由过程LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上画图,其代码了存放在特别的地位
8. 开机自启动的第三方应用法度
1) 源码:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
2) 申明:体系启动成功后SystemServer调用ActivityManagerNative.getDefault().systemReady()通知ActivityManager启动成功,ActivityManager会经由过程置变量mBooting,通知它的另一线程,该线程会发送广播android.intent.action.BOOT_COMPLETED以告诉已注册的第三办法度在开机时主动启动。
9. 总结
综上所述,体系层次关于启动最核心的项目组是zygote(即app_process)和system server,zygote它负责最根蒂根基的虚拟机的建树,以支撑各个应用法度的启动,而system server用于经管android后台办事,启动步调及次序。
(end)
本文来自:http://blog.csdn.net/omg_2012/article/details/7875093
android recovery模式及ROM建造
转载时请注明出处和作者
文章出处:http://www.cnblogs.com/xl19862005
作者:Xandy
1 总述
为了便利客户日后的固件进级,本周研究了一下android的recovery模式。网上有不少这类的材料,但都斗劲错杂,没有一个体系的介绍与熟悉,在这里将网上所找到的和本身经由过程查阅代码所把握的器材收拾出来,给大师一个参考!
2 Android启动过程
在这里有须要理一下android的启动过程:
图1 android启动过程
体系上电之后,起首是完成一系列的初始化过程,如cpu、串口、中断、timer、DDR等等硬件设备,然后接着加载boot default environmet,为后面内核的加载作好筹办。在一些体系启动须要的初始完成之后,将断定是否要进入recovery模式,从图1中可以看出,进入recovery模式有两种景象。一种是检测到有组合按键按下时;另一种是检测到cache/recovery目次下有command这个文件,这个文件有内容有它特定的格局,将在后面讲到。
3 Uboot启动
下面来看看uboot中lib_arm/board.c这个文件中的start_armboot这个函数,这个函数在start.s这个汇编文件中完成客栈等一些根蒂根基动作之后被调用,进入到c的代码中,start_armboot项目组代码如下:
void start_armboot (void)
{
.
.
.
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
#ifdef CONFIG_ANDROID_RECOVERY
check_recovery_mode();
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
}
init_sequence是一个函数布局体指针,里面存放的是一些必备的初始化函数,其代码如下:
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
我们来看看env_init这个函数,其代码如下:
int env_init(void)
{
/* use default */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
#ifdef CONFIG_DYNAMIC_MMC_DEVNO
extern int get_mmc_env_devno(void);
mmc_env_devno = get_mmc_env_devno();
#else
mmc_env_devno = CONFIG_SYS_MMC_ENV_DEV;
#endif
return 0;
}
可以看出在这里将default_environment加载进入体系,default_environment对应的项目组代码如下:
uchar default_environment[] = {
.
.
.
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
""
};
而CONFIG_EXTRA_ENV_SETTINGS则是在我们对应的BSP的头文件中定义了,如下:
#define CONFIG_EXTRA_ENV_SETTINGS
"netdev=eth0"
"ethprime=FEC0"
"bootfile=uImage"
"loadaddr=0 x70800000"
"rd_loadaddr=0 x70D00000"
"bootargs=console=ttymxc0 init=/init "
"androidboot.console=ttymxc0 video=mxcdi1fb:RGB666,XGA "
"ldb=di1 di1_primary pmem=32M,64M fbmem=5M gpu_memory=64M"
"bootcmd_SD=mmc read 0 ¥{loadaddr} 0 x800 0 x2000;"
"mmc read 0 ¥{rd_loadaddr} 0 x3000 0 x300"
"bootcmd=run bootcmd_SD; bootm ¥{loadaddr} ¥{rd_loadaddr}"
再来看看check_recovery_mode这个函数中的代码,具体代码如下:
/* export to lib_arm/board.c */
void check_recovery_mode(void)
{
if (check_key_pressing())
setup_recovery_env();
else if (check_recovery_cmd_file()) {
puts("Recovery command file founded! ");
setup_recovery_env();
}
}
可以看到在这里经由过程check_key_pressing这个函数来检测组合按键,当有对应的组合按键按下时,将会进入到recovery模式,这也恰是各大android论坛里讲到刷机时都邑提到的power+音量加键进入recovery模式的原因。那么check_recovery_cmd_file又是在什么景象下履行的呢?这个也恰是这篇文章所要讲的内容之处。
先来看看check_recovery_cmd_file这个函数中的如下这段代码:
int check_recovery_cmd_file(void)
{
.
.
.
switch (get_boot_device()) {
case MMC_BOOT:
case SD_BOOT:
{
for (i = 0; i < 2; i++) {
block_dev_desc_t *dev_desc = NULL;
struct mmc *mmc = find_mmc_device(i);
dev_desc = get_dev("mmc", i);
if (NULL == dev_desc) {
printf("** Block device MMC %d not supported ", i);
continue;
}
mmc_init(mmc);
if (get_partition_info(dev_desc, CONFIG_ANDROID_CACHE_PARTITION_MMC,
&info)) {
printf("** Bad partition %d ** ",CONFIG_ANDROID_CACHE_PARTITION_MMC);
continue;
}
part_length = ext2fs_set_blk_dev(dev_desc, CONFIG_ANDROID_CACHE_PARTITION_MMC);
if (part_length == 0) {
printf("** Bad partition - mmc %d:%d ** ", i, CONFIG_ANDROID_CACHE_PARTITION_MMC);
ext2fs_close();
continue;
}
if (!ext2fs_mount(part_length)) {
printf("** Bad ext2 partition or "
"disk - mmc %d:%d ** ",
i, CONFIG_ANDROID_CACHE_PARTITION_MMC);
ext2fs_close();
continue;
}
filelen = ext2fs_open(CONFIG_ANDROID_RECOVERY_CMD_FILE);
ext2fs_close();
break;
}
}
break;
.
.
.
}
首要来看看下面这个ext2fs_open所打开的内容,CONFIG_ANDROID_RECOVERY_CMD_FILE,这个恰是上方所提到的rocovery cmd file的宏定义,内容如下:
#define CONFIG_ANDROID_RECOVERY_CMD_FILE "/recovery/command"
当检测到有这个文件存在时,将会进入到setup_recovery_env这个函数中,其响应的代码如下:
void setup_recovery_env(void)
{
char *env, *boot_args, *boot_cmd;
int bootdev = get_boot_device();
boot_cmd = supported_reco_envs[bootdev].cmd;
boot_args = supported_reco_envs[bootdev].args;
if (boot_cmd == NULL) {
printf("Unsupported bootup device for recovery ");
return;
}
printf("setup env for recovery.. ");
env = getenv("bootargs_android_recovery");
/* Set env to recovery mode */
/* Only set recovery env when these env not exist, give user a
* chance to change their recovery env */
if (!env)
setenv("bootargs_android_recovery", boot_args);
env = getenv("bootcmd_android_recovery");
if (!env)
setenv("bootcmd_android_recovery", boot_cmd);
setenv("bootcmd", "run bootcmd_android_recovery");
}
在这里主如果将bootcmd_android_recovery这个景象变量加到uboot启动的environment中,如许当体系启动加载完root fs之后将不会进入到android的system中,而是进入到了recovery这个轻量级的小UI体系中。
下面我们来看看为什么在uboot的启动景象变量中参加bootcmd_android_recovery这些启动参数的时辰,体系就会进入到recovery模式下而不是android system,先看看bootcmd_android_recovery响应的参数:
#define CONFIG_ANDROID_RECOVERY_BOOTARGS_MMC
"setenv bootargs ¥{bootargs} init=/init root=/dev/mmcblk1p4"
"rootfs=ext4 video=mxcdi1fb:RGB666,XGA ldb=di1 di1_primary"
#define CONFIG_ANDROID_RECOVERY_BOOTCMD_MMC
"run bootargs_android_recovery;"
"mmc read 0 ¥{loadaddr} 0 x800 0 x2000;bootm"
可以看到在进入recovery模式的时辰这里把root的分区设置成了/dev/mmcblk1p4,再来看看在体系烧录的时辰对全部SD卡的分区如下:
sudo mkfs.vfat -F 32 ¥{NODE}¥{PART}1 -n sdcards
sudo mkfs.ext4 ¥{NODE}¥{PART}2 -O ^extent -L system
sudo mkfs.ext4 ¥{NODE}¥{PART}4 -O ^extent -L recovery
sudo mkfs.ext4 ¥{NODE}¥{PART}5 -O ^extent -L data
sudo mkfs.ext4 ¥{NODE}¥{PART}6 -O ^extent -L cache
这里NODE = /dev/mmcblk1为挂载点,PART = p或者为空,作为分区的检测。可以看出上方在给recovery分区的时辰,用的是/dev/mmcblk1p4这个分区,所以当设置了recovery启动模式的时辰,root根目次就被挂载到/dev/mmcblk1p4这个recovery分区中来,从而进入recovery模式。
4 recovery
关于android的recovery网上有各类版本的定义,这里我总结一下:所谓recovery是android下参加的一种特别工作模式,有点类似于windows下的gost,体系进入到这种模式下时,可以在这里经由过程按键选择响应的操纵菜单实现响应的功能,比如android体系和数据区的快速格局化(wipe);体系和用户数据的备份和恢复;经由过程sd卡刷新的rom等等。典范的recovery界面如下:
图2 recovery界面
Recovery的源代码在bootable/recovery这个目次下面,首要来看看recovery.c这个文件中的main函数:
Int main(int argc, char **argv) {
.
.
.
ui_init();
ui_set_background(BACKGROUND_ICON_INSTALLING);
load_volume_table();
.
.
.
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
switch (arg) {
case ""p"": previous_runs = atoi(optarg); break;
case ""s"": send_intent = optarg; break;
case ""u"": _package = optarg; break;
case ""w"": wipe_data = wipe_cache = 1; break;
case ""c"": wipe_cache = 1; break;
case ""e"": encrypted_fs_mode = optarg; toggle_secure_fs = 1; break;
case ""t"": ui_show_text(1); break;
case ""?"":
LOGE("Invalid command argument ");
continue;
}
}
device_recovery_start();
.
.
.
if (_package)
{
// For backwards compatibility on the cache partition only, if
// we""re given an old ""root"" path "CACHE:foo", change it to
// "/cache/foo".
if (strncmp(_package, "CACHE:", 6) == 0)
{
int len = strlen(_package) + 10;
char* modified_path = malloc(len);
strlcpy(modified_path, "/cache/", len);
strlcat(modified_path, _package+6, len);
printf("(replacing path "%s" with "%s") ",
_package, modified_path);
_package = modified_path;
}
//for "/mnt/sdcard/.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
//ui_print("before:[%s] ",_package);
if (strncmp(_package, "/mnt", 4) == 0)
{
//jump the "/mnt"
_package +=4;
}
ui_print("install package [%s] ",_package);
}
printf(" ");
property_list(print_property, NULL);
printf(" ");
int status = INSTALL_SUCCESS;
.
.
.
// Recovery strategy: if the data partition is damaged, disable encrypted file systems.
// This preventsthe device recycling endlessly in recovery mode.
.
.
.
if (_package != NULL)
{
status = install_package(_package);
if (status != INSTALL_SUCCESS)
ui_print("Installation aborted. ");
else
{
erase_volume("/data");
erase_volume("/cache");
}
} else if (wipe_data) {
if (device_wipe_data()) status = INSTALL_ERROR;
if (erase_volume("/data")) status = INSTALL_ERROR;
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
if (status != INSTALL_SUCCESS) ui_print("Data wipe failed. ");
} else if (wipe_cache) {
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed. ");
} else {
status = INSTALL_ERROR; // No command specified
}
if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
//Xandy modify for view the install infomation
//if (status != INSTALL_SUCCESS || ui_text_visible())
if(status != INSTALL_SUCCESS)
{
prompt_and_wait();
}
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);
ui_print("Rebooting... ");
sync();
reboot(RB_AUTOBOOT);
return EXIT_SUCCESS;
}
在这里起首完成recovery模式轻量级的UI体系初始化,设置靠山图片,然后对输入的参数格局化,最后按照输入的参数进行响应的操纵,如:安装新的ROM、格局化(wipe)data及cache分区等等;值得重视的是刷新ROM的时辰,要建造响应的.zip的安装包,这个在最后一章节讲述,这里碰到的一个题目是在recovery模式下sd卡的挂载点为/sdcard而不是android体系下的/mnt/sdcard,所以我在这里经由过程:
//for "/mnt/sdcard/.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
//ui_print("before:[%s] ",_package);
if (strncmp(_package, "/mnt", 4) == 0)
{
//jump the "/mnt"
_package +=4;
}
如许的操纵跳过了上层传过来的/mnt这四个字符。别的一个值得一提的是,传入这里的这些参数都是从/cache/recovery/command这个文件中提取。具体对command文件的解析过程这里不再讲述,可能经由过程查看recovery.c这个文件中的get_args函数。
那么command这个文件是在什么景象下创建的呢?下面我们就来看看吧!
5 恢复出厂设置和固件进级
在android的体系设备中进入“隐私权->恢复出厂设置->重置手机”将为进入到恢复出厂设置的状况,这时将会清除data、cache分区中的所有效户数据,使得体系重启后和刚刷机时一样了。别的为了便利操纵我们还可在“隐私权->固件进级->刷新ROM”这里参加了固件进级这一项。
在讲述这些内容之前,我们有须要来看看/cache/recovery/command这个文件响应的一些recovery号令,这些号令都由android体系写入。所有的号令如下:
* --send_intent=anystring ―― write the text out to recovery.intent
* --_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
5.1 恢复出厂设置
在frameworks/base/services/java/com/android/server/masterClearReceiver.java
这个文件中有如下代码:
public class MasterClearReceiver extends BroadcastReceiver {
private static final String TAG = "MasterClear";
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if (!"google.com".equals(intent.getStringExtra(""))) {
Slog.w(TAG, "Ignoring master clear request -- not trusted server.");
return;
}
}
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
if (intent.hasExtra("enableEFS")) {
RecoverySystem.rebootToggleEFS(context, intent.getBooleanExtra("enableEFS", false));
} else {
RecoverySystem.rebootWipeUserData(context);
}
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can""t perform master clear/factory reset", e);
}
}
};
thr.start();
}
}
当app中操纵了“恢复出厂设置”这一项时,将发出广播,这个广播将在这里被监听,然掉队入到恢复出厂设置状况,我们来看看rebootWipeUserData这个办法的代码:
public static void rebootWipeUserData(Context context) throws IOException {
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
context.sendOrderedBroadcast(intent, android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
condition.open();
}
}, null, 0, null, null);
// Block until the ordered broadcast has completed.
condition.block();
bootCommand(context, "--wipe_data");
}
我们可以看到在这里参入了“--wipe_data”这个参数,并把这条号令写入到command这个文件中去了,在进入recovery模式的时辰解析到这条号令时就会清除data和cache中的数据了。
再来看看bootCommand这个办法里的代码:
private static void bootCommand(Context context, String arg) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.(); // In case it""s not writable
LOG_FILE.();
FileWriter command = new FileWriter(COMMAND_FILE);
try {
command.write(arg);
command.write(" ");
} finally {
command.close();
}
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot("recovery");
throw new IOException("Reboot failed (no permissions?)");
}
此中COMMAND_FILE这个成员的定义如下:
/** Used to communicate with recovery. See bootable/recovery/recovery.c. */
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
至此恢复出厂设置的号令就写入了recovery cmd file中去了,经由过程pm.reboot(“recovery”);重启体系,体系就主动进入到recovery模式主动清除用户数据后再重启体系。
5.2 固件进级
固件进级的流程和恢复出厂设置差不久不多,不合之处是入command这个文件中写入的号令不一样,下面是恢复出厂设置时的写号令的代码:
public static void installPackage(Context context, File packageFile)
throws IOException {
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
String arg = "--_package=" + filename;
bootCommand(context, arg);
}
这里的packageFile是由上层app传入的,内容如下:
File packageFile = new File("/sdcard/.zip");
RecoverySystem.installPackage(context, packageFile);
如许当体系重启进入到recovery模式时将会主动查找sdcard的根目次下是否有.zip这个文件,若是有将会进入到状况,不然会提示无法找到.zip!
至此我们已经熟悉打听了android的全部recovery流程,下面将讲讲.zip也就是各大论坛里讲到的ROM的建造过程。
6 ROM的建造
我们解压.zip这个文件,可发明它一般打包了如下这几个文件:
图3 ROM包中的内容
或者没有s而是system这个目次,不合的原因是我这里在s里放置的是system.img等镜像文件,这些文件都由源码编译而来。而若是是system目次,这里一般放的是android体系的system目次下的内容,可所以全部android体系的system目次,也可所以此中的一项目组内容,如一些so库等等,如许为补丁的公布供给了一个很好的解决办法,不须要更新全部体系,只须要更新一项目组内容就可以了!
来看看META-INF/com/google/android这个目次下的内容,在这里就两个文件,一个是可履行的exe文件-binary,这个文件在进入状况的用于把握ROM的烧入,具体的代码在recovery下的install.c文件中的try__binary这个函数中;另一个是r-script,这个文件里是一些脚本法度,具体的代码如下:
# Mount system for check figurepoint etc.
# mount("ext4", "EMMC","/dev/block/mmcblk0p2", "/system");
# Make sure Check system image figurepoint first.
# uncomment below lines to check
# assert(file_getprop("/system/build.prop", "ro.build.fingerprint") == "freescale/imx53_evk/imx53_evk/imx53_evk:2.2/FRF85B/eng.b33651.20100914.145340:eng/test-keys");
# assert(getprop("ro.build.platform) == "imx5x");
# unmount("/system");
show_progress(0.1, 5);
package_extract_dir("s", "/tmp");
#Format system/data/cache partition
ui_print("Format disk...");
format("ext4","EMMC","/system");
format("ext4","EMMC","/data");
format("ext4","EMMC","/cache");
show_progress(0.2, 10);
# Write u-boot to 1K position.
# u-boot binary should be a no padding uboot!
# For eMMC(iNand) device, needs to unlock boot partition.
ui_print("writting u-boot...");
sysfs_file_write(" /sys/class/mmc_host/mmc0/mmc0:0001/boot_config", "1");
package_extract_file("files/u-boot.bin", "/tmp/u-boot.bin");
#ui_print("Clean U-Boot environment...");
show_progress(0.2, 5);
#simple_dd("/dev/zero","/dev/block/mmcblk0",2048);
simple_dd("/tmp/u-boot.bin", "/dev/block/mmcblk0", 2048);
#access user partition,and enable boot partion1 to boot
sysfs_file_write("/sys/class/mmc_host/mmc0/mmc0:0001/boot_config", "8");
#Set boot width is 8bits
sysfs_file_write("/sys/class/mmc_host/mmc0/mmc0:0001/boot_bus_config", "2");
show_progress(0.2, 5);
ui_print("extract kernel image...");
package_extract_file("files/uImage", "/tmp/uImage");
# Write uImage to 1M position.
ui_print("writting kernel image");
simple_dd("/tmp/uImage", "/dev/block/mmcblk0", 1048576);
ui_print("extract uramdisk image...");
package_extract_file("files/uramdisk.img", "/tmp/uramdisk.img");
# Write uImage to 1M position.
ui_print("writting uramdisk image");
simple_dd("/tmp/uramdisk", "/dev/block/mmcblk0", 6291456);
show_progress(0.2, 50);
# You can use two way to your system which using ext4 system.
# dd hole system.img to your mmcblk0p2 partition.
package_extract_file("files/system.img", "/tmp/system.img");
ui_print("upgrading system partition...");
simple_dd("/tmp/system.img", "/dev/block/mmcblk0p2", 0);
show_progress(0.1, 5);
响应的脚本指令可在申明可对应源码可在recovery包中的install.c这个文件中找到。
在bootable/recovery/etc下有原始版的脚本代码-script,但在recovery下的r.c这个文件中有如下定义:
// Where in the package we expect to find the edify script to execute.
// (Note it""s "R-script", not the older "-script".)
#define SCRIPT_NAME "META-INF/com/google/android/r-script"
地点应用这个原版的脚本的时辰要将-script更成r-script,须要重视!
我们可以发明在bootable/recovery/etcMETA-INFO/com/google/android目次下少了一个-binary的履行文件,在out/target/product/YOU_PRODUCT/system/bin下面我们可以找到r,只要将其重名字为-binary就可以了!
有了这些筹办工作,我们就可以开端建造一个我们本身的ROM了,具体步调如下:
* Xandy@ubuntu:~¥ mkdir recovery
* Xandy@ubuntu:~¥ cd recovery 然后将上方提到的bootable/recovery/etc下的所有内容拷贝到当前目次下并删掉init.rc这个文件
* 编译./META-INF/com/google/android/r-script这个文件使达到我们想要的烧写把握,若是是烧写system.img如许的镜像文件,可以直接用我上方提到的r-script这个脚本代码。
* 拷贝响应的须要建造成ROM的android文件到s目次或者system目次下,这个得按照体系的须要决意。
* Xandy@ubuntu:~/recovery¥ mkdir res
* Xandy@ubuntu:~/recovery¥ ~/myandroid/out/host/linux-x86/framework/dumpkey.jar ~/myandroid/build/target/product/security/testkey.x509.pem > res/keys 这里创建一个目次用于存储体系的key值
* zip /tmp/recovery.zip -r ./META-INF ./s ./res 将所有文件打包
* java -jar ./tools/signapk.jar -w ./tools/testkey.x509.pem ./tools/testkey.pk8 /tmp/recovery.zip .zip 我在recovery目次下创建了一个tools目次,里面放置了sygnapk.jar、testkey.pk8、testkey.x509.pem这几个文件用于java签名时用
经过上方这几步之后就会在recovery目次生成一个.zip的文件,这个就是我们本身建造的ROM文件,将它拷到sdcard的根目次下,在体系设置里操纵进入到“固件进级状况”,比及体系重启时,就会看到已经开端自行格局化data和cache分区,稍后就开端呈现进度条向响应分区里烧写uboot、kernel、android system的文件了!
图4 烧入新ROM
Android的开机流程
分类: Android
转:
1. 体系勾引bootloader
1) 源码:bootable/bootloader/*
2) 申明:加电后,CPU将先履行bootloader法度,此处有三种选择
a) 开机按Camera+Power启动到fastboot,即号令或SD卡烧写模式,不加载内核及文件体系,此处可以进行工厂模式的烧写
b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.img包含内核,根蒂根基的文件体系,用于工程模式的烧写
c) 开机按Power,正常启动体系,加载boot.img,boot.img包含内核,根蒂根基文件体系,用于正常启下手机(以下只解析正常启动的景象)
2. 内核kernel
1) 源码:kernel/*
2) 申明:kernel由bootloader加载
3. 文件体系及应用init
1) 源码:system/core/init/*
2) 设备文件:system/core/rootdir/init.rc,
3) 申明:init是一个由内核启动的用户级过程,它遵守init.rc中的设置履行:启动办事(这里的办事指linux底层办事,如adbd供给adb支撑,vold供给SD卡挂载等),履行号令和按此中的设备语句履行响应功能
4. 首要的后台法度zygote
1) 源码:frameworks/base/cmds/app_main.cpp等
2) 申明:zygote是一个在init.rc中被指定启动的办事,该办事对应的号令是/system/bin/app_process
source (service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start- system-server
socket zygote stream 666)
a) 建树Java Runtime,建树虚拟机
b) 建树Socket接管ActivityManangerService的恳求,用于Fork应用法度
c) 启动System Server
5. 体系办事system server
1) 源码:frameworks/base/services/java/com/android/server/SystemServer.java
2) 申明:被zygote启动,经由过程System Manager经管android的办事(这里的办事指frameworks/base/services下的办事,如卫星定位办事,剪切板办事等)
6. 桌面launcher
1) 源码:ActivityManagerService.java为进口,packages/apps/launcher*实现
2) 申明:体系启动成功后SystemServer应用xxx.systemReady()通知各个办事,体系已经伏贴,桌面法度Home就是在ActivityManagerService.systemReady()通知的过程中建树的,终极调用startHomeActivityLocked()启launcher
7. 解锁
1) 源码:
frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
2) 申明:体系启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,终极经由过程LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上画图,其代码了存放在特别的地位
8. 开机自启动的第三方应用法度
1) 源码:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
2) 申明:体系启动成功后SystemServer调用ActivityManagerNative.getDefault().systemReady()通知ActivityManager启动成功,ActivityManager会经由过程置变量mBooting,通知它的另一线程,该线程会发送广播android.intent.action.BOOT_COMPLETED以告诉已注册的第三办法度在开机时主动启动。
9. 总结
综上所述,体系层次关于启动最核心的项目组是zygote(即app_process)和system server,zygote它负责最根蒂根基的虚拟机的建树,以支撑各个应用法度的启动,而system server用于经管android后台办事,启动步调及次序。
(end)
本文来自:http://blog.csdn.net/omg_2012/article/details/7875093
android recovery模式及ROM建造
转载时请注明出处和作者
文章出处:http://www.cnblogs.com/xl19862005
作者:Xandy
1 总述
为了便利客户日后的固件进级,本周研究了一下android的recovery模式。网上有不少这类的材料,但都斗劲错杂,没有一个体系的介绍与熟悉,在这里将网上所找到的和本身经由过程查阅代码所把握的器材收拾出来,给大师一个参考!
2 Android启动过程
在这里有须要理一下android的启动过程:
图1 android启动过程
体系上电之后,起首是完成一系列的初始化过程,如cpu、串口、中断、timer、DDR等等硬件设备,然后接着加载boot default environmet,为后面内核的加载作好筹办。在一些体系启动须要的初始完成之后,将断定是否要进入recovery模式,从图1中可以看出,进入recovery模式有两种景象。一种是检测到有组合按键按下时;另一种是检测到cache/recovery目次下有command这个文件,这个文件有内容有它特定的格局,将在后面讲到。
3 Uboot启动
下面来看看uboot中lib_arm/board.c这个文件中的start_armboot这个函数,这个函数在start.s这个汇编文件中完成客栈等一些根蒂根基动作之后被调用,进入到c的代码中,start_armboot项目组代码如下:
void start_armboot (void)
{
.
.
.
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
#ifdef CONFIG_ANDROID_RECOVERY
check_recovery_mode();
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
}
init_sequence是一个函数布局体指针,里面存放的是一些必备的初始化函数,其代码如下:
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
我们来看看env_init这个函数,其代码如下:
int env_init(void)
{
/* use default */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
#ifdef CONFIG_DYNAMIC_MMC_DEVNO
extern int get_mmc_env_devno(void);
mmc_env_devno = get_mmc_env_devno();
#else
mmc_env_devno = CONFIG_SYS_MMC_ENV_DEV;
#endif
return 0;
}
可以看出在这里将default_environment加载进入体系,default_environment对应的项目组代码如下:
uchar default_environment[] = {
.
.
.
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
""
};
而CONFIG_EXTRA_ENV_SETTINGS则是在我们对应的BSP的头文件中定义了,如下:
#define CONFIG_EXTRA_ENV_SETTINGS
"netdev=eth0"
"ethprime=FEC0"
"bootfile=uImage"
"loadaddr=0 x70800000"
"rd_loadaddr=0 x70D00000"
"bootargs=console=ttymxc0 init=/init "
"androidboot.console=ttymxc0 video=mxcdi1fb:RGB666,XGA "
"ldb=di1 di1_primary pmem=32M,64M fbmem=5M gpu_memory=64M"
"bootcmd_SD=mmc read 0 ¥{loadaddr} 0 x800 0 x2000;"
"mmc read 0 ¥{rd_loadaddr} 0 x3000 0 x300"
"bootcmd=run bootcmd_SD; bootm ¥{loadaddr} ¥{rd_loadaddr}"
再来看看check_recovery_mode这个函数中的代码,具体代码如下:
/* export to lib_arm/board.c */
void check_recovery_mode(void)
{
if (check_key_pressing())
setup_recovery_env();
else if (check_recovery_cmd_file()) {
puts("Recovery command file founded! ");
setup_recovery_env();
}
}
可以看到在这里经由过程check_key_pressing这个函数来检测组合按键,当有对应的组合按键按下时,将会进入到recovery模式,这也恰是各大android论坛里讲到刷机时都邑提到的power+音量加键进入recovery模式的原因。那么check_recovery_cmd_file又是在什么景象下履行的呢?这个也恰是这篇文章所要讲的内容之处。
先来看看check_recovery_cmd_file这个函数中的如下这段代码:
int check_recovery_cmd_file(void)
{
.
.
.
switch (get_boot_device()) {
case MMC_BOOT:
case SD_BOOT:
{
for (i = 0; i < 2; i++) {
block_dev_desc_t *dev_desc = NULL;
struct mmc *mmc = find_mmc_device(i);
dev_desc = get_dev("mmc", i);
if (NULL == dev_desc) {
printf("** Block device MMC %d not supported ", i);
continue;
}
mmc_init(mmc);
if (get_partition_info(dev_desc, CONFIG_ANDROID_CACHE_PARTITION_MMC,
&info)) {
printf("** Bad partition %d ** ",CONFIG_ANDROID_CACHE_PARTITION_MMC);
continue;
}
part_length = ext2fs_set_blk_dev(dev_desc, CONFIG_ANDROID_CACHE_PARTITION_MMC);
if (part_length == 0) {
printf("** Bad partition - mmc %d:%d ** ", i, CONFIG_ANDROID_CACHE_PARTITION_MMC);
ext2fs_close();
continue;
}
if (!ext2fs_mount(part_length)) {
printf("** Bad ext2 partition or "
"disk - mmc %d:%d ** ",
i, CONFIG_ANDROID_CACHE_PARTITION_MMC);
ext2fs_close();
continue;
}
filelen = ext2fs_open(CONFIG_ANDROID_RECOVERY_CMD_FILE);
ext2fs_close();
break;
}
}
break;
.
.
.
}
首要来看看下面这个ext2fs_open所打开的内容,CONFIG_ANDROID_RECOVERY_CMD_FILE,这个恰是上方所提到的rocovery cmd file的宏定义,内容如下:
#define CONFIG_ANDROID_RECOVERY_CMD_FILE "/recovery/command"
当检测到有这个文件存在时,将会进入到setup_recovery_env这个函数中,其响应的代码如下:
void setup_recovery_env(void)
{
char *env, *boot_args, *boot_cmd;
int bootdev = get_boot_device();
boot_cmd = supported_reco_envs[bootdev].cmd;
boot_args = supported_reco_envs[bootdev].args;
if (boot_cmd == NULL) {
printf("Unsupported bootup device for recovery ");
return;
}
printf("setup env for recovery.. ");
env = getenv("bootargs_android_recovery");
/* Set env to recovery mode */
/* Only set recovery env when these env not exist, give user a
* chance to change their recovery env */
if (!env)
setenv("bootargs_android_recovery", boot_args);
env = getenv("bootcmd_android_recovery");
if (!env)
setenv("bootcmd_android_recovery", boot_cmd);
setenv("bootcmd", "run bootcmd_android_recovery");
}
在这里主如果将bootcmd_android_recovery这个景象变量加到uboot启动的environment中,如许当体系启动加载完root fs之后将不会进入到android的system中,而是进入到了recovery这个轻量级的小UI体系中。
下面我们来看看为什么在uboot的启动景象变量中参加bootcmd_android_recovery这些启动参数的时辰,体系就会进入到recovery模式下而不是android system,先看看bootcmd_android_recovery响应的参数:
#define CONFIG_ANDROID_RECOVERY_BOOTARGS_MMC
"setenv bootargs ¥{bootargs} init=/init root=/dev/mmcblk1p4"
"rootfs=ext4 video=mxcdi1fb:RGB666,XGA ldb=di1 di1_primary"
#define CONFIG_ANDROID_RECOVERY_BOOTCMD_MMC
"run bootargs_android_recovery;"
"mmc read 0 ¥{loadaddr} 0 x800 0 x2000;bootm"
可以看到在进入recovery模式的时辰这里把root的分区设置成了/dev/mmcblk1p4,再来看看在体系烧录的时辰对全部SD卡的分区如下:
sudo mkfs.vfat -F 32 ¥{NODE}¥{PART}1 -n sdcards
sudo mkfs.ext4 ¥{NODE}¥{PART}2 -O ^extent -L system
sudo mkfs.ext4 ¥{NODE}¥{PART}4 -O ^extent -L recovery
sudo mkfs.ext4 ¥{NODE}¥{PART}5 -O ^extent -L data
sudo mkfs.ext4 ¥{NODE}¥{PART}6 -O ^extent -L cache
这里NODE = /dev/mmcblk1为挂载点,PART = p或者为空,作为分区的检测。可以看出上方在给recovery分区的时辰,用的是/dev/mmcblk1p4这个分区,所以当设置了recovery启动模式的时辰,root根目次就被挂载到/dev/mmcblk1p4这个recovery分区中来,从而进入recovery模式。
4 recovery
关于android的recovery网上有各类版本的定义,这里我总结一下:所谓recovery是android下参加的一种特别工作模式,有点类似于windows下的gost,体系进入到这种模式下时,可以在这里经由过程按键选择响应的操纵菜单实现响应的功能,比如android体系和数据区的快速格局化(wipe);体系和用户数据的备份和恢复;经由过程sd卡刷新的rom等等。典范的recovery界面如下:
图2 recovery界面
Recovery的源代码在bootable/recovery这个目次下面,首要来看看recovery.c这个文件中的main函数:
Int main(int argc, char **argv) {
.
.
.
ui_init();
ui_set_background(BACKGROUND_ICON_INSTALLING);
load_volume_table();
.
.
.
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
switch (arg) {
case ""p"": previous_runs = atoi(optarg); break;
case ""s"": send_intent = optarg; break;
case ""u"": _package = optarg; break;
case ""w"": wipe_data = wipe_cache = 1; break;
case ""c"": wipe_cache = 1; break;
case ""e"": encrypted_fs_mode = optarg; toggle_secure_fs = 1; break;
case ""t"": ui_show_text(1); break;
case ""?"":
LOGE("Invalid command argument ");
continue;
}
}
device_recovery_start();
.
.
.
if (_package)
{
// For backwards compatibility on the cache partition only, if
// we""re given an old ""root"" path "CACHE:foo", change it to
// "/cache/foo".
if (strncmp(_package, "CACHE:", 6) == 0)
{
int len = strlen(_package) + 10;
char* modified_path = malloc(len);
strlcpy(modified_path, "/cache/", len);
strlcat(modified_path, _package+6, len);
printf("(replacing path "%s" with "%s") ",
_package, modified_path);
_package = modified_path;
}
//for "/mnt/sdcard/.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
//ui_print("before:[%s] ",_package);
if (strncmp(_package, "/mnt", 4) == 0)
{
//jump the "/mnt"
_package +=4;
}
ui_print("install package [%s] ",_package);
}
printf(" ");
property_list(print_property, NULL);
printf(" ");
int status = INSTALL_SUCCESS;
.
.
.
// Recovery strategy: if the data partition is damaged, disable encrypted file systems.
// This preventsthe device recycling endlessly in recovery mode.
.
.
.
if (_package != NULL)
{
status = install_package(_package);
if (status != INSTALL_SUCCESS)
ui_print("Installation aborted. ");
else
{
erase_volume("/data");
erase_volume("/cache");
}
} else if (wipe_data) {
if (device_wipe_data()) status = INSTALL_ERROR;
if (erase_volume("/data")) status = INSTALL_ERROR;
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
if (status != INSTALL_SUCCESS) ui_print("Data wipe failed. ");
} else if (wipe_cache) {
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed. ");
} else {
status = INSTALL_ERROR; // No command specified
}
if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
//Xandy modify for view the install infomation
//if (status != INSTALL_SUCCESS || ui_text_visible())
if(status != INSTALL_SUCCESS)
{
prompt_and_wait();
}
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);
ui_print("Rebooting... ");
sync();
reboot(RB_AUTOBOOT);
return EXIT_SUCCESS;
}
在这里起首完成recovery模式轻量级的UI体系初始化,设置靠山图片,然后对输入的参数格局化,最后按照输入的参数进行响应的操纵,如:安装新的ROM、格局化(wipe)data及cache分区等等;值得重视的是刷新ROM的时辰,要建造响应的.zip的安装包,这个在最后一章节讲述,这里碰到的一个题目是在recovery模式下sd卡的挂载点为/sdcard而不是android体系下的/mnt/sdcard,所以我在这里经由过程:
//for "/mnt/sdcard/.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
//ui_print("before:[%s] ",_package);
if (strncmp(_package, "/mnt", 4) == 0)
{
//jump the "/mnt"
_package +=4;
}
如许的操纵跳过了上层传过来的/mnt这四个字符。别的一个值得一提的是,传入这里的这些参数都是从/cache/recovery/command这个文件中提取。具体对command文件的解析过程这里不再讲述,可能经由过程查看recovery.c这个文件中的get_args函数。
那么command这个文件是在什么景象下创建的呢?下面我们就来看看吧!
5 恢复出厂设置和固件进级
在android的体系设备中进入“隐私权->恢复出厂设置->重置手机”将为进入到恢复出厂设置的状况,这时将会清除data、cache分区中的所有效户数据,使得体系重启后和刚刷机时一样了。别的为了便利操纵我们还可在“隐私权->固件进级->刷新ROM”这里参加了固件进级这一项。
在讲述这些内容之前,我们有须要来看看/cache/recovery/command这个文件响应的一些recovery号令,这些号令都由android体系写入。所有的号令如下:
* --send_intent=anystring ―― write the text out to recovery.intent
* --_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
5.1 恢复出厂设置
在frameworks/base/services/java/com/android/server/masterClearReceiver.java
这个文件中有如下代码:
public class MasterClearReceiver extends BroadcastReceiver {
private static final String TAG = "MasterClear";
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if (!"google.com".equals(intent.getStringExtra(""))) {
Slog.w(TAG, "Ignoring master clear request -- not trusted server.");
return;
}
}
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
if (intent.hasExtra("enableEFS")) {
RecoverySystem.rebootToggleEFS(context, intent.getBooleanExtra("enableEFS", false));
} else {
RecoverySystem.rebootWipeUserData(context);
}
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can""t perform master clear/factory reset", e);
}
}
};
thr.start();
}
}
当app中操纵了“恢复出厂设置”这一项时,将发出广播,这个广播将在这里被监听,然掉队入到恢复出厂设置状况,我们来看看rebootWipeUserData这个办法的代码:
public static void rebootWipeUserData(Context context) throws IOException {
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
context.sendOrderedBroadcast(intent, android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
condition.open();
}
}, null, 0, null, null);
// Block until the ordered broadcast has completed.
condition.block();
bootCommand(context, "--wipe_data");
}
我们可以看到在这里参入了“--wipe_data”这个参数,并把这条号令写入到command这个文件中去了,在进入recovery模式的时辰解析到这条号令时就会清除data和cache中的数据了。
再来看看bootCommand这个办法里的代码:
private static void bootCommand(Context context, String arg) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.(); // In case it""s not writable
LOG_FILE.();
FileWriter command = new FileWriter(COMMAND_FILE);
try {
command.write(arg);
command.write(" ");
} finally {
command.close();
}
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot("recovery");
throw new IOException("Reboot failed (no permissions?)");
}
此中COMMAND_FILE这个成员的定义如下:
/** Used to communicate with recovery. See bootable/recovery/recovery.c. */
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
至此恢复出厂设置的号令就写入了recovery cmd file中去了,经由过程pm.reboot(“recovery”);重启体系,体系就主动进入到recovery模式主动清除用户数据后再重启体系。
5.2 固件进级
固件进级的流程和恢复出厂设置差不久不多,不合之处是入command这个文件中写入的号令不一样,下面是恢复出厂设置时的写号令的代码:
public static void installPackage(Context context, File packageFile)
throws IOException {
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
String arg = "--_package=" + filename;
bootCommand(context, arg);
}
这里的packageFile是由上层app传入的,内容如下:
File packageFile = new File("/sdcard/.zip");
RecoverySystem.installPackage(context, packageFile);
如许当体系重启进入到recovery模式时将会主动查找sdcard的根目次下是否有.zip这个文件,若是有将会进入到状况,不然会提示无法找到.zip!
至此我们已经熟悉打听了android的全部recovery流程,下面将讲讲.zip也就是各大论坛里讲到的ROM的建造过程。
6 ROM的建造
我们解压.zip这个文件,可发明它一般打包了如下这几个文件:
图3 ROM包中的内容
或者没有s而是system这个目次,不合的原因是我这里在s里放置的是system.img等镜像文件,这些文件都由源码编译而来。而若是是system目次,这里一般放的是android体系的system目次下的内容,可所以全部android体系的system目次,也可所以此中的一项目组内容,如一些so库等等,如许为补丁的公布供给了一个很好的解决办法,不须要更新全部体系,只须要更新一项目组内容就可以了!
来看看META-INF/com/google/android这个目次下的内容,在这里就两个文件,一个是可履行的exe文件-binary,这个文件在进入状况的用于把握ROM的烧入,具体的代码在recovery下的install.c文件中的try__binary这个函数中;另一个是r-script,这个文件里是一些脚本法度,具体的代码如下:
# Mount system for check figurepoint etc.
# mount("ext4", "EMMC","/dev/block/mmcblk0p2", "/system");
# Make sure Check system image figurepoint first.
# uncomment below lines to check
# assert(file_getprop("/system/build.prop", "ro.build.fingerprint") == "freescale/imx53_evk/imx53_evk/imx53_evk:2.2/FRF85B/eng.b33651.20100914.145340:eng/test-keys");
# assert(getprop("ro.build.platform) == "imx5x");
# unmount("/system");
show_progress(0.1, 5);
package_extract_dir("s", "/tmp");
#Format system/data/cache partition
ui_print("Format disk...");
format("ext4","EMMC","/system");
format("ext4","EMMC","/data");
format("ext4","EMMC","/cache");
show_progress(0.2, 10);
# Write u-boot to 1K position.
# u-boot binary should be a no padding uboot!
# For eMMC(iNand) device, needs to unlock boot partition.
ui_print("writting u-boot...");
sysfs_file_write(" /sys/class/mmc_host/mmc0/mmc0:0001/boot_config", "1");
package_extract_file("files/u-boot.bin", "/tmp/u-boot.bin");
#ui_print("Clean U-Boot environment...");
show_progress(0.2, 5);
#simple_dd("/dev/zero","/dev/block/mmcblk0",2048);
simple_dd("/tmp/u-boot.bin", "/dev/block/mmcblk0", 2048);
#access user partition,and enable boot partion1 to boot
sysfs_file_write("/sys/class/mmc_host/mmc0/mmc0:0001/boot_config", "8");
#Set boot width is 8bits
sysfs_file_write("/sys/class/mmc_host/mmc0/mmc0:0001/boot_bus_config", "2");
show_progress(0.2, 5);
ui_print("extract kernel image...");
package_extract_file("files/uImage", "/tmp/uImage");
# Write uImage to 1M position.
ui_print("writting kernel image");
simple_dd("/tmp/uImage", "/dev/block/mmcblk0", 1048576);
ui_print("extract uramdisk image...");
package_extract_file("files/uramdisk.img", "/tmp/uramdisk.img");
# Write uImage to 1M position.
ui_print("writting uramdisk image");
simple_dd("/tmp/uramdisk", "/dev/block/mmcblk0", 6291456);
show_progress(0.2, 50);
# You can use two way to your system which using ext4 system.
# dd hole system.img to your mmcblk0p2 partition.
package_extract_file("files/system.img", "/tmp/system.img");
ui_print("upgrading system partition...");
simple_dd("/tmp/system.img", "/dev/block/mmcblk0p2", 0);
show_progress(0.1, 5);
响应的脚本指令可在申明可对应源码可在recovery包中的install.c这个文件中找到。
在bootable/recovery/etc下有原始版的脚本代码-script,但在recovery下的r.c这个文件中有如下定义:
// Where in the package we expect to find the edify script to execute.
// (Note it""s "R-script", not the older "-script".)
#define SCRIPT_NAME "META-INF/com/google/android/r-script"
地点应用这个原版的脚本的时辰要将-script更成r-script,须要重视!
我们可以发明在bootable/recovery/etcMETA-INFO/com/google/android目次下少了一个-binary的履行文件,在out/target/product/YOU_PRODUCT/system/bin下面我们可以找到r,只要将其重名字为-binary就可以了!
有了这些筹办工作,我们就可以开端建造一个我们本身的ROM了,具体步调如下:
* Xandy@ubuntu:~¥ mkdir recovery
* Xandy@ubuntu:~¥ cd recovery 然后将上方提到的bootable/recovery/etc下的所有内容拷贝到当前目次下并删掉init.rc这个文件
* 编译./META-INF/com/google/android/r-script这个文件使达到我们想要的烧写把握,若是是烧写system.img如许的镜像文件,可以直接用我上方提到的r-script这个脚本代码。
* 拷贝响应的须要建造成ROM的android文件到s目次或者system目次下,这个得按照体系的须要决意。
* Xandy@ubuntu:~/recovery¥ mkdir res
* Xandy@ubuntu:~/recovery¥ ~/myandroid/out/host/linux-x86/framework/dumpkey.jar ~/myandroid/build/target/product/security/testkey.x509.pem > res/keys 这里创建一个目次用于存储体系的key值
* zip /tmp/recovery.zip -r ./META-INF ./s ./res 将所有文件打包
* java -jar ./tools/signapk.jar -w ./tools/testkey.x509.pem ./tools/testkey.pk8 /tmp/recovery.zip .zip 我在recovery目次下创建了一个tools目次,里面放置了sygnapk.jar、testkey.pk8、testkey.x509.pem这几个文件用于java签名时用
经过上方这几步之后就会在recovery目次生成一个.zip的文件,这个就是我们本身建造的ROM文件,将它拷到sdcard的根目次下,在体系设置里操纵进入到“固件进级状况”,比及体系重启时,就会看到已经开端自行格局化data和cache分区,稍后就开端呈现进度条向响应分区里烧写uboot、kernel、android system的文件了!
图4 烧入新ROM