进入Recover后升级失败,提示unknown volume for path错误探索

为了实现u盘升级功能,但每次进入recovery升级都提示的是升级失败,最终我通过找到位于cache/recovery下的升级日志进行分析,摘取关键日志如下:

I:no boot messages 
I:Got arguments from /cache/recovery/command
locale is [zh_CN]
can't open /dev/tty0: No such file or directory
framebuffer: fd 3 (480 x 854)
ioctl(): blank: Invalid argument
ioctl(): blank: Invalid argument
       installing_text: zh_CN (240 x 38 @ 1818)
          erasing_text: zh_CN (128 x 38 @ 1521)
       no_command_text: zh_CN (92 x 38 @ 1521)
            error_text: zh_CN (98 x 38 @ 1521)
Command: "/sbin/recovery" "--update_package=/storage/sdcard0/update.zip" "--locale=zh_CN"


update_package = /storage/sdcard0/update.zip
I:Finding update package...
I:Update location: /storage/sdcard0/update.zip
E:unknown volume for path [/storage/sdcard0/update.zip]

我尝试了许多次网络上所提供的方法,依旧没能解决问题,实在没办法,我就将u盘的update.zip文件通过程序拷贝到cache/recovery之后再升级,最后成功实现了本地升级功能。

过了几日再回过来看,实际没那么麻烦。下面来跟一下代码讲讲思路(不同芯片厂家实现可能会有一定差异):
./bootable/recovery/recovery.cpp

int
main(int argc, char **argv) {
    
    
//省略无关代码
load_volume_table();//这个是关键点,后面会讲
//省略无关代码
status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
//省略无关代码
}

从recovery的入口main函数找到install_package函数,这里是实现升级的关键接口,再往下跟踪:
./bootable/recovery/install.cpp

int
install_package(const char* path, int* wipe_cache, const char* install_file)
{
    
    
	//省略无关代码
	result = really_install_package(path, wipe_cache);
	//省略无关代码
    return result;
}

最终实现升级我们的升级包的是调用了really_install_package函数,那就继续往下,我也不多废话了:
./bootable/recovery/install.cpp

static int
really_install_package(const char *path, int* wipe_cache)
{
    
    
	//省略无关代码
    if (ensure_path_mounted(path) != 0) {
    
    
        LOGE("Can't mount %s\n", path);
        return INSTALL_CORRUPT;
    }
    //省略无关代码
    return try_update_binary(path, &zip, wipe_cache);
}

这个really_install_package函数中,我们有目的的直接找ensure_path_mounted的实现代码:

int ensure_path_mounted(const char* path) {
    
    
    Volume* v = volume_for_path(path);
    if (v == NULL) {
    
    
        LOGE("unknown volume for path [%s]\n", path);
        return -1;
    }
     //省略无关代码
 }

可以看到日志中的问题是在这儿弹出的,表示的就是在分区表中没找到我们升级地址,那我们是不是只要在分区表中加上不就能找到了呢?特别提下,volume_for_path函数是从结构体中遍历,看分区表是否注册有这个地址,实现这里就不贴了。

我们现在再回到最开始讲的main函数中,这个load_volume_table函数就是加载分区表:

./bootable/recovery/roots.cpp

void load_volume_table() {
    
    
    int i;
    int ret;
	if ( check_flash_type() == NAND_TYPE ) {
    
    
		LOGI("Load the recovery.fstab\n");
    	fstab = fs_mgr_read_fstab("/etc/recovery.fstab");
    } else if ( check_flash_type() == EMMC_TYPE ) {
    
    
        LOGI("Load the recovery.emmc.fstab\n");
        fstab = fs_mgr_read_fstab("/etc/recovery.emmc.fstab");
    } else {
    
    
	    fstab = fs_mgr_read_fstab("/etc/recovery.fstab");
	}
	if (!fstab) {
    
    
        LOGE("failed to read /etc/recovery.fstab\n");
        return;
    }

    ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk", 0);
    if (ret < 0 ) {
    
    
        LOGE("failed to add /tmp entry to fstab\n");
        fs_mgr_free_fstab(fstab);
        fstab = NULL;
        return;
    }

    printf("recovery filesystem table\n");
    printf("=========================\n");
    for (i = 0; i < fstab->num_entries; ++i) {
    
    
        Volume* v = &fstab->recs[i];
        printf("  %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
               v->blk_device, v->length);
    }
    printf("\n");
}

可以看到是根据flash类型加载不同的分区表,解析并存到fstab 结构体中,所以我们根据实际情况选择,在fstab文件中添加我们的u盘升级路径即可。

我这里也讲的比较简单,但差不多原理就是这样了。

猜你喜欢

转载自blog.csdn.net/angelsmiling/article/details/105177240