欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android系统编译小小理解

程序员文章站 2022-08-29 13:06:38
Android系统编译简介搭建编译环境系统编译命令常见小知识点Android编译版本Android.mk文件编译系统中的变量和宏native layer编译碰到的问题安装lib32bz2-1.0出问题add-apt-repository命令不存在Jack server installation not foundsubcommand failed问题内核目录下存在.config文件导致编译错误输出目录中的重要目录编译模块系统属性相关目标和依赖文件的定义打包新添加的模块至system.img简介Andro...

简介

Android系统源码将Makefile划分成一个个Makefile片段,通过Makefileinclude指令将这些片段组装成一个Makefile,因此Android.mk编译脚本其实是整个Android编译系统的一个Makefile片段,编译时编译系统会遍历每个目录下的Android.mk文件。

搭建编译环境

sudo apt-get install u-boot-tools
 
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev lib32ncurses5 lib32z1 x11proto-core-dev libx11-dev lib32z1-dev
 
sudo apt-get install build-essential subversion git-core libncurses5-dev zlib1g-dev gawk flex quilt libssl-dev xsltproc libxml-parser-perl mercurial bzr ecj cvs unzip lib32z1 lib32ncurses5 lib32bz2-1.0
 
sudo apt-get install libxml2-utils
 
sudo apt-get install subversion openssh-client openssh-server samba git-core git-gui vim
 
sudo add-apt-repository ppa:git-core/ppa
 
sudo apt-get update
 
sudo apt-get upgrade
 
sudo apt-get install libswitch-perl
 
sudo apt-get install rar unrar
 
sudo apt-get install gawk
 
sudo apt-get install bc

搭建编译环境官方文档(有关JDK要求)

系统编译命令

  1. source build/envsetup.sh
  • 此命令会将vendor和device目录中厂商指定的envsetup.sh加载到当前shell中,获取厂商提供的产品配置信息。脚本文件build/envsetup.sh提供编译所需的重要命令用于编译Android源码。build/envsetup.sh脚本中的函数
    add_lunch_combo会被多次调用,用来添加Android编译选项。
  1. lunch
  • 用于初始化编译环境,指定目标产品类型和编译类型。第二件事是通过make命令执行build/core/config.mk脚本,并且加载另一个脚本build/core/dumpvar.mk来打印出当前的编译环境配置信息。
  1. m
  • 相当于make命令
  1. mm和mmm
  • 用于模块编译
  1. 查看编译命令
  • mmm ./ showcommands

常见小知识点

Android编译版本

  • user :权限受限;适用于生产环境
  • userdebug: 与“user”类似,但具有 root 权限和可调试性;是进行调试时的首选编译类型
  • eng : 具有额外调试工具的开发配置

Android.mk文件

Android.mk是编译系统解析一次或多次的微小Makefile片段。Android.mk的语法支持将源文件分组为模块。模块是静态库、动态库或独立的可执行程序。可在每个Android.mk中定义一个或多个模块,也可在多个模块中使用同一个源文件。

LOCAL_PATH := $(call my-dir)
//表示源文件在开发树中的位置,my-dir是编译系统提供的宏函数,返回当前目录的路径

LOCAL_MODULE:= service_manager_my
// 指定生成的模块名,不能包含空格

include $(BUILD_EXECUTABLE)
// BUILD_EXECUTABLE表示我们要编译的是可执行程序

include $(CLEAR_VARS)
// 清空编译环境的变量,会清除许多LOCAL_XXX变量

LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-unused-variable
LOCAL_CFLAGS += -Wno-unused-function
LOCAL_CFLAGS += -Wincompatible-pointer-types
// 指定忽略一些未使用的变量或函数

LOCAL_SRC_FILES:= test_server.c binder.c
// 指定源文件,包含要编译到模块中的C/C++源文件列表

LOCAL_C_INCLUDES += system/core/libcutils/include/
// 指定头文件路径,指定的路径是相对于NDK编译系统根目录的路径

LOCAL_MODULE_TAGS := user eng optional test
// 各项具体说明如下:
1、user:只有在user版本时该模块才被编译进去;
2、eng:只有在eng版本时该模块才被编译进去;
3、test:只有在tests版本时该模块才被编译进去;
4、optional:在所有版本中都编译该模块进去。

