編輯:關於Android編程
FFBM: fast factory boot mode,快速工程啟動模式
此函數主要是如何解析boot.img和recovery.img的頭部信息,提取這兩部分的參數,傳遞給內核,簡化後的流程圖如下:

圖1
//根據bootselect分區信息判斷是否進入recovery模式
if (check_format_bit())
boot_into_recovery= 1;
//根據misc分區信息判斷是否進入ffbm模式
if (!boot_into_recovery) { // 非recovery模式
memset(ffbm_mode_string, '\0', sizeof(ffbm_mode_string));
rcode = get_ffbm(ffbm_mode_string, sizeof(ffbm_mode_string)); if (rcode <= 0) {
boot_into_ffbm = false;
if (rcode < 0)
dprintf(CRITICAL,"failedto get ffbm cookie");
} else
boot_into_ffbm = true;
}else
boot_into_ffbm = false;
//如果不是recovery模式,就從EMMC中讀取boot.img的第1個page(2048)的//boot image header,判斷magic是否等於"ANDROID!"
if (mmc_read(ptn + offset, (unsigned int *)buf, page_size)) {
dprintf(CRITICAL,"ERROR: Cannot read boot image header\n");
return -1;
}
if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
dprintf(CRITICAL,"ERROR: Invalid boot image header\n");
return -1;
}
接著讀第2個page的header,這裡對應arm64 kernel的文件頭。
/* Read the next page to get kernel Imageheader
* which lives in the second page for arm64targets.
*/
if(mmc_read(ptn + page_size, (unsigned int *) kbuf, page_size)) {
dprintf(CRITICAL,"ERROR: Cannot read boot image header\n");
return -1;
}
/*
* Update the kernel/ramdisk/tags address ifthe boot image header
* has default values, these default valuescome from mkbootimg when
* the boot image is flashed using fastbootflash:raw
*/
//根據\lk\project\msm8909.mk中kenel、ramdisk和tags地址來更新
update_ker_tags_rdisk_addr(hdr,IS_ARM64(kptr));
/*Get virtual addresses since the hdr saves physical addresses. */
hdr->kernel_addr= VA((addr_t)(hdr->kernel_addr));//轉換後就是運行地址
hdr->ramdisk_addr= VA((addr_t)(hdr->ramdisk_addr));
hdr->tags_addr= VA((addr_t)(hdr->tags_addr));
//kernel、ramdisk大小向上頁對齊
kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask); ramdisk_actual= ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
//檢查kernel和ramdisk的是否與aboot的內存空間有重疊
/* Check if the addresses in the header arevalid. */
if(check_aboot_addr_range_overlap(hdr->kernel_addr, kernel_actual) ||
check_aboot_addr_range_overlap(hdr->ramdisk_addr,ramdisk_actual))
{
dprintf(CRITICAL,"kernel/ramdisk addresses overlap with aboot addresses.\n");
return-1;
}
//認證內核,這裡打印出來全部是0,表示沒有使用簽名的內核
/* Authenticate Kernel */
dprintf(INFO,"use_signed_kernel=%d, is_unlocked=%d, is_tampered=%d.\n",
(int)target_use_signed_kernel(),
device.is_unlocked,
device.is_tampered);
#if VERIFIED_BOOT
boot_verifier_init();//初始化boot.img的鑒權,讀取OEM 和User Keystore
#endif
接下來分是否使用采用簽名的內核來分析。
//采用簽名的內核,且設備沒有未來解鎖
if(target_use_signed_kernel() &&(!device.is_unlocked))
{
dprintf(INFO,"boot_linux_from_mmc()3333\n");
offset= 0;
image_addr= (unsigned char *)target_get_scratch_address();
#if DEVICE_TREE//表示采用設備樹
dt_actual= ROUND_TO_PAGE(hdr->dt_size, page_mask);
imagesize_actual= (page_size + kernel_actual + ramdisk_actual + dt_actual);
/// 檢查device tree是否與aboot的內存空間有重疊
if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_actual))
{
dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
return-1;
}
#else
imagesize_actual= (page_size + kernel_actual + ramdisk_actual);
#endif
dprintf(INFO,"Loading boot image (%d): start\n", imagesize_actual);
//設置kernel開始加載的時間戳,在kernel log中可以看到
bs_set_timestamp(BS_KERNEL_LOAD_START);
//引導kernel所需內存是否與aboot的內存空間有重疊
if(check_aboot_addr_range_overlap(image_addr, imagesize_actual))
{
dprintf(CRITICAL,"Boot image buffer address overlaps with aboot addresses.\n");
return-1;
}
//從EMMC讀取除了簽名之外的kernel內容
/*Read image without signature */
if(mmc_read(ptn + offset, (void *)image_addr, imagesize_actual))
{
dprintf(CRITICAL,"ERROR: Cannot read boot image\n");
return-1;
}
//設置加載kernel結束的時間戳
dprintf(INFO,"Loading boot image (%d): done\n", imagesize_actual);
bs_set_timestamp(BS_KERNEL_LOAD_DONE);
offset= imagesize_actual;
if(check_aboot_addr_range_overlap(image_addr + offset, page_size))
{
dprintf(CRITICAL,"Signature read buffer address overlaps with aboot addresses.\n");
return-1;
}
//從EMMC讀取內核的簽名信息
/*Read signature */
if(mmc_read(ptn+ offset, (void *)(image_addr + offset), page_size))
{
dprintf(CRITICAL,"ERROR: Cannot read boot image signature\n");
return-1;
}
verify_signed_bootimg(image_addr,imagesize_actual);//對boot.img鑒權
//將kernel和ramdisk移到正確的地址處
/*Move kernel, ramdisk and device tree to correct address */
memmove((void*)hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
memmove((void*)hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual),hdr->ramdisk_size);
#ifDEVICE_TREE
if(hdr->dt_size){
dt_table_offset= ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual +second_actual);
table= (struct dt_table*) dt_table_offset;
//檢查設備樹內容格式是否正確
if(dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {
dprintf(CRITICAL,"ERROR: Cannot validate Device Tree Table \n");
return-1;
}
//從device tree表中選擇一個最合適的device tree項
/*Find index of device tree within device tree table */
if(dev_tree_get_entry_info(table,&dt_entry) != 0){
dprintf(CRITICAL,"ERROR: Device Tree Blob cannot be found\n");
return-1;
}
//檢查device tree項是否與aboot的內存空間有重疊
/*Validate and Read device device tree in the "tags_add */
if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
{
dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
return-1;
}
//將device tree除了header部分的內容移到tags_addr地址處。
memmove((void*)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size);
}else {
/*
* If appended dev tree is found, update theatags with
* memory address to the DTB appended locationon RAM.
* Else update with the atags address in thekernel header
*/
void*dtb;
dtb= dev_tree_appended((void*) hdr->kernel_addr,
hdr->kernel_size,
(void*)hdr->tags_addr);
if(!dtb) {
dprintf(CRITICAL,"ERROR: Appended Device Tree Blob not found\n");
return-1;
}
}
#endif
}
Else//不需要對boot.img簽權,下面的代碼可參考簽權情況下的分析。
{
second_actual = ROUND_TO_PAGE(hdr->second_size, page_mask);
image_addr= (unsigned char *)target_get_scratch_address();
#if DEVICE_TREE
dt_actual= ROUND_TO_PAGE(hdr->dt_size, page_mask);
imagesize_actual= (page_size + kernel_actual + ramdisk_actual + dt_actual);
if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_actual))
{
dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
return-1;
}
#else
imagesize_actual= (page_size + kernel_actual + ramdisk_actual);
#endif
if(check_aboot_addr_range_overlap(image_addr, imagesize_actual))
{
dprintf(CRITICAL,"Boot image buffer address overlaps with aboot addresses.\n");
return-1;
}
dprintf(INFO,"Loading boot image (%d): start\n",
imagesize_actual);
bs_set_timestamp(BS_KERNEL_LOAD_START);
offset= 0;
/*Load the entire boot image */
if(mmc_read(ptn + offset, (void *)image_addr, imagesize_actual)) {
dprintf(CRITICAL,"ERROR: Cannot read boot image\n");
return-1;
}
dprintf(INFO,"Loading boot image (%d): done\n",
imagesize_actual);
bs_set_timestamp(BS_KERNEL_LOAD_DONE);
#ifdefTZ_SAVE_KERNEL_HASH
aboot_save_boot_hash_mmc(image_addr,imagesize_actual);
#endif/* TZ_SAVE_KERNEL_HASH */
/*Move kernel, ramdisk and device tree to correct address */
memmove((void*)hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
memmove((void*)hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual),hdr->ramdisk_size);
#ifDEVICE_TREE
if(hdr->dt_size){
dt_table_offset= ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual +second_actual);
table= (struct dt_table*) dt_table_offset;
if(dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {
dprintf(CRITICAL,"ERROR: Cannot validate Device Tree Table \n");
return-1;
}
/*Find index of device tree within device tree table */
if(dev_tree_get_entry_info(table,&dt_entry) != 0){
dprintf(CRITICAL,"ERROR: Getting device tree address failed\n");
return-1;
}
/*Validate and Read device device tree in the tags_addr */
if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
{
dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
return-1;
}
memmove((void*)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size);
}else {
/*Validate the tags_addr */
if(check_aboot_addr_range_overlap(hdr->tags_addr, kernel_actual))
{
dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
return-1;
}
/*
* If appended dev tree is found, update theatags with
* memory address to the DTB appended locationon RAM.
* Else update with the atags address in thekernel header
*/
void*dtb;
dtb= dev_tree_appended((void*) hdr->kernel_addr,
kernel_actual,
(void*)hdr->tags_addr);
if(!dtb) {
dprintf(CRITICAL,"ERROR: Appended Device Tree Blob not found\n");
return-1;
}
}
#endif
}
if (boot_into_recovery &&!device.is_unlocked && !device.is_tampered)
target_load_ssd_keystore();
unified_boot:
//調用boot_linux()解壓並啟動內核
boot_linux((void*)hdr->kernel_addr, (void *)hdr->tags_addr,
(const char *)hdr->cmdline,board_machtype(),
(void *)hdr->ramdisk_addr,hdr->ramdisk_size);
這裡的kernel_addr、tags_addr和ramdisk_addr地址由\bootable\bootloader\lk\project\msm8909.mk定義如下:
DEFINES +=ABOOT_FORCE_KERNEL_ADDR=0x80008000
DEFINES +=ABOOT_FORCE_RAMDISK_ADDR=0x82000000
DEFINES += ABOOT_FORCE_TAGS_ADDR=0x81E00000
DEFINES +=ABOOT_FORCE_KERNEL64_ADDR=0x00080000
要和device\qcom\msm8909\BoardConfig.mk下定義的保持一致
BOARD_KERNEL_BASE := 0x80000000
BOARD_KERNEL_PAGESIZE := 2048
BOARD_KERNEL_TAGS_OFFSET := 0x01E00000
BOARD_RAMDISK_OFFSET :=0x02000000
Android實現平鋪圖片效果
最近開發App,美工設計了一個有鋸齒邊沿效果的背景圖,只給了我一個鋸齒,然後需要平鋪展示鋸齒效果: android中實現平鋪圖片有兩種方式:(1)在drawable中的d
AsyncTask 流程解析
為什麼要使用異步任務?Android 單線程模型,多線程的操作系統耗時操作放在非主線程中運行AsyncTask 為何而生?子線程中更新UI封裝簡化異步操作構建AsyncT
Android5.0的Palette(調色板)、視圖陰影、著色和裁剪介紹
隨著Android5.0的發布,google帶來了Material Design,俗稱:材料設計。並帶來了一些新的東西,這裡就一一介紹這些新的設計元素。 1、P
Android源碼編譯之Nexus5真機編譯
1.前言在Android安全的研究工作中,我們時常要對Android進行改進並對其進行源碼編譯,由於目前幾乎所有的手機廠商均對其底層驅動實行封閉政策,導致我們在完成And