本文转载自:https://blog.csdn.net/huangyabin001/article/details/44465145

版权声明:本文为博主原创文章,未经博主允许不得转载。    https://blog.csdn.net/huangyabin001/article/details/44465145
写在前面:
    为了帮助理解,这里首先描述一个应用场景。

一个项目有两个版本(一个项目两个版本的原因或许是由于硬件不同导致的,如不同容量电池,不同分辨率摄像头等),在升级的时候很容易将相同项目的两个版本的升级包混淆,因此需要实现两个版本的防互刷功能,那么在该应用场景下需要如何实现呢?

注意,这里肯定会有疑问了,既然一个项目两个版本容易混淆更新包,那么把它作为两个项目来实施不是有效避免这个问题了吗?当然,把一个项目由于不同版本分拆为不同的项目来做当然可以有效的避免更新包混淆的问题,这也是一个比较快捷的方案。因此该博文是在实施一个项目的场景下来开展的。

第一步:了解校验原理
熟悉ota_from_target_files、edify_generator.py或则了解install.c和updater-script脚本执行过程的朋友应该很清楚在更新包安装的一开始会对一些属性信息进行校验,这里贴出部分脚本生成器edify_generator.py的相关的函数:

#校验时间戳

def AssertOlderBuild(self, timestamp, timestamp_text):
    """Assert that the build on the device is older (or the same as)
    the given timestamp."""
    self.script.append(
        ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || '
         'abort("Can\'t install this package (%s) over newer '
         'build (" + getprop("ro.build.date") + ").");'
         ) % (timestamp, timestamp_text))

校验时间戳,我们需要理解上面的方法,上面的函数只是生成一条edify语句,实际上在生成的updater-script脚本中,也就是下面这条语句:

(!less_than_int(%s, getprop("ro.build.date.utc")))①||abort("Can\'t install this package (%s) over newer build (" + getprop("ro.build.date") + ").");②

arg1:timestamp, arg2:timestamp_text//参数1为世界时间,参数2为日期格式

上面的代码告诉我们如果①的值为True则执行下一步,否则执行语句②,语句①对比时间戳大小,语句②为中断语句。也就是说如果当前更新包的打包时间如果比手机Build的时间older,就执行中止语句。

#校验设备信息
  def AssertDevice(self, device):
    """Assert that the device identifier is the given string."""
    cmd = ('getprop("ro.product.device") == "%s" || '
           'abort("This package is for \\"%s\\" devices; '
           'this is a \\"" + getprop("ro.product.device") + "\\".");'
           ) % (device, device)
    self.script.append(cmd)

若更新包中打包的设备信息如果与手机Build中的设备信息不一致就会执行中止语句。

#校验系统指纹

def AssertSomeFingerprint(self, *fp):
    """Assert that the current system build fingerprint is one of *fp."""
    if not fp:
      raise ValueError("must specify some fingerprints")
    cmd = (
           ' ||\n    '.join([('file_getprop("/system/build.prop", '
                         '"ro.build.fingerprint") == "%s"')
                        % i for i in fp]) +
           ' ||\n    abort("Package expects build fingerprint of %s; this '
           'device has " + getprop("ro.build.fingerprint") + ".");'
           ) % (" or ".join(fp),)
    self.script.append(cmd)

若更新包中新旧版本的系统指纹与当前手机中的系统指纹不一致就会执行中止语句。
无论是时间戳还是设备信息还是系统指纹都是从build.prop中取值。但是,这里呢,要对fingerprint信息简单介绍一下,fingerprint就是我们常说的系统指纹,我们可以在adb模式下能否通过getprop ro.build.fingerprint的方式进行查看或者参考alps\frameworks\base\core\java\android\os\Build.java下对应的FINGERPRINT的取值方式在代码中进行取值。每个项目的每个版本Fingerprint都不同,按照Google的要求,前后不允许带有空格、空行、断行,字符不超过91个,

