1. 程式人生 > >Android系統Recovery工作原理之使用update.zip

Android系統Recovery工作原理之使用update.zip

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
       "\0"
};

       而CONFIG_EXTRA_ENV_SETTINGS則是在我們對應的BSP的標頭檔案中定義了,如下:

#define  CONFIG_EXTRA_ENV_SETTINGS                                 \
              "netdev=eth0\0"                                    \
              "ethprime=FEC0\0"                                \
              "bootfile=uImage\0"  \
              "loadaddr=0x70800000\0"                            \
              "rd_loadaddr=0x70D00000\0"        \
              "bootargs=console=ttymxc0 init=/init " \
                     "androidboot.console=ttymxc0 video=mxcdi1fb:RGB666,XGA " \
                     "ldb=di1 di1_primary pmem=32M,64M fbmem=5M gpu_memory=64M\0" \
              "bootcmd_SD=mmc read 0 ${loadaddr} 0x800 0x2000;" \
                     "mmc read 0 ${rd_loadaddr} 0x3000 0x300\0" \
              "bootcmd=run bootcmd_SD; bootm ${loadaddr} ${rd_loadaddr}\0" \

       再來看看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!\n");
              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\n", i);
                                   continue;
                            }
                            mmc_init(mmc);
                            if (get_partition_info(dev_desc, CONFIG_ANDROID_CACHE_PARTITION_MMC,
                                                 &info)) {
                                   printf("** Bad partition %d **\n",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 **\n", i, CONFIG_ANDROID_CACHE_PARTITION_MMC);
                                   ext2fs_close();
                                   continue;
                            }
                            if (!ext2fs_mount(part_length)) {
                                   printf("** Bad ext2 partition or "
                                          "disk - mmc %d:%d **\n",
                                          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\n");
              return;
       }
       printf("setup env for recovery..\n");
       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} 0x800 0x2000;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': update_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\n");
            continue;
        }
    }
    device_recovery_start();
       .
       .
       .
    if (update_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(update_package, "CACHE:", 6) == 0)
              {
            int len = strlen(update_package) + 10;
            char* modified_path = malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
              //for update from "/mnt/sdcard/update.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
              //ui_print("before:[%s]\n",update_package);
        if (strncmp(update_package, "/mnt", 4) == 0)
        {
        //jump the "/mnt"
                     update_package +=4;
              }
              ui_print("install package from[%s]\n",update_package);
     }
    printf("\n");
    property_list(print_property, NULL);
    printf("\n");
    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 (update_package != NULL)
    {
        status = install_package(update_package);
        if (status != INSTALL_SUCCESS)
                     ui_print("Installation aborted.\n");
              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.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n");
    } 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...\n");
    sync();
    reboot(RB_AUTOBOOT);
    return EXIT_SUCCESS;
}

       在這裡首先完成recovery模式輕量級的UI系統初始化,設定背景圖片,然後對輸入的引數格式化,最後根據輸入的引數進行相應的操作,如:安裝新的ROM、格式化(wipe)data及cache分割槽等等;值得注意的是重新整理ROM的時候,要製作相應的update.zip的安裝包,這個在最後一章節講述,這裡遇到的一個問題是在recovery模式下sd卡的掛載點為/sdcard而不是android系統下的/mnt/sdcard,所以我在這裡通過:

