Android如何查找java代码编译路径
- 1. 源文件代码位置
- 2. 查找文件编译后存放的地方
- 3. 找一下这个文件在哪里
- 4. 看一下实际效果
1. 源文件代码位置
如果有code search,那么直接使用code search,
如果没有可以使用locate "***.java"来查找对应的文件
举一个例子想要调试FinalizerDaemon这个class,先“frameworks/base”搜索一下
在frameworks/base/config/preloaded-classes可以找到类似定义
java.lang.Daemons$FinalizerDaemon
那么我们其实应该去找Daemons.java在哪里
locate “Daemons.java”
可以找到源码位置
libcore/libart/src/main/java/java/lang/Daemons.java
不过直接修改这个文件发现修改不生效,那么很大可能就是没有编译进去,接下去需要看一下这个文件编译在哪里
2. 查找文件编译后存放的地方
1、libcore/libart/src/main/java/java/lang/Daemons.java
逐级往上查找Android.mk、Android.bp
如这里最近的就是libcore\Android.bp
2、在Android.bp的目录libcore, 先搜索一下Daemons.java或者libcore
find -name “*.bp” |xargs grep “Daemons”
./non_openjdk_java_files.bp: “libart/src/main/java/java/lang/Daemons.java”,
libcore$ find -name “*.bp” |xargs grep “libart”
./non_openjdk_java_files.bp: path: “libart/src/main”,
上面2中都是可以将Daemons.java引用进来
3、打开搜索到的文件libcore/non_openjdk_java_files.bp
//文件组
filegroup {
//名字
name: “non_openjdk_javadoc_libart_files”,
//源文件,如frameworks/base/core/java/Android.bp中的"**/*.java"代表将frameworks/base/core/java后面的所有java文件做为资源,包括Activity.java
srcs: [
//…
“libart/src/main/java/java/lang/Daemons.java”,
//…
],
//路径,从这里开始引入源码
path: “libart/src/main”,
//私有的,这个文件组只有libcore本包可以访问,其它子包Android.bp访问不了
visibility: ["//visibility:private"],
}4、non_openjdk_javadoc_libart_files使用的地方是non_openjdk_javadoc_files,还是文件组,不是生成文件的地方
filegroup {
name: “non_openjdk_javadoc_files”,
srcs: [
//…
“:non_openjdk_javadoc_libart_files”,
//…
],
visibility: ["//visibility:private"],
}5、接着继续找non_openjdk_javadoc_files使用的地方,是core_libart_api_files/non_openjdk_java_files文件组
libcore$ find -name “*.bp” |xargs grep “non_openjdk_javadoc_files”
./JavaLibrary.bp: “:non_openjdk_javadoc_files”,
./non_openjdk_java_files.bp: name: “non_openjdk_javadoc_files”,
./non_openjdk_java_files.bp: “:non_openjdk_javadoc_files”,//JavaLibrary.bp
filegroup {
name: “core_libart_api_files”,
srcs: [
“:non_openjdk_javadoc_files”,
],
}//non_openjdk_java_files.bp
filegroup {
name: “non_openjdk_java_files”,
visibility: [
“//frameworks/base”,
],
srcs: [
//…
“:non_openjdk_javadoc_files”,
],
}
6、core_libart_api_files看起来都是用在接口的地方,没有包含实际运行的逻辑
//被java_sdk_library引用,一般是用于接口
java_sdk_library {
name: “art.module.public.api”,
//…
srcs: [
//…
“:core_libart_api_files”,
//…
],
//…
}//引用在droidstubs,用于生成接口
droidstubs {
name: “java-current-stubs-source”,
//…
srcs: [
//…
“:core_libart_api_files”,
//…
],
//…
}//art_module_api_files是filegroup文件组,还是要继续找
filegroup {
name: “art_module_api_files”,
//…
srcs: [
//…
“:core_libart_api_files”,
//…
],
//…
}//art_module_api_files引用在droidstubs,用于生成接口
droidstubs {
name: “art-module-public-api-stubs-nullability-validation”,
srcs: [":art_module_api_files"],
//…
}7、non_openjdk_java_files被core_libart_java_files引用,也是文件组
filegroup {
name: “core_libart_java_files”,
//可以被子包应用,如果libcore子目录有Android.bp子包,也是可以用这个filegroup的
visibility: [
“//libcore:subpackages”,
],
srcs: [
“:non_openjdk_java_files”,
],
}
8、core_libart_java_files被core-libart引用,这个是一个java_library(java的库,如.jar)是可以生成文件的看起来像是了
java_library {
name: “core-libart”,
visibility: [
“//art/build/apex”,
“//art/build/sdk”,
“//external/wycheproof”,
“//libcore/benchmarks”,
“//packages/modules/ArtPrebuilt”,
],
//…
srcs: [":core_libart_java_files"],
//…
}
3. 找一下这个文件在哪里
1、可以搜索生成文件
$ locate “core-libart.jar”
ArtPrebuilt/com.google.android.art.deapexer/android_common/deapexer/javalib/core-libart.jar
dex_artjars_input/core-libart.jar
到这里可以看到这个是在art
那么大概原因应该已经知道了,应该是mainline导致了代码没有生效
手机apex里面也可以找到这个jar包
apex # find . -name “core-libart”
./com.android.art/javalib/core-libart.jar
./com.android.art@310924000/javalib/core-libart.jar
2、接着去源码art目录看一下是如何使用这个jar的
//art/build/apex/Android.bp
//放在libcore_java_libs列表里面
// Core Java libraries.
libcore_java_libs = [
“core-oj”,
“core-libart”,
“okhttp”,
“bouncycastle”,
“apache-xml”,
]
//host主机端,也不是终端里面,不是这个
art_apex_test_host {
name: “com.android.art.host”,
//…
java_libs: libcore_java_libs,
//…
]
//这个是defaults,还有别的地方引用
apex_defaults {
name: “com.android.art-device-defaults”,
defaults: [“com.android.art-defaults”],
//…
java_libs: libcore_java_libs,
//…
]
//这个就是给mainline了的
art_apex {
name: “com.android.art”,
defaults: [“com.android.art-device-defaults”],
certificate: “:com.android.art.certificate”,
}
3、那么去掉mainline重新编译应该是生效的
diff --git a/build/mainline_modules_s.mk b/build/mainline_modules_s.mk
--- a/build/mainline_modules_s.mk
+++ b/build/mainline_modules_s.mk
+# delete by yunhen
# Art
-MAINLINE_COMPRESS_APEX_ART ?= true
-ifeq ($(MAINLINE_COMPRESS_APEX_ART),true)
-PRODUCT_PACKAGES += \
- com.google.android.art_compressed
-else
-PRODUCT_PACKAGES += \
- com.google.android.art
-endif
+#MAINLINE_COMPRESS_APEX_ART ?= true
+#ifeq ($(MAINLINE_COMPRESS_APEX_ART),true)
+#PRODUCT_PACKAGES += \
+# com.google.android.art_compressed
+#else
+#PRODUCT_PACKAGES += \
+# com.google.android.art
+#endif
4. 看一下实际效果
- 加入日志,如在FinalizerDaemon的doFinalize加入一个日志"FinalizerDaemon doFinalize yunhen"
//libcore/libart/src/main/java/java/lang/Daemons.java
private static class FinalizerDaemon extends Daemon {
//…
private void doFinalize(FinalizerReference<?> reference) {
System.logE(“FinalizerDaemon doFinalize yunhen”);
//…
}
} - 找到手机的文件
/apex # find . -name “core-libart*”
./com.android.art/javalib/core-libart.jar
./com.android.art@319999900/javalib/core-libart.jar - pull出来adb pull /apex/com.android.art/javalib/core-libart.jar core-libart_new.jar
- 转换成smali文件
java -jar apktool_2.3.0.jar d core-libart_new.jar
5.搜索FinalizerDaemon找到Daemons$FinalizerDaemon.smali
$ find . -name “FinalizerDaemon”
./smali/java/lang/Daemons$FinalizerDaemon.smali
6.打开Daemons$FinalizerDaemon.smali,果然发现doFinalize有我们加入的代码
.method private doFinalize(Ljava/lang/ref/FinalizerReference;)V
.locals 4
.annotation system Ldalvik/annotation/Signature;
value = {
"(",
"Ljava/lang/ref/FinalizerReference<",
"*>;)V"
}
.end annotation
.line 294
.local p1, "reference":Ljava/lang/ref/FinalizerReference;, "Ljava/lang/ref/FinalizerReference<*>;"
const-string v0, "FinalizerDaemon doFinalize yunhen" //常量v0是"FinalizerDaemon doFinalize yunhen"
invoke-static {v0}, Ljava/lang/System;->logE(Ljava/lang/String;)V //调用logE打印日志
.line 295
invoke-static {p1}, Ljava/lang/ref/FinalizerReference;->remove(Ljava/lang/ref/FinalizerReference;)V
7、实际手机也会输出
$ adb logcat | grep “FinalizerDaemon doFinalize yunhen”
03-03 15:29:52.648 9462 9478 E System : FinalizerDaemon doFinalize yunhen
03-03 15:30:05.826 2832 2850 E System : FinalizerDaemon doFinalize yunhen
03-03 15:30:05.826 2832 2850 E System : FinalizerDaemon doFinalize yunhen
ps:
System.logE 日志打印需要runtime的一些环境,故先不要在FinalizerDaemon的clinit中打印(clinit是类初始化的时候调用,Android的preloaded-classes就是调用clinit,将部分class提前载入zygote),这个函数用在FinalizerDaemon有点特殊,别的如framework的java日志打印调用Log.w或者Slog.w都是没有问题的
dex2oatd F 03-03 11:48:21 4711 4711 unstarted_runtime.cc:2130] Calling native method java.lang.String dalvik.system.VMRuntime.bootClassPath() in an unstarted non-transactional runtime
//...
at dalvik.system.VMRuntime.bootClassPath(Native method)
at java.lang.System.initUnchangeableSystemProperties(System.java:971)
at java.lang.System.<clinit>(System.java:1690)
at java.lang.System.logE(System.java:1727)
at java.lang.Daemons$FinalizerDaemon.<init>(Daemons.java:246)
at java.lang.Daemons$FinalizerDaemon.<clinit>(Daemons.java:237)
at java.lang.Daemons$FinalizerDaemon.access$200(Daemons.java:235)
at java.lang.Daemons.<clinit>(Daemons.java:56)
//如在构造函数FinalizerDaemon中打印日志,本来构造函数不在clinit中,但是静态变量INSTANCE在clinit中,故还是会报错
private static class FinalizerDaemon extends Daemon {
@UnsupportedAppUsage
private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
//...
FinalizerDaemon() {
super("FinalizerDaemon");
//System.logE("FinalizerDaemon yunhen"); //build error
}