排查Android编译错误时的技巧及常见Android编译错误

1.排查技巧

编译Android时,我们常用命令

make flashfiles -j8

-j8代表用系统的8个线程去编译

但是这样出来的log会直接打印在标准输出里,会存不全;而且因为是8个线程,会导致log的顺序是乱的

所以当我们编译过一次之后(大部分文件已经被编译了,下次编译会跳过,这样节省下大部分时间)

选择下面的命令编译比较好:

nohup make flashfiles -j1

log会存储在当前目录下的"nohup"文件中,并且-j1参数指定只用1个线程去编译,log顺序不会乱,这样方便我们排查编译错误。

 

补充:

一般情况下,我们需要看log里的error信息,如果步骤没错,一般出现的错误都是缺少依赖,这样我们就缺什么就安装什么。

 

补充:关于nohup,这是一个可以让当前shell语句在系统后台执行的command。标准的输出全部被重定向到当前文件夹的nohup中。

 

1.nohup

用途:不挂断地运行命令。

语法:nohup Command [ Arg … ] [ & ]

  无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。

  如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。

  如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。

退出状态:该命令返回下列出口值:   
  126 可以查找但不能调用 Command 参数指定的命令。   
  127 nohup 命令发生错误或不能查找由 Command 参数指定的命令。   
  否则,nohup 命令的退出状态是 Command 参数指定命令的退出状态。

2.&

用途:在后台运行

一般两个一起用

nohup command &

eg: nohup /usr/local/node/bin/node /www/im/chat.js >> /usr/local/node/output.log 2>&1 &

这条命令的意思是调用路径“/usr/local/node/bin/”下的“node”来运行“/www/im/”下的“chat.js”,让程序的运行过程不在前台显示,而是后台运行,最终将输出重定向到“ /usr/local/node/”下的“output.log”文件。

 

查看运行的后台进程

(1)jobs -l

jobs命令只看当前终端生效的,关闭终端后,在另一个终端jobs已经无法看到后台跑得程序了,此时利用ps(进程查看命令)

(2)ps -ef 

 a:显示所有程序 
u:以用户为主的格式来显示
x:显示所有程序,不以终端机来区分

(3)如果某个进程起不来,可能是某个端口被占用

查看使用某端口的进程

lsof -i:8090

netstat -ap|grep 8090

查看到进程id之后,使用netstat命令查看其占用的端口

netstat -nap|grep 7779

(4)终止后台运行进程

kill -9  进程号

 

linux下我们如果想一个任务或者程序还后台执行可以使用&,实际上linux还提供了其他任务调度的命令。

bg
将一个在后台暂停的命令,变成继续执行

fg
将后台中的命令调至前台继续运行

jobs
查看当前有多少在后台运行的命令

ctrl + z
可以将一个正在前台执行的命令放到后台,并且暂停

 

nohup 命令

用途:不挂断地运行命令。

 

   &的意思是在后台运行, 什么意思呢?  意思是说, 当你在执行 ./a.out & 的时候, 即使你用ctrl C,  那么a.out照样运行(因为对SIGINT信号免疫)。 但是要注意, 如果你直接关掉shell后, 那么, a.out进程同样消失。 可见, &的后台并不硬(因为对SIGHUP信号不免疫)。

 

      nohup的意思是忽略SIGHUP信号, 所以当运行nohup ./a.out的时候, 关闭shell, 那么a.out进程还是存在的(对SIGHUP信号免疫)。 但是, 要注意, 如果你直接在shell中用Ctrl C, 那么, a.out进程也是会消失的(因为对SIGINT信号不免疫)

 

      所以, &和nohup没有半毛钱的关系, 要让进程真正不受shell中Ctrl C和shell关闭的影响, 那该怎么办呢? 那就用nohua ./a.out &吧, 两全其美。

 

       如果你懂守护进程, 那么nohup ./a.out &颇有点让a.out成为守护进程的感觉。

 

 

2.Android编译错误

2.1 root_elements issue

报错:Missing -r/--root option: please specify the names of root elements. In Android.bp, use 'root_elements' property to set root elements. Possible root elements are: "feature", "ip_capabilities", "capabilities

解决办法:在对应的Android.bp中的xsd_config中加入提示的root_elements的内容:

