车载设置--自定义版本信息 build.prop生成过程分析

需求分析
在车载设置中,通常会有系统信息选项卡,里面主要列出的是系统版本,MCU 版本,蓝牙版本等等,MCU 版本能通过 mcu 获取,蓝牙版本有蓝牙 API 提供,而系统版本通常是自定义的字符串,如果由应用来定义,可能的隐患是不确定系统是不是最新的,因为 apk 能通过 adb push 推送到系统中,继而获得最新的系统版本号。如果由系统提供,可是通过 Build 提供的 api 又不符合我们的实际需求,所以我们需要自定义 api 来获取我们自定义的版本信息。

源码浅析
通常获取系统版本信息如下:

String version = Build.VERSION.RELEASE;

简简单单的一句话就获取到了系统版本信息,就让我们从源码角度深入分析是如何获取系统信息的。

public static class VERSION {
        /**
         * The internal value used by the underlying source control to
         * represent this build.  E.g., a perforce changelist number
         * or a git hash.
         */
        public static final String INCREMENTAL = getString("ro.build.version.incremental");

        /**
         * The user-visible version string.  E.g., "1.0" or "3.4b5".
         */
        public static final String RELEASE = getString("ro.build.version.release");

        /**
         * The user-visible SDK version of the framework in its raw String
         * representation; use {@link #SDK_INT} instead.
         * 
         * @deprecated Use {@link #SDK_INT} to easily get this as an integer.
         */
        @Deprecated
        public static final String SDK = getString("ro.build.version.sdk");

        /**
         * The user-visible SDK version of the framework; its possible
         * values are defined in {@link Build.VERSION_CODES}.
         */
        public static final int SDK_INT = SystemProperties.getInt(
                "ro.build.version.sdk", 0);

        /**
         * The current development codename, or the string "REL" if this is
         * a release build.
         */
        public static final String CODENAME = getString("ro.build.version.codename");

        /**
         * The SDK version to use when accessing resources.
         * Use the current SDK version code.  If we are a development build,
         * also allow the previous SDK version + 1.
         * @hide
         */
        public static final int RESOURCES_SDK_INT = SDK_INT
                + ("REL".equals(CODENAME) ? 0 : 1);
    }

从源码上可以看出,VERSION 是 Build 的一个静态内部类,里面定义了很多静态常量,有我们熟悉的 SDK ,RELEASE 等,而 SDK 的值则是通过函数 getString 获得:

 private static String getString(String property) {
        return SystemProperties.get(property, UNKNOWN);
    }

在 getString 函数中,通过 SystemProperties 获得版本信息,SystemProperties 存储方式有点类似 key-value 的方式,而它的值主要存储在 system/build.prop 中,让我们看看你们的内容:

# begin build properties
# autogenerated by buildinfo.sh
ro.build.id=KOT49H
ro.build.display.id=t3_p3-eng 4.4.2 KOT49H 20171018 test-keys
ro.build.version.incremental=20171018
ro.build.version.sdk=19
ro.build.version.codename=REL
ro.build.version.release=4.4.2

# end build properties

#
# ADDITIONAL_BUILD_PROPERTIES
#

限于篇幅,只截取了一部分代码,从代码中看出 key 值 为 ro.build.version.release 的 value 为 4.4.2,说明我们的系统版本为 4.4.2。那么 ro.build.version.release 的值又是怎么来的?

build.prop生成过程分析
Android 的 build.prop 文件是在 Android 编译时刻收集的各种 property(LCD density/语言/编译时间, etc.),编译完成之后,文件生成在 out/target/product/board/system/ 目录下。在 Android 运行时刻可以通过 SystemProperties_get*() 读取这些属性值。build.prop 的生成是由make 系统解析 build/core/Makefile 完成,Makefile 又是如何工作的呢?

1.Makefile 中首先定义各种变量,这在下一步执行时会用到。比如:

