Android OTA使用及原理浅析

Android OTA使用及原理浅析

OTA(over the air)通过无线网络下载、删除更新等操作,完成业务操作;在Android系统方面,使用OTA可以解决系统升级,而其差分包会增量更新系统,具有占比流量小,适用于Android端;


制作OTA升级包

OTA包分区全量包和差分包;全量包包含编译整个系统后的所有内容,差分包则是在两个全量包基础上,对比产生的差分包;假如你有两个全量包Full A和Full B,此时设备上的系统是A版本,你之多的差分包C = Full B - Full A,则可以使用OTA技术将C作为升级包更新,而不需要更新整个B;

制作全量包

在源码根目录下,执行:

make otapackage -jX

X为线程数;成功后,会在out/target/product//obj/PACKAGING/target_files_intermediates/目录下生成zip的OTA全量包,表示制作成功
修改源码后,再次执行上述代码,会在上述目录在生成一个全量包;

制作差分包

将先后两个OTA包,差分对比生成差分包,并签上名即可部署到服务器或者本地,进行OTA升级;这里签名用到了源码生成的签名文件,如果更换签名会导致OTA升级校验verify无法通过,从而失败!

/build/tools/releasetools/ota_from_target_files -v --block -p out/host/linux-x86 -k build/target/product/security/testkey -i old.zip new.zip update.zip

上述命令实质是执行ota_from_target_files.py脚本,检验全量包,对比old.zip和new.zip产生差分包update.zip最后在签名,签名文件在testkey下面

差分包制作原理
原理实质就在这个ota_from_target_files.py脚本中,会对比两个zip的各个Image镜像文件,把不同的文件写入到update文件中;

差分包文件内容

在这里插入图片描述

  • metadata
    升级包中的元数据,主要描述当前差分包的版本升级信息、时间戳、需要缓存大小
ota-required-cache=53972992                                                                                                                                                                                                                                                              
ota-type=BLOCK
post-build=qcom/msm8953_32/msm8953_32:8.1.0/OPM1.171019.026/SIM8950LB01_10:userdebug/test-keys
post-build-incremental=SIM8950LB01_10
post-timestamp=1607567016
pre-build=qcom/msm8953_32/msm8953_32:8.1.0/OPM1.171019.026/SIM8950LB01_A9:userdebug/test-keys
pre-build-incremental=SIM8950LB01_A9
pre-device=msm8953_32
  • system.new.dat
    此次增量更新,system镜像的数据;vendor也有一个,因为我改动了vendor下的chromatic图像优化文件,所以这里也有
  • system.patch.data
    升级包中,system镜像需要的patch补丁数据
  • system.transfer.list
    升级命令列表,也就是升级过程中,会执行此list里面的命令,这些命令在制作时就确定了
  • otacert
    签名信息
  • update-binary和update-script
    二进制升级文件binary,用于解析update-script中的升级脚本,而script脚本又会调用每个镜像的list命令列表完成ota升级

OTA升级实践

上面我们制作好包后,就可以升级了;但是要切记 版本A8和A9制作的的A89差分包只能用于A8版本升到A9,不能用于其他版本
OTA升级都需要依赖Recovery模式,由Recovery帮我们完成升级

手动升级

把升级包update.zip推送到系统中或者网络下载下来,假如保存在/data/media/0/update.zip;则我们需要在/cache/recovery/下创建command命令,然后重启bootloader进入recovery模式:

adb push update.zip /data/media/0/
echo "--update_package=/data/media/0/update.zip" > command
adb push command /cache/recovery/
adb reboot recovery

这样就完成升级,升级后再/cache/recovery/会产生升级日志last_log,如果升级失败可用于分析其过程

Android API升级

API升级其实就是将上面手动升级弄成自动升级一样,我们需要指定升级包在哪里,然后重启进入recovery模式,如下代码:

try {
    File file = new File("/data/media/0/update.zip");
    RecoverySystem.installPackage(this, file);
} catch (IOException e) {
    e.printStackTrace();
}

分析源码:

public static void installPackage(Context context, File packageFile, boolean processed)
            throws IOException {
	String filename = packageFile.getCanonicalPath();
	.....
	配置update_package指令
	final String filenameArg = "--update_package=" + filename + "\n";
	final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "\n";
	final String securityArg = "--security\n";
	String command = filenameArg + localeArg;
    if (securityUpdate) {
        command += securityArg;
    }
    RecoverySystem rs = (RecoverySystem) context.getSystemService(
                    Context.RECOVERY_SERVICE);
    写入指令                
    if (!rs.setupBcb(command)) {
            throw new IOException("Setup BCB failed");
    }

    Having set up the BCB (bootloader control block), go ahead and reboot
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    String reason = PowerManager.REBOOT_RECOVERY_UPDATE;
		.....
	重启系统进入recovery模式	
    pm.reboot(reason);
}

升级过程原理分析

上面两个升级过程实质都是告诉系统,升级包在哪里,而没有打开、解析包内容等;而这些操作都是进入Recovery模式后,由Recovery任务来完成;
重启进入Recovery模式后,会发现/cache/recovery下有command指令,就会分析其指令并执行,其分析过程如下代码:

int arg;  
        while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {  
        switch (arg) {  
        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 't': show_text = 1; break;  
        case 'x': just_exit = true; break;  
        case 'l': locale = optarg; break;  
        case 'g': {  
        if (stage == NULL || *stage == '\0') {  
        char buffer[20] = "1/";  
        strncat(buffer, optarg, sizeof(buffer)-3);  
        stage = strdup(buffer);  
        }  
        break;  
        }  
        case 'p': shutdown_after = true; break;  
        case 'r': reason = optarg; break;  
        case '?':  
        LOGE("Invalid command argument\n");  
        continue;  
        }

看到没?Recovery可以做很多事情,同理,你可以往/cache/recovery里面写入wipe_data来擦除数据区;
升级过程大致可以分为:

  • 校验文件签名
  • 打开升级文件
  • 执行升级脚本try_update_binary
    最后一个步骤中,会创建一个子进程,子进程中执行update中的binary脚本,通过管道与父进程通信;最后完成升级,重启,清除command文件,否则第二次还会出现升级
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气好男人_Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值