xsd_config {
    name: "capabilities_xxx_type",
    srcs: ["capabilities_xxx_type.xsd"],
    package_name: "capabilities_xxx_type",
    root_elements: [
        "capabilities",
        "feature",
        "ip_capabilities",
    ],
}

 2.2 llvm-strip error

报错:llvm-strip : error: 'xxxxx/xxxx/xxxx/xxxx/xxx.sh' : the file was not recognized as a valid object file

分析:llvm-strip是用来去除目标文件中的一些符号表、调试符号表信息,以减小程序的大小。这里是把xxx.sh这个文件当成ELF文件(binary文件的格式)去做strip操作了。其实并不影响,这个error只是表示想减少这个shell文件的size,结果失败了。

这里的error message只是llvm-strip自己打印的log信息,并非Android编译系统出的error。

修复也比较简单,可以在Android.bp中加入以下字段来skip掉strip的操作:

strip: { none: true, },

 2.3 invalid escape sequence '\0' in an unevaluated string "Extension name exceeds the permitted length of 64 including '\0' terminator" 

修复:

-                     "Extension name exceeds the permitted length of 64 including '\0' terminator");
+                     "Extension name exceeds the permitted length of 64 including '\\0' terminator"); 

 

2.3 sepolicy编译错误: xxxx is not defined 

out/soong/.intermediates/system/sepolicy/contexts/vendor_service_contexts_test/android_common/79ee1e9077a85cf0a7efae415df2b097/timestamp # hash of input list: c846b504469b87be61d57f02d93b5ba3a1ff35595e86220e4280962f2be84092 libsepol.context_from_record: type hal_mali_platform_service is not defined libsepol.context_from_record: could not create context structure

这个错误信息表明,在尝试运行vendor_service_contexts_test测试时,SELinux策略编译器遇到了问题。具体来说,它无法加载vendor_service_contexts文件,因为该文件的第一行包含了一个未定义的上下文hal_mali_platform_service

要解决这个问题,请按照以下步骤操作:

检查SELinux策略文件:

  1. 确保在SELinux策略文件中定义了hal_mali_platform_service类型。
  2. 检查该类型的定义是否正确,包括它的属性、角色和敏感级别。

而sepolicy文件中是定义 hal_mali_platform_service的:

type hal_mali_platform_service, service_manager_type, hal_service_type, vendor_service;
add_service(hal_mali_platform_default, hal_mali_platform_service);
allow { coredomain -init -vold -installd -app_zygote -webview_zygote -isolated_app } hal_mali_platform_service:service_manager find;

在这个SELinux策略片段中,定义了几个类型(type),包括hal_mali_platform_service、service_manager_type、hal_service_type和vendor_service。

然后,用add_service宏将hal_mali_platform_default服务添加到hal_mali_platform_service类型中。

最后,使用allow语句来允许特定的域(domain)对hal_mali_platform_service类型的service_manager类进行find操作。

最终是发现Android升级后,sepolicy.mk中没有添加上述sepolicy文件,导致hal_mali_platform_service未定义,加入Android15的定义就可以了如下:

ifeq ($(PLATFORM_VERSION), 15)
    BOARD_VENDOR_SEPOLICY_DIRS += $(THIS_DIR)/public/sepolicy-v15
endif

ifeq ($(PLATFORM_VERSION), VanillaIceCream)
    BOARD_VENDOR_SEPOLICY_DIRS += $(THIS_DIR)/public/sepolicy-v15
endif

 2.4 Depends on multiple versions of the same aidl_interface

Depends on multiple versions of the same aidl_interface: android.hardware.graphics.common-V4-ndk, android.hardware.graphics.common-V5-ndk

一般该问题出现在Android升级时,是由于NDK的更新导致的。

解决办法:

diff --git a/android/build.bp b/android/build.bp
index exxxxxxx4
--- a/android/build.bp
+++ b/android/build.bp
@@ -46,6 +46,10 @@ bob_external_shared_library {
     name: "android.hardware.graphics.common-V4-ndk",
 }
 
+bob_external_shared_library {
+    name: "android.hardware.graphics.common-V5-ndk",
+}
+
 bob_external_shared_library {
     name: "arm.mali.platform-V2-ndk",
 }