用于设置该app是否要安装到priv-app下
LOCAL_PRIVILEGED_MODULE = true

不开启odex,不生成APP的dex文件,不进行预先优化,节省空间,可编译出完整的apk
LOCAL_DEX_PREOPT = false

如果预置的APK,要覆盖原生apk,则需在android.mk中添加以下选项,此变量可以使其他的模块不加入编译。
LOCAL_OVERRIDES_PACKAGES

  • 特别注意不要在Android.mk文件中添加无谓的空格,编译报错找不到原因很痛苦的!

编译系统中的变量和宏

编译系统提供了许多可在Android.mk中使用的变量。NDK编译系统保留了下列变量名称:

以 LOCAL_ 开头的名称,例如 LOCAL_MODULE。
以 PRIVATE_、NDK_ 或 APP 开头的名称。编译系统在内部使用这些变量名。
小写名称,例如 my-dir。编译系统也是在内部使用这些变量名。

指向用于指定预编译共享库的编译脚本。与 BUILD_SHARED_LIBRARYBUILD_STATIC_LIBRARY 的情况不同,这里的 LOCAL_SRC_FILES 值不能是源文件,而必须是指向预编译共享库的一个路径,例如 foo/libfoo.so。使用此变量的语法为:

include $(PREBUILT_SHARED_LIBRARY)

指定生成的模块名称。例如,如果LOCAL_MODULE 的名称为 foo,可以强制系统将它生成的文件命名为 libnewfoo。

LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo

native layer

本地应用程序指的是可以直接运行在操作系统上,并且处理器直接执行机器码的程序。比如windows上的各种*.exe的程序,而linux上的是各种bin程序。
在Android上,OS是linux,因此各种bin程序就是所谓natvie application了,比如**/system/bin**目录下的所有文件。
这些应用程序都是由GCC(c/c++)编译生成。在Android软件架构里,这些应用程序组成了native layer。

编译碰到的问题

安装lib32bz2-1.0出问题

解决方法:

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libbz2-1.0:i386

add-apt-repository命令不存在

解决方法:

apt-get install software-properties-common

Jack server installation not found

解决方法:在prebuilts/sdk/tools 目录下执行以下命令

./jack-admin install-server jack-launcher.jar jack-server-4.11.ALPHA.jar

  • Jack编译器工具是一套新的Android编译工具用来将Java代码转换为Android dex字节代码。Jack服务器无法启动原因:$HOME目录下无.jack文件

subcommand failed问题

编译Android系统时经常都是使用多线程编译,有时甚至用到了58个线程,启用太多线程的话,由于Makefile的目标与文件或其它目标的依赖关系,会导致编译目标时需要的源还未编译完成,会提示ninja: build stopped: subcommand failed,这时就需要减少线程数来编译。

  • 在切换编译目标时需要执行make installclean,用以清除之前编译生成的文件。

内核目录下存在.config文件导致编译错误

Using /mnt/kernel-4.4 as source for kernel
/mnt/kernel-4.4 is not clean, please run ‘make mrproper’
in the ‘/mnt/kernel-4.4’ directory.
/mnt/kernel-4.4/Makefile:1033: recipe for target ‘prepare3’ failed
make[1]: *** [prepare3] Error 1
make[1]: *** Waiting for unfinished jobs…
[DCT_INFO]: DWS file path is /mnt/kernel-4.4/drivers/misc/mediatek/dws/m
t6771/8p1_64_bsp.dws
[DCT_INFO]: Gen files path is /mnt/out/target/product/8p1_64_bsp/ob
j/KERNEL_OBJ/arch/arm64/boot/dts/8p1_64_bsp
[DCT_INFO]: Log files path is /mnt/out/target/product/8p1_64_bsp/ob
j/KERNEL_OBJ/arch/arm64/boot/dts/8p1_64_bsp
[DCT_INFO]: Parameter is cust_dtsi
[DCT_INFO]: chip id: MT6771
[DCT_INFO]: Chip ID : MT6771
[DCT_INFO]: Project Info: 8p1_64_bsp
[DCT_INFO]: Start to generate cust_dtsi file…
[DCT_INFO]: Generate cust_dtsi file successfully!
make[1]: *** wait: No child processes. Stop.
Makefile:152: recipe for target ‘sub-make’ failed
make: *** [sub-make] Error 2
make: Leaving directory ‘/mnt/kernel-4.4’