Fingerprint字段定义格式如下:
BUILD_FINGERPRINT :=
$(PRODUCT_BRAND)/$(TARGET_PRODUCT)/$(TARGET_DEVICE):$(PLATFORM_VERSION)/$(BUILD_ID)/$(BUILD_NUMBER):$(TARGET_BUILD_VARIANT)/$(BUILD_VERSION_TAGS)
如:Google/Y100-T00/GoogleY100-T:4.2.2/GoogleY100-T00/CHSC01B001:user/release-keys
TCT/TCL_J900T/Camry2_TD:4.2.1/JOP40D/TCL_J900T_V2.0:user/release-keys
具体配置请按以下:
1.PRODUCT_BRAND为getprop文件中的相关字段:ro.product.brand的信息,全字母大写or首字母大写均可。Eg:Google
2.TARGET_PRODUCT为getprop文件中的相关字段:ro.product.name的信息,全字母大写,Eg:Y516-T00。
3.TARGET_DEVICE为getprop文件中的相关字段:ro.product.device的信息
4.ID为getprop文件中的相关字段:ro.build.id的信息,
5.version.incremental为getprop文件中的相关字段:ro.build.version.incremental的信息。要求version.incremental是内部版本号(真实版本号)
6.VERSION.RELEASE为getprop文件中的相关字段:ro.build.version.release的信息,一般为Android系统版本号
7.TYPE必须是user版本,不能是eng版本。
8.TAGS必须是release-keys,不能是test-keys,(将宏MTK_SIGNATURE_CUSTOMIZATION = yes)。如果该版本带有或者后续将开发OTA升级功能,须使用ota-rel-keys,release-keys,普通版本请使用release-keys。

那么系统指纹在差分升级的时候才会校验,设备信息和签名一般来说同一个项目后者同一个产品对于客户来讲都是不允许修改的,如果客户允许这些也可以作为防互刷的手段。那么可能到这里你或许已经明白这篇博文的目的了。

那么,对的,本篇博文主要是通过增加新的系统属性来标识相同项目不同版本防互刷的功能。那么该如何实现呢?

第二步:添加校验标识
一、添加系统属性

这里需要在/vendor/{项目}/{项目分支}/config/system.prop文件,当然不同平台不同公司对应的system.prop路径不一致

这里我在system.prop中最后一行添加如下属性:

ro.update.version=a1

二、修改脚本

首先在脚本生成器edifty_generator.py文件中定义如下方法:

def AssertUpdateVersion(self, update_version):
    """Assert that the update_version identifier is the given string."""
    cmd = ('getprop("ro.update.version") == "%s" || '
           'abort("This package is for \\"%s\\" update_version; '
           'this is a \\"" + getprop("ro.update.version") + "\\".");'
           ) % (update_version, update_version)
    self.script.append(cmd)
然后在ota_from_target_file文件中的AppendAssertions函数中添加如下:(红色为新添加)
def AppendAssertions(script, info_dict):
      device = GetBuildProp("ro.product.device", info_dict)
      script.AssertDevice(device)
      update_version = GetBuildProp("ro.update.version", info_dict)//从字典中去除ro.update.version的值
      script.AssertUpdateVersion(update_version)//在升级脚本中添加验证新的属性函数
并修改WriteFullOTAPackage()函数,如下:

def WriteFullOTAPackage(input_zip, output_zip):
  # TODO: how to determine this?  We don't know what version it will
  # be installed on top of.  For now, we expect the API just won't
  # change very often.
  script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict)

metadata = {"post-build": GetBuildProp("ro.build.fingerprint",
                                         OPTIONS.info_dict),
              "pre-device": GetBuildProp("ro.product.device",
                                         OPTIONS.info_dict),
              "post-timestamp": GetBuildProp("ro.build.date.utc",
                                             OPTIONS.info_dict),
              "update-version": GetBuildProp("ro.update.version",
                                             OPTIONS.info_dict),//定义新的属性
              }

三、验证(注!不要偷懒,直接修改update包中的build.pro,否则会校验签名不过的)

那么接下来就需要进行验证了,这里呢首先使用ro.update.version值为a1的版本制作整包,然后在手机中download属性ro.update.version值为a2的版本进行sd卡整包升级,在升级的过程中会对update-version进行校验,如果值不一样则校验失败。

下面贴出校验失败的log(也就是防互刷功能成功实现的效果)

script aborted: This package is for "a1" update_version; this is a "a2".
This package is for "a1" update_version; this is a "a2".
E:Error in /sdcard/dload/update.zip
(Status 7)
Installation aborted.

I:no boot messages recovery
I:[1]check the otaupdate is done!
factory_poweroff_flag=0
demo_mode_flag=0

下面是对应的updater-script脚本中防互刷的语句。

getprop("ro.update.version") == "a1" || abort("This package is for \"a1\" update_version; this is a \"" + getprop("ro.update.version") + "\".");

