如题,各位,我想问下,怎么自制android的卡刷机ROM包update.zip。我最近的工作是在MT6516平台下制作一个官方固件升级包以支持公司一款即将出货的使用MT6516开发的android2.2智能手机,折腾了好几天,也google了一些资料,现在遇到的问题是update.zip的签名不能通过(failed to verify whole-file signature)。下面给出我的update.zip包的制作过程。首先,我是参考taohl04的这篇博客文章来做的:http://blog.csdn.net/taohl04/archive/2011/05/02/6384686.aspx,按照上面的步骤,我在update目录下得到了如下文件:
.--boot.img|-- META-INF|   `-- com|       `-- google|           `-- android|               |-- update-binary |               `-- updater-script (说明1)`—system说明1:这个文件我是直接拷贝自android源码树根目录下的这个目录:bootable\recovery\etc\META-INF\com\google\android然后开始签名:$java  –jar  signapk.jar  –w  testkey.x509.pem  testkey.pk8  update.zip  update_signed.zip第三步,将update_signed.zip改名为update.zip($mv update_signed.zip update.zip),因为recovery源代码里对ROM做了这样的指定:static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
#define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary" (说明2)
#define PUBLIC_KEYS_FILE "/res/keys"    (说明3)说明3:见4.1所以将改名后的update.zip存放到sdcard根目录下。第四步,重启机器进入recovery模式,开始刷机,报错信息大致是说签名未能验证成功。我在源码中如下几个地方添加了打印信息:
4.1.install_package函数中
    int numKeys;
    RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
    ui_print("numKeys = %6d loadedKeys->len = %6d\n", numKeys,loadedKeys->len);打印结果为:numkeys = 1 loadedKeys->len = 64
其中PUBLIC_KEYS_FILE(见说明3)这个是什么东西,是要在刷机包中添加/res/key这个文件(或目录)吗?google了一下,发现老外也在问这个问题:http://forum.xda-developers.com/showthread.php?t=5812164.2.install_packge函数中
    err = verify_file(path, loadedKeys, numKeys); //path = "sdcard/update.zip"
    free(loadedKeys);
    ui_print("verify_file returned %d\n", err);  //打印为err = 1.即VERIFY_FAILURE ,参考4.3.
    if (err != VERIFY_SUCCESS) {
        ui_print("signature verification failed\n");    //报错,刷机失败,因为signature验证失败。
        reset__block();
        return INSTALL_CORRUPT;
    }4.3.好吧,能不能绕过签名呢?我试了一下,直接将err = VERIFY_SUCCESS,程序继续向下运行,又报错,大致是因为等待子进程结束时遇到堵塞。出错信息见4.3.3
    /* Try to open the package.
     */
    ZipArchive zip;
    err = mzOpenZipArchive(path, &zip);
    if (err != 0) {
        ui_print("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
        reset__block();
        return INSTALL_CORRUPT;
    }    /* Verify and install the contents of the package.
     */
    int status = handle_update_package(path, &zip);  //函数体见4.3.1.
    mzCloseZipArchive(&zip);4.3.1.函数handle_update_package
static int
handle_update_package(const char *path, ZipArchive *zip)
{
    // Update should take the rest of the progress bar.
    ui_print("Installing update...\n");    int result = try_update_binary(path, zip);      //函数体见4.3.2.
    register_package_root(NULL, NULL);  // Unregister package root
    return result;
}
4.3.2.函数try_update_binary   (代码有点长,拷贝到sourceinsight里面看比较明了)
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char *path, ZipArchive *zip) {
    const ZipEntry* binary_entry =
            mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);  //参考说明2,如去掉update-binary呢?参考4.4.
    if (binary_entry == NULL) {
        ui_print("because binary_entry == NULL,return INSTALL_CORRUPT\n");
        return INSTALL_CORRUPT;
    }
    
    char* binary = "/tmp/update_binary";
    unlink(binary);
    int fd = creat(binary, 0755);
    if (fd < 0) {
        ui_print("Can't make %s\n", binary);
        return 1;
    }
    bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
    close(fd);    if (!ok) {
        ui_print("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
        return 1;
    }    int pipefd[2];
    pipe(pipefd);    char** args = malloc(sizeof(char*) * 5);
    args[0] = binary;
    args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk
    args[2] = malloc(10);
    sprintf(args[2], "%d", pipefd[1]);    //为什么要添加进程间管道通信?!
    args[3] = (char*)path;
    args[4] = NULL;    pid_t pid = fork();
    if (pid == 0) {
        close(pipefd[0]);          //关闭管道0
        execv(binary, args);
        fprintf(stderr, "E:Can't run %s (%s)\n", binary, strerror(errno));
        _exit(-1);
    }
    close(pipefd[1]);          //关闭管道1    char buffer[1024];
    FILE* from_child = fdopen(pipefd[0], "r");   //打开管道0
    while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
        char* command = strtok(buffer, " \n");
        if (command == NULL) {
            continue;
        } else if (strcmp(command, "progress") == 0) {
            char* fraction_s = strtok(NULL, " \n");
            char* seconds_s = strtok(NULL, " \n");            float fraction = strtof(fraction_s, NULL);
            int seconds = strtol(seconds_s, NULL, 10);            ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION),
                             seconds);
        } else if (strcmp(command, "set_progress") == 0) {
            char* fraction_s = strtok(NULL, " \n");
            float fraction = strtof(fraction_s, NULL);
            ui_set_progress(fraction);
        } else if (strcmp(command, "ui_print") == 0) {
            char* str = strtok(NULL, "\n");
            if (str) {
                ui_print(str);
            } else {
                ui_print("\n");
            }
        } else {
            ui_print("unknown command [%s]\n", command);
        }
    }
    fclose(from_child);    int status;
    waitpid(pid, &status, 0);
    ui_print("pid = %6d status = %6d\n", pid,status);   //出错在这里。参考4.3.3.
    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { //两个宏函数的定义,见4.3.4
        ui_print("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
        return INSTALL_ERROR;
    }    return INSTALL_SUCCESS;
}
4.3.3.出错消息为
pid = 59 status = 768 
Error in /sdcard/update.zip
(status3)
Installation abort另外,想了解wait和waitpid,可以看这篇文章:http://hi.baidu.com/qiaoyongfeng/blog/item/3d6fc100bcf93e17738b6576.html4.3.4.WIFEXITED和WEXITSTATUS
#define WIFEXITED(status) (((status) & 0xff) == 0)
#define WEXITSTATUS(status) (((status) >> 8) & 0xff)4.4.去掉update.zip包中的update-binary,报错信息为
because binary_entry == NULL,return INSTALL_CORRUPT
Installation aborted.
各位请帮帮我,到底我哪一步错了,万分火急,先谢谢啦。

解决方案 »

  1.   


    签名直接绕过去了,直接success,签名是什么?为什么要签名?不是很懂这东西。知道的话还望指教指教。
      

  2.   

    首先保证recvery足够新的话,升级一般来说没有问题
      

  3.   

    现发现一个错误,taohl04文章说:
    updater-script    : 该文件需要自己根据更新包需要更新的内容自行编写. 具体用什么名字是由 myandroid/bootable/recovery/updater/updater.c 文件中的宏 SCRIPT_NAME 的值而定.(注意: 是updater-script, 而不是 update-script).检查了一下,原来我的update.zip包中的update-script也应该使用updater-script现在改为:
    cp  myandroid/bootable/recovery/etc/META-INF/com/google/android/update-script META-INF/com/google/android/updater-script 
      

  4.   

    是不是updater-script有问题?myandroid/bootable/recovery/etc/META-INF/com/google/android/update-script 的原文内容是:assert compatible_with("0.1") == "true"
    assert file_contains("SYSTEM:build.prop", "ro.product.device=dream") == "true" || file_contains("SYSTEM:build.prop", "ro.build.product=dream") == "true"
    assert file_contains("RECOVERY:default.prop", "ro.product.device=dream") == "true" || file_contains("RECOVERY:default.prop", "ro.build.product=dream") == "true"
    assert getprop("ro.product.device") == "dream"
    format BOOT:
    format SYSTEM:
    copy_dir PACKAGE:system SYSTEM:
    write_raw_image PACKAGE:boot.img BOOT:
      

  5.   

    关于“说明2  res/keys”  是在out/...../recovery目录下的root/res/keys    也就是recovery.img下的res/keys
      

  6.   

    你好,看了你写的东西,感觉很深刻,我现在也是面临这样的问题,如何自制rom包,你能给点建议吗,我主要是没有任何的编程基础,ubuntu下编译的。