在kernel-4.4目录下搜索“is not clean”会发现导致错误的原因是当kernel-4.4目录下存在.config文件或kernel-4.4/include/目录下存在config目录时,就会报错,因此删除掉这两个对象就可以了。
因为之前有去修改过kernel-4.4目录中的文件,并执行过make menuconfig命令,这在Android系统源码中是不可以的。

输出目录中的重要目录

  • Android系统预装的APP所在目录为:
    out/target/product/$(PROJECT_NAME))/system/app/

  • C编译的可执行文件所在目录为:
    out/target/product/$(PROJECT_NAME))/system/bin/

  • 动态链接库所在目录为:
    out/target/product/$(PROJECT_NAME))/system/lib/

  • 硬件抽象层接口文件所在目录:
    out/target/product/$(PROJECT_NAME))/system/lib/hw/

编译模块

  • init模块

mmm system/core/init/
编译完成:
[100% 201/201] Copy: out/target/product/88p1_64_bsp/testcases/init_tests/arm/init_tests

  • 单独编译framework的services模块

先在framework/base目录下执行
mmm core/res/生成framework-res.apk

如果framework/base/services/下也有修改,也要编译:
mmm framework/base/services

然后再单独编译framework
mmm frameworks/base

相关的输出文件在输出目录下的system/framework中,包含:
services.jar
framework-res.apk
framework.jar

可利用adb命令将这些文件push到设备端的system/framework目录下。若需测试这两个新模块,需先杀掉所有使用该模块的进程,进程重启后会重新加载模块。
系统服务被杀掉后一般都会自动重启(由init控制)

系统属性相关目标和依赖文件的定义

  • build/make/core/Makefile

intermediate_system_build_prop := $(call intermediates-dir-for,ETC,
system_build_prop)/build.prop
猜想intermediate_system_build_prop 展开即为:
out/target/product/8p1_64_bsp/obj/ETC/system_build_prop_intermediates/build.prop

BUILDINFO_SH := build/make/tools/buildinfo.sh
INTERNAL_BUILD_ID_MAKEFILE := $(wildcard $(BUILD_SYSTEM)/build_id.mk)
即为:build/make/core/build_id.mk

system_prop_file := $(wildcard $(TARGET_DEVICE_DIR)/system.prop)
展开即为:device/mediateksample/8p1_64_bsp/system.prop

INSTALLED_ANDROID_INFO_TXT_TARGET := $(PRODUCT_OUT)/android-info.txt
展开即为:out/target/product/8p1_64_bsp/android-info.txt

  • 最后将包括build/make/tools/buildinfo.sh中设置的属性一并写入build.prop文件中,并在out目录下生成build.prop文件。位于输出目录的system目录下。
    build.prop记录的都是系统设置,是个属性文件。init进程将会加载/system/build.prop中定义的属性。
  • 系统源码中的property_service.cpp源文件中的load_properties_from_file函数就是用于init进程加载存储属性值的文件。
bool load_properties_from_file(const char* filename, const char* filter) {
    Timer t;
    auto file_contents = ReadFile(filename);
    if (!file_contents) {
        PLOG(WARNING) << "Couldn't load property file '" << filename
                      << "': " << file_contents.error();
        return false;
    }
    file_contents->push_back('\n');

    LoadProperties(file_contents->data(), filter, filename);
    LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
    return true;
}

编译时确定系统属性值

在device.mk中添加,例如:
PRODUCT_PROPERTY_OVERRIDES += persist.sys.Notification=1

打包新添加的模块至system.img

device.mk中的PRODUCT_PACKAGES选项中加入该模块如果将新添加的PRODUCT_PACKAGES选项放入新创建的Makefile中,需要在build/target/product/core.mk末尾追加一行
例如在build/target/product目录下创建一个新的Makefile文件mytest.mk
build/target/product/core.mk末尾追加:$(call inherit-product, $(SRC_TARGET_DIR)/product/mytest.mk)

本文地址:https://blog.csdn.net/weixin_41388144/article/details/109393921