Android系统更新防互刷功能实现与分析【转】的更多相关文章

  1. 利用 Android 系统原生 API 实现分享功能

    利用 Android 系统原生 API 实现分享功能 这篇文章提供一个封装好的 Share2 库供大家参考. GitHub 项目地址:Share2 大家知道,要调用 Android 系统内建的分享功能 ...

  2. android系统又一次刷ROM简记(一)

    当须要对android系统进行大刀阔斧的改造的时候,应该清晰的了解android各个image的组成才干做到庖丁解牛. 首先在android烧写过程中须要烧写的文件主要包含uboot.bin\boot ...

  3. Android 系统自带图片裁剪功能(适配7.0、8.0、对了还有小米手机)

    前段时间写了如何获取相册和拍照之后的照片并且进行显示和上传,这一次是如何进行圆形图像制作,经常看我写的笔记的人会知道,我很懒.那么我就懒的自定义了,目前需求就用原生的就好了,大神的轮子,我会在后面进行 ...

  4. 修改Android系统属性SystemProperties.set("sys.powerctl", "shutdown")关机分析

    简介: 从之前的博文中我们提到过,关机流程中最后是通过修改Android属性进行关机操作(SystemProperties.java通过JNI调用访问系统属性),当然我们也可以通过adb命令修改And ...

  5. 开机时候系统总是提醒Android系统更新

    今天刷了个android的rom,平常没有经常刷机,对这个也不是特别了解. 但是刷完开机,显示系统升级,一开始都是18个app,后来捣鼓了几次,安装了几个常用的软件,居开机的时候,升级的app需要90 ...

  6. Android系统定制----删除系统锁屏功能【转】

    本文转载自:http://blog.csdn.net/morixinguan/article/details/56675914 frameworks/base/packages/SettingsPro ...

  7. Android系统源码学习步骤

    Android系统是基于Linux内核来开发的,在分析它在运行时库层的源代码时,我们会经常碰到诸如管道(pipe).套接字(socket)和虚拟文件系统(VFS)等知识. 此外,Android系统还在 ...

  8. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共 ...

  9. Android系统的开机画面显示过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/7691321 好几个月都没有更新过博客了,从今天 ...

随机推荐

  1. 初识Vue,简单的todolist

    vue开发源码:https://vuejs.org/js/vue.js todolist代码: <!DOCTYPE html> <html lang="en"&g ...

  2. javaweb防止表单重新提交

    一.前台验证 1.首先在from表单加一个隐藏域字段,设值为true.例如: <input type="hideen" name="tokenFlag" ...

  3. FSDB Dumper

    FSDB:Fast Signal Database 相比较于VCD文件,FSDB文件的大小比VCD波形小5-50倍. 各家的仿真器都支持在simulation的过程中,直接生成FSDB文件 将VCD文 ...

  4. DX9 顶点缓存案例

    // @time 2012.3.5 // @author jadeshu //包含头文件 #include <Windows.h> #include <d3d9.h> #pra ...

  5. <7>Cocos Creator 节点 cc.Node

    1.简介 节点(cc.Node)是渲染的必要组成部分.所有需要在游戏场景中显示的内容都必须是节点或者依附于节点之上.节点负责控制显示内容的位置.大小.旋转.缩放.颜色等信息. 2.节点属性 1: na ...

  6. python-demo实例

    1.turtle库与蟒蛇案例 import turtle def drawSnake(rad,angle,len,neckrad): for i in range(len): turtle.circl ...

  7. 标准I/O流

    一.标准输入流 标准输入流对象cin,重点掌握的函数 cin.get() //一次只能读取一个字符 cin.get(一个参数) //读一个字符 cin.get(三个参数) //可以读字符串 cin.g ...

  8. Lua用一维数组存储一个n阶方阵,输出这个方阵的正对角线上的数的和与反对角线上的数的和的差的绝对值。

    arr = {, , , , , , , , -} function diagonalDifference(arr) dimesion = math.sqrt(#arr) arr1 = {} sum1 ...

  9. spring boot: ConfigurationProperties

    读取配置信息 1.5 之前 @Component @ConfigurationProperties(prefix = "user", locations= {"class ...

  10. python os.path.basename()方法

    返回path最后的文件名.如果path以/或\结尾,那么就会返回空值.即os.path.split(path)的第二个元素. >>> import os >>> p ...