• Android不同设备字符串显示原理和build.prop生成过程


    1. 问题背景

            在Android各设备上,同一个字符串ID,通过配置不同的product参数用来显示不同的字符串,这样子就可以用一套代码,不同设备加载不同的字符串资源,显示在不同的终端设备上,呈现给用户的描述就是合理准确的,我们来看看字符串ID是怎么定义的

     同一个字符串ID,这里有四种产品型号:平板,手机,其他设备,模拟器,这样子不同的设备上就显示了对应的"关于xx"的字符串。

    2. 问题描述

            我的设备明明是平板设备,但是显示的是“关于手机”的字符串,明显不对。应该就是产品属性相关的配置项没有配置对,也就是product="XXX"的值不对。

    3. 相关字段

            通过以往的工作经验,涉及的配置项为:ro.build.characteristics= ?

    default默认为手机设备。而我手上的设备为平板,我该如何修改呢?

            我们来看看此ro值是位于平板设备的product/build.prop文件中,那此ro属性是如何编译到build.prop文件中来的呢,我们一起来探究下?

    4. 加载原理

            涉及到编译脚本文件基本都在 build/make/core/ 此路径下,我们找一下此属性定义的位置:

    build/make/core/Makefile 文件中

     来看看具体定义内容:

    1. $(hide) echo "#" >> $@; \
    2. echo "# ADDITIONAL PRODUCT PROPERTIES" >> $@; \
    3. echo "#" >> $@; \
    4. echo "ro.build.characteristics=$(TARGET_AAPT_CHARACTERISTICS)" >> $@;

    也就是ro属性的值是变量 TARGET_AAPT_CHARACTERISTICS定义的,接下来看看它是定义的地方: build/make/core/product_config.mk

     这段话的意思:

            如果没有定义 PRODUCT_CHARACTERISTICS,则默认为default值,也就是手机产品,如果定义了,则为其定义的产品类型,好了到这里,就知道怎么去配置了,所以最后需要配置

    PRODUCT_CHARACTERISTICS :=  tablet 就可以解决啦!

    5. product/build.prop 生成过程

    Android10的源码路径为:build/make/core/makefile文件

    1. # -----------------------------------------------------------------
    2. # product build.prop
    3. INSTALLED_PRODUCT_BUILD_PROP_TARGET := $(TARGET_OUT_PRODUCT)/build.prop
    4. $(warning 调试 in Makefile 打印TARGET_OUT_PRODUCT的值: $(TARGET_OUT_PRODUCT))
    5. ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_PRODUCT_BUILD_PROP_TARGET)
    6. ifdef TARGET_PRODUCT_PROP
    7. product_prop_files := $(TARGET_PRODUCT_PROP)
    8. else
    9. product_prop_files := $(wildcard $(TARGET_DEVICE_DIR)/product.prop)
    10. $(warning 调试 in Makefile 打印TARGET_DEVICE_DIR的值: $(TARGET_DEVICE_DIR))
    11. endif
    12. FINAL_PRODUCT_PROPERTIES += \
    13. $(call collapse-pairs, $(PRODUCT_PRODUCT_PROPERTIES) $(ADDITIONAL_PRODUCT_PROPERTIES))
    14. FINAL_PRODUCT_PROPERTIES := $(call uniq-pairs-by-first-component, \
    15. $(FINAL_PRODUCT_PROPERTIES),=)
    16. $(INSTALLED_PRODUCT_BUILD_PROP_TARGET): $(BUILDINFO_COMMON_SH) $(product_prop_files)
    17. @echo Target product buildinfo: $@
    18. @mkdir -p $(dir $@)
    19. $(hide) echo > $@
    20. ifdef BOARD_USES_PRODUCTIMAGE
    21. $(hide) $(call generate-common-build-props,product,$@)
    22. endif # BOARD_USES_PRODUCTIMAGE
    23. $(hide) $(foreach file,$(product_prop_files), \
    24. if [ -f "$(file)" ]; then \
    25. echo Target product properties from: "$(file)"; \
    26. echo "" >> $@; \
    27. echo "#" >> $@; \
    28. echo "# from $(file)" >> $@; \
    29. echo "#" >> $@; \
    30. cat $(file) >> $@; \
    31. echo "# end of $(file)" >> $@; \
    32. fi;)
    33. $(hide) echo "#" >> $@; \
    34. echo "# ADDITIONAL PRODUCT PROPERTIES" >> $@; \
    35. echo "#" >> $@; \
    36. echo "ro.build.characteristics=$(TARGET_AAPT_CHARACTERISTICS)" >> $@;
    37. $(hide) $(foreach line,$(FINAL_PRODUCT_PROPERTIES), \
    38. echo "$(line)" >> $@;)
    39. $(hide) build/make/tools/post_process_props.py $@
    40. $(error 调试 到这里停止)

    代码解读:

            1. 首先看了这段代码,内容不多,我们一句一句来分析下,首先把关键的位置加上log,并在结尾加上:$(error 调试 到这里停止), 在工程中编译,就会到这里停止下来。

            2. 编译工程自己加的打印log如下:

    1. build/make/core/Makefile:289: warning: 调试 in Makefile 打印TARGET_OUT_PRODUCT的值 out/target/product/ums512_1h10/product
    2. build/make/core/Makefile:413: warning: 调试 in Makefile 打印TARGET_DEVICE_DIR的值 device/sprd/sharkl5Pro/ums512_1h10
    3. build/make/core/Makefile:497: error: 调试 到这里停止

    产品工程为展锐平台:sprd   产品项目名:ums512_1h10

    关于在Makefile中如何添加打印log,请移步到我的另外一篇文章:Android源码编译makefile文件的调试方法_broadview_java的博客-CSDN博客

            3.  INSTALLED_PRODUCT_BUILD_PROP_TARGET := $(TARGET_OUT_PRODUCT)/build.prop 这句话表达的意思是:最后编译版本的输出路径为out/target/product/ums512_1h10/product/build.prop

            4. product_prop_files := $(wildcard $(TARGET_DEVICE_DIR)/product.prop) :

            wildcard 是通配符的意思,代码表达的意思:就是遍历device/sprd/sharkl5Pro/ums512_1h10路径下的所有product.prop文件,赋值给product_prop_files变量。

            5. 

    1. FINAL_PRODUCT_PROPERTIES += \
    2.     $(call collapse-pairs, $(PRODUCT_PRODUCT_PROPERTIES) $(ADDITIONAL_PRODUCT_PROPERTIES))

            这段代码里面有个call方法  collapse-pairs 就是函数名,后面带两个参数,我们看看这个函数定义的地方:build/make/core/common/string.mk

    1. ###########################################################
    2. ## Convert "a=b c= d e = f" into "a=b c=d e=f"
    3. ##
    4. ## $(1): list to collapse
    5. ## $(2): if set, separator word; usually "=", ":", or ":="
    6. ## Defaults to "=" if not set.
    7. ###########################################################
    8. define collapse-pairs
    9. $(eval _cpSEP := $(strip $(if $(2),$(2),=)))\
    10. $(strip $(subst $(space)$(_cpSEP)$(space),$(_cpSEP),$(strip \
    11. $(subst $(_cpSEP), $(_cpSEP) ,$(1)))$(space)))
    12. endef

            就是把 =  : := 赋值的语句,或带有空格的赋值语句,统一格式化为 a=b 得样式

            6. 

    1. FINAL_PRODUCT_PROPERTIES := $(call uniq-pairs-by-first-component, \
    2. $(FINAL_PRODUCT_PROPERTIES),=)

            这段代码,就是调用 uniq-pairs-by-first-component 函数,同样我们看看定义的地方:

    build/make/core/common/string.mk文件中

    1. ###########################################################
    2. ## Given a list of pairs, if multiple pairs have the same
    3. ## first components, keep only the first pair.
    4. ##
    5. ## $(1): list of pairs
    6. ## $(2): the separator word, such as ":", "=", etc.
    7. define uniq-pairs-by-first-component
    8. $(eval _upbfc_fc_set :=)\
    9. $(strip $(foreach w,$(1), $(eval _first := $(word 1,$(subst $(2),$(space),$(w))))\
    10. $(if $(filter $(_upbfc_fc_set),$(_first)),,$(w)\
    11. $(eval _upbfc_fc_set += $(_first)))))\
    12. $(eval _upbfc_fc_set :=)\
    13. $(eval _first:=)
    14. endef

            就是去掉重复的赋值语句,只保留第一条

            7. 

    1. $(INSTALLED_PRODUCT_BUILD_PROP_TARGET): $(BUILDINFO_COMMON_SH) $(product_prop_files)
    2. @echo Target product buildinfo: $@
    3. @mkdir -p $(dir $@)
    4. $(hide) echo > $@

            这段代码就是一个target 语句,makefile的语法规则如下:

     翻译过来就是:

    out/target/product/ums512_1h10/product/build.prop 是由下面2个文件编译生成的:

    BUILDINFO_COMMON_SH := build/make/tools/buildinfo_common.sh
    

     还有device/sprd/sharkl5Pro/ums512_1h10路径下的所有product.prop。

    $(hide)  我们来看看  hide这个变量定义的地方: build/make/core/config.mk

    hide := @
    

    通常makefile会将其执行的命令行在执行前输出到屏幕上。如果将‘@’添加到命令行前,这个命令将不被make回显出来。
    例如:@echo  --hello world----;    // 屏幕输出       --hello world----
                 echo  --hello world----;    // 没有@ 屏幕输出    echo  --hello world---- 

           8. 

    1. $(hide) $(foreach file,$(product_prop_files), \
    2. if [ -f "$(file)" ]; then \
    3. echo Target product properties from: "$(file)"; \
    4. echo "" >> $@; \
    5. echo "#" >> $@; \
    6. echo "# from $(file)" >> $@; \
    7. echo "#" >> $@; \
    8. cat $(file) >> $@; \
    9. echo "# end of $(file)" >> $@; \
    10. fi;)

            这段代码通过for循环语句,把4中device/sprd/sharkl5Pro/ums512_1h10路径下的所有product.prop文件的内容重定向输出到同一个product.prop中

             9. 

    1. $(hide) echo "#" >> $@; \
    2. echo "# ADDITIONAL PRODUCT PROPERTIES" >> $@; \
    3. echo "#" >> $@; \
    4. echo "ro.build.characteristics=$(TARGET_AAPT_CHARACTERISTICS)" >> $@;

           这里就是把 ro.build.characteristics属性编译到build.prop文件中,好了,到这里就分析完毕了。

    6. product/build.prop 内容

     内容如下:

    我们配置的PRODUCT_CHARACTERISTICS :=  table 属性最终编译生成到product/build.prop 文件中。

    7. 总结

           系统生成的system/build.prop  vendor/build.prop  分析方法也同上,首先还是要掌握makefile和shell的基本语法规则,然后也要了解makefile的调试方法,看不懂的地方去打log看,就大致明白其编译过程了。

           

  • 相关阅读:
    Ctfshow web入门 phpCVE篇 web311-web315 详细题解 全
    Linux cp命令:复制文件和目录
    滴滴SQL面试题之打车业务问题如何分析
    kafka_2.10启动Kafka broker
    网络安全(黑客)自学
    uniapp基础篇 - - 页面跳转和传值
    最受欢迎的30款开源软件
    玩转Linux与运维岗(36)
    React经典初级错误
    C语言的多级指针的上限及实现方法
  • 原文地址:https://blog.csdn.net/u012514113/article/details/126563061