//for update from "/mnt/sdcard/update.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
              //ui_print("before:[%s]\n",update_package);
        if (strncmp(update_package, "/mnt", 4) == 0)
        {
        //jump the "/mnt"
                     update_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
*      --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

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("from"))) {
                Slog.w(TAG, "Ignoring master clear request -- not from 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.delete();  // In case it's not writable
        LOG_FILE.delete();
        FileWriter command = new FileWriter(COMMAND_FILE);
        try {
            command.write(arg);
            command.write("\n");
        } 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 = "--update_package=" + filename;
      bootCommand(context, arg);
  }

       這裡的packageFile是由上層app傳入的,內容如下:

File packageFile = new File("/sdcard/update.zip");
RecoverySystem.installPackage(context, packageFile);

       這樣當系統重啟進入到recovery模式時將會自動查詢sdcard的根目錄下是否有update.zip這個檔案,如果有將會進入到update狀態,否則會提示無法找到update.zip!

       至此我們已經明白了android的整個recovery流程,下面將講講update.zip也就是各大論壇裡講到的ROM的製作過程。

6       ROM的製作

我們解壓update.zip這個檔案,可發現它一般打包瞭如下這幾個檔案: 

圖3  ROM包中的內容

或者沒有updates而是system這個目錄,不同的原因是我這裡在updates裡放置的是system.img等映象檔案,這些檔案都由原始碼編譯而來。而如果是system目錄,這裡一般放的是android系統的system目錄下的內容,可以是整個android系統的system目錄,也可以是其中的一部分內容,如一些so庫等等,這樣為補丁的釋出提供了一個很好的解決辦法,不需要更新整個系統,只需要更新一部分內容就可以了!

來看看META-INF/com/google/android這個目錄下的內容,在這裡就兩個檔案,一個是可執行的exe檔案update-binary,這個檔案在進入update狀態的用於控制ROM的燒入,具體的程式碼在recovery下的install.c檔案中的try_update_binary這個函式中;另一個是updater-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("updates", "/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 update 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下有原始版的指令碼程式碼update-script,但在recovery下的updater.c這個檔案中有如下定義:

// Where in the package we expect to find the edify script to execute.
// (Note it's "updateR-script", not the older "update-script".)
#define SCRIPT_NAME "META-INF/com/google/android/updater-script"

       所在使用這個原版的指令碼的時候要將update-script更成updater-script,需要注意!

       我們可以發現在bootable/recovery/etcMETA-INFO/com/google/android目錄下少了一個update-binary的執行檔案,在out/target/product/YOU_PRODUCT/system/bin下面我們可以找到updater,只要將其重名字為update-binary就可以了!

       有了這些準備工作,我們就可以開始製作一個我們自己的ROM了,具體步驟如下:

*      [email protected]:~$ mkdir recovery
*      [email protected]:~$ cd recovery 然後將上面提到的bootable/recovery/etc下的所有內容拷貝到當前目錄下並刪掉init.rc這個檔案
*      編譯./META-INF/com/google/android/updater-script這個檔案使達到我們想要的燒寫控制,如果是燒寫system.img這樣的映象檔案,可以直接用我上面提到的updater-script這個指令碼程式碼。
*      拷貝相應的需要製作成ROM的android檔案到updates目錄或者system目錄下,這個得根據系統的需要決定。
*      [email protected]:~/recovery$ mkdir res
*      [email protected]:~/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 ./updates ./res 將所有檔案打包
*      java -jar ./tools/signapk.jar -w ./tools/testkey.x509.pem ./tools/testkey.pk8 /tmp/recovery.zip update.zip 我在recovery目錄下建立了一個tools目錄,裡面放置了sygnapk.jar、testkey.pk8、testkey.x509.pem這幾個檔案用於java簽名時用

經過上面這幾步之後就會在recovery目錄生成一個update.zip的檔案,這個就是我們自己製作的ROM檔案,將它拷到sdcard的根目錄下,在系統設定裡操作進入到“韌體升級狀態”,等到系統重啟時,就會看到已經開始自行格式化data和cache分割槽,稍後就開始出現進度條向相應分割槽裡燒寫uboot、kernel、android system的檔案了!

圖4 燒入新ROM

相關推薦

Android系統Recovery工作原理2---update.zip差分包問題的解決

一、生成OTA增量包失敗的解決方案            在上一篇中末尾使用build/tools/releasetools/ota_from_target_files指令碼製作update.zip

Android系統Recovery工作原理使用update.zip升級過程分析

                       ① 在main函式的開頭,首先將使用者設定的option選項存入OPTIONS變數中,它是一個python中的類。緊接著判斷有沒有額外的指令碼,如果有就讀入到OPTIONS變數中。                        ② 解壓縮輸入的zip包,即我們在

Android系統Recovery工作原理使用update.zip

1       總述 為了方便客戶日後的韌體升級,本週研究了一下android的recovery模式。網上有不少這類的資料,但都比較繁雜,沒有一個系統的介紹與認識,在這裡將網上所找到的和自己通過查閱程式碼所掌握的東西整理出來,給大家一個參考! 2       Android啟動過程 在這裡有必要理一下an

很棒的開源監控系統原理系列文章:UAV MOF工作原理Agent注入機制原理

原文連結:https://mp.weixin.qq.com/s/eA6nuYPVvgoCWO4E3yP4BQ 也可關注公眾號:UAVStack智慧運維 大家好,UAVStack推送時間到~ 上月我們為大家介紹了UAVStack中的呼叫鏈技術,助力大家進行問題診斷和系統性能提升,希望大家有

希捷操作系統SeaOS工作原理

希捷操作系統seaos工作原理以希捷操作系統SeaOS為例:我們拆開硬盤的電路板,能看到CPU ,Flash ROM , RAM ,這三大跟電腦和手機相似的結構Flash ROM 和 固件區(硬盤碟片上的固件使用區域) Flash ROM 和固件區都是SeaOS系統用來存放的空間,就像我們電腦的C盤

[Java]Servlet工作原理二:Session與Cookie

工作 一段時間 .cn cookie font ava logs mage ont (未完待續) 一、Cookie Cookie 用於記錄用戶在一段時間內的行為,它有兩個版本:Version 0 和 Version 1,分別對應兩種響應頭 Set-Cookie 和 Set-

[Java]SpringMVC工作原理二:HandlerMapping和HandlerAdapter

!= 子類 exe 指定 ssa ble sina -name manage 一、HandlerMapping 作用是根據當前請求的找到對應的 Handler,並將 Handler(執行程序)與一堆 HandlerInterceptor(攔截器)封裝到 HandlerExe

Android系統root破解原理分析

上一篇文章 Android adb 原始碼分析 理論基礎 root破解過程的終極目標是替換掉系統中的su程式。但是要想替換掉系統中su程式本身就是需要root許可權的,怎樣在root破解過程中獲得root許可權,成為我們研究的重點了。下面我們先清點一下我們需要破解系統情況,假設需要破

SpringMVC工作原理:HandlerMapping和HandlerAdapter

一、HandlerMapping 作用是根據當前請求的找到對應的 Handler,並將 Handler(執行程式)與一堆 HandlerInterceptor(攔截器)封裝到 HandlerExecutionChain 物件中。在 HandlerMapping 介面的內部只有一個方法,

UAV MOF工作原理Agent注入機制原理

大家好,本月我們將為大家推送UAVStack的中介軟體增強框架專題(MOF),為大家詳細講述UAV中的MOF Agent是如何藉助javaagent(premain)和javaassist技術在對應用無侵入的前提下完成資料捕獲的。歡迎繼續關注UAVStack,瞭解UAV更多的技術創新。 前言 MOF(Mo

Android View 的工作原理

文章主要參考書籍《Android 開發藝術探索》(任玉剛 著),與書籍主要區別: 原始碼基於 Android 19,Android 版本變化導致的變化會標註說明 追加大量流程圖,原始碼追加更詳細註釋,以方便理解與記憶 擴充套件了一些書籍上未說明的原始碼、流程說明 前言 View 的三大

View的工作原理自定義View

        前面的四篇系列文章,從原始碼開始詳細的分析了View的Measure過程。學以致用,這篇文章就記錄一下,學完View的Measure過程之後,自己自定義View的一些收穫。本文講解的是普通View的自定義,ViewGroup的自定義將在下篇

View的工作原理Measure過程原始碼學習(四)

       上一篇文章,學習了ViewGroup和View的measure流程。文章最後講到,本文將會學習ViewGroup和普通View的onMeasure方法的工作。        因為ViewGroup是

View的工作原理Measure過程原始碼學習(三)

        上一篇文章講解了整個Android應用程式的View檢視的頂級節點DecorView的Measure過程,文章最後就講到了DecorView的onMeasure方法中呼叫super.onMeasure(widthMeasureSpec, h

View的工作原理Measure過程原始碼學習(二)

          上一篇文章從Android程式啟動過程講解了Activity、PhoneWindow以及ViewRoot與DecorView的聯絡。本篇文章詳細講述一下DecorView的measure過程。  

View的工作原理Measure過程原始碼學習(一)

       在Android開發過程中,View控制元件的使用是最基本的技能,而自定義View技能的掌握也是非常重要的。這篇博文講記錄一下在讀任玉剛老師的《Android開發藝術探索》一書中學習到的相關知識以及自己的一些收穫。這裡說明一點,在"View的

自定義View(一)View工作原理測量 measure

在Android中,一個View繪製出來要經過三大流程,分別用measure來測量View的寬高,用layout來確定View在父容器中的位置,最終用draw將View繪製到螢幕上。本章節主要,通過自己的理解來講解一下第一個流程measure的相關知識點。 measure方法在View類中,

Android系統移植與除錯-------)如何修改Android系統預設顯示

1、首先解決【設定】介面預設顯示【開發者選項】的問題 檢視原始碼:packages/apps/Settings/src/com/android/settings/SettingsActivity.java 在updateTilesList(List target)方法中,可以找到【開發

Android系統底層驅動除錯資訊列印級別

(本文說明的平臺:msm8953,系統:Android N,其他平臺和系統可作為參考使用)    在Linux中除錯核心模組時使用printk函式來列印除錯資訊時,可以設定列印資訊的級別。那麼就肯定會有這樣一個設定,用於控制終端顯示的資訊級別的。這個是通過/proc/sys/

Android系統移植與除錯------->Amlogic方案編譯步驟

這個命令是用來將envsetup.sh裡的所有用到的命令載入到環境變數裡去,我們來分析下它。 envsetup.sh裡的主要命令如下: function help() # 顯示幫助資訊 function get_abs_build_var()# 獲取絕對變數 function get_build_var()