PRODUCT_MODEL="$(PRODUCT_MODEL)" \
PRODUCT_MANUFACTURER="$(PRODUCT_MANUFACTURER)" \
PRIVATE_BUILD_DESC="$(PRIVATE_BUILD_DESC)" \
BUILD_ID="$(BUILD_ID)" \
BUILD_DISPLAY_ID="$(BUILD_DISPLAY_ID)" \
BUILD_NUMBER="$(BUILD_NUMBER)" \
PLATFORM_VERSION="$(PLATFORM_VERSION)" \
PLATFORM_SDK_VERSION="$(PLATFORM_SDK_VERSION)" \
PLATFORM_VERSION_CODENAME="$(PLATFORM_VERSION_CODENAME)" \
BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \

2.Makefile中调用 build/tools/buildinfo.sh 执行脚本,并输出到build.prop.Buildinfo.sh 很简单,只是 echo 一些属性,比如:

echo "# begin build properties"
echo "# autogenerated by buildinfo.sh"

echo "ro.build.id=$BUILD_ID"
echo "ro.build.display.id=$BUILD_DISPLAY_ID"
echo "ro.build.version.incremental=$BUILD_NUMBER"
echo "ro.build.version.sdk=$PLATFORM_SDK_VERSION"
echo "ro.build.version.codename=$PLATFORM_VERSION_CODENAME"
echo "ro.build.version.release=$PLATFORM_VERSION"
echo "ro.build.date=`date`"
echo "ro.build.date.utc=`date +%s`"
echo "ro.build.type=$TARGET_BUILD_TYPE"
echo "ro.build.user=$USER"
echo "ro.build.host=`hostname`"
echo "ro.build.tags=$BUILD_VERSION_TAGS"

ro.build.version.release 是系统属性,等号后面是值, $PLATFORM_VERSION” 表示取变量 PLATFORM_VERSION 的值,而 PLATFORM_VERSION 又是在 build/core/Makefile 定义并赋值的。

3.Makefile 中直接把 $(TARGET_DEVICE_DIR)/system.prop 的内容追加到 build.prop中。

 bash $(BUILDINFO_SH) > $@
        $(hide) $(foreach file,$(system_prop_file), \
                if [ -f "$(file)" ]; then \
                        echo "#" >> $@; \
                        echo Target buildinfo from: "$(file)"; \
                        echo "# from $(file)" >> $@; \
                        echo "#" >> $@; \
                        cat $(file) >> $@; \
                fi;)

在 build.prop 中为打印 from system.prop 这句话,说明我们的 $(TARGET_DEVICE_DIR) 没有 system.prop 文件。

4.收集 ADDITIONAL_BUILD_PROPERTIES 中的属性,追加到 build.prop 中。
ADDITIONAL_BUILD_PROPERTIES 又会收集 PRODUCT_PROPERTY_OVERRIDES 中定义的属性

ADDITIONAL_BUILD_PROPERTIES := \
    $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))
ADDITIONAL_BUILD_PROPERTIES := $(call uniq-pairs-by-first-component, \
    $(ADDITIONAL_BUILD_PROPERTIES),=)

////////在build.prop 中有打印这句话//////////
 $(if $(ADDITIONAL_BUILD_PROPERTIES), \
                $(hide) echo >> $@; \
                        echo "#" >> $@; \
                        echo "# ADDITIONAL_BUILD_PROPERTIES" >> $@; \
                        echo "#" >> $@; )

总结
通过上述代码分析,当我们通过 Build.VERSION.RELEASE 获取系统版本信息时,会调用 SystemProperties.get(property, UNKNOWN) 方法。而 ro.build.version.release 的赋值是在编译时期 build/tools/buildinfo.sh 通过echo 而赋值的。那么如果我们自定义版本信息,只需要在 buildinfo.sh 赋值,写到 SystemProperties 属性中,再在 Build 提供 api 来获取不就 ok 了。

移植过程
1.在 VERSION 中增加自定义静态字段

 public static final String XX_VERSION = getString("ro.build.xx.version");

2.在 build/tools/buildinfo.sh 中对 ro.build.xx.version 赋值。

echo "ro.build.xx.version=xx.veersion.10.25"

3.使用

String version = Build.VERSION.XX_VERSION; 来获取我们自定义的版本信息

happy a nice day!

猜你喜欢

转载自blog.csdn.net/liqianwei1230/article/details/78336906