@@ -199,9 +203,12 @@ bob_static_library {
         "{{if eq .android_api_level \"33\"}}" +
             "android.hardware.graphics.common-V3-ndk" +
         "{{end}}",
-        "{{if ge .android_api_level \"34\"}}" +
+        "{{if eq .android_api_level \"34\"}}" +
             "android.hardware.graphics.common-V4-ndk" +
         "{{end}}",
+        "{{if ge .android_api_level \"35\"}}" +
+            "android.hardware.graphics.common-V5-ndk" +
+        "{{end}}",
     ],


diff --git a/android/usages/build.bp b/android/usages/build.bp
index xxxxxxxxx100644
--- a/android/usages/build.bp
+++ b/android/usages/build.bp
@@ -39,9 +39,12 @@ bob_static_library {
         "{{if eq .android_api_level \"33\"}}" +
             "android.hardware.graphics.common-V3-ndk" +
         "{{end}}",
-        "{{if ge .android_api_level \"34\"}}" +
+        "{{if eq .android_api_level \"34\"}}" +
             "android.hardware.graphics.common-V4-ndk" +
         "{{end}}",
+        "{{if ge .android_api_level \"35\"}}" +
+            "android.hardware.graphics.common-V5-ndk" +
+        "{{end}}",
     ],
     android: {

2.5 not normalized

升级Android15时遇到:

编译Android镜像时报错,单独编译xxx component可以pass
但是编译整个Android镜像时就报错:

打包vendor.img时报错

xxxxxx/./libxxxxx.so: not normalized

本质原因就是对应的xxxx.mk里写了“LOCAL_MODULE_RELATIVE_PATH = .”导致多了一级无效的路径。 最终导致生成了  xxxx/./libxxxx.so 这种不太规范的路径,使得Android15打包vendor.img时报错(A15报错,A14未报错,可能是因为A15的编译系统打包系统对错误检查更加严格)

LOCAL_MODULE_RELATIVE_PATH这个变量就是用来指定模块(比如一个库或者可执行文件)在构建系统中的输出目录的相对路径的,这里指指定成“ . ”其实就是当前目录,没有任何额外效果,直接注释掉就行。

 

2.6 CANNOT LINK EXECUTABLE "./XYZ": cannot locate symbol "abc_abcxxxx" referenced by "/system/lib64/libbinder_ndk.so"

Android升级完成后,运行某个可执行文件时遇到该报错

用readelf -a命令查看该XYZ依赖于哪些so文件:

$ readelf -a XYZ |grep NEEDED

发现该XYZ文件除了报出来的libbinder_ndk.so,还依赖于libbiner.so

用readelf -Ws查看对应的.so文件中符号abc_abcxxxx的情况

$ readelf -Ws libbinder.so
$ readelf -Ws libbinder_ndk.so

发现符号abc_abcxxxx在libbinder_ndk.so中是UND(undefined),在libbinder.so中可以找到定义

这里就发生特别奇怪的事情了。按道理,如果是某个符号找不到定义的话,肯定在编译的link阶段会报错,但是我们这里编译时未报错,而是执行的时候报错无法定位该symbol,那么就应该是运行XYZ时的环境变量设置的有问题。

去检查执行XYZ前设置环境变量发现:

export LD_LIBRARY_PATH=/vendor/lib64:/vendor/lib64/egl:/system/lib64

我们未把/system/lib64放在最前,该路径既是报错中提示的路径,也是我们通过readelf -Ws能确切找到abc_abcxxxx这个符号的.so所在路径,考虑到这里,我们把环境变量的设置更改为:

export LD_LIBRARY_PATH=/system/lib64:/vendor/lib64:/vendor/lib64/egl

即把/system/lib64放在最前面,再运行./XYZ,此时这个报错消失了。

回头复盘,为什么会导致这个问题?

发现/vendor/lib64路径下面也有一个libbinder.so,并且readelf -Ws找不到abc_abcxxxx这个符号,推测是优先搜索了/vendor/lib64/这个路径,发现有libbinder.so,没有再去找/system/lib64下面的,结果找不到该符号。

posted @ 2018-06-05 13:34  青山牧云人  阅读(1361)  评论(0)    收藏  举报