场景:想在libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java类里打印一下Android日志,研究一下这个类。Log类已经导入
编译报错,找不到Log类。
image.png
看一下Log.java类的路径:frameworks/base/core/java/android/util/Log.java
这两个类,完全不在一个模块下,BaseDexClassLoader.java属于libcore模块,Log属于frameworks/base模块。定位到Log.java位于Sdk\platforms\android-29\android.jar里,而android.jar有20M,不可能直接把这个jar直接复制到libcore模块然后引用。所以,我们先分析一下android.jar是如何打包生成的,然后依葫芦画瓢,生成一个czlog.jar包。
android.jar出生记
http://www.360doc.com/content/14/0214/23/9075092_352577757.shtml
https://wenku.baidu.com/view/8144fa1314791711cc79175e.html
https://blog.csdn.net/c_z_w/article/details/78994001
自己打造一个Android工具类库
参考https://www.jianshu.com/p/584ff56909b3这篇博客关于Log类相关的分析,准备裁剪出一个log相关的so和jar包。
- so库裁剪
仿照frameworks/base/core/jni/Android.mk,增加一个生成so库的脚本,只依赖和lib相关的库。
# ========================================================
# lib_cz_log.so
# ========================================================
# CZAdd
# try make a small Android logutil
include $(CLEAR_VARS)
LOCAL_MODULE := lib_cz_log
LOCAL_SRC_FILES := \
AndroidRuntime.cpp \
android_util_Log.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
libcore/include
LOCAL_SHARED_LIBRARIES := \
libnativehelper \
liblog \
libcutils \
libutils
include $(BUILD_SHARED_LIBRARY)
然后,后面就报错了,还有东西要依赖。
这篇博客
https://blog.csdn.net/dahailantian1/article/details/78584651?utm_source=blogxgwz4里说到:
Android的java核心库中是无法使用Logcat打印的,因为Android的java层要使用Java库,即Java库是Android的Java运行的前提。(我理解的意思就是Logcat是应用层用的东西,而Logcat又要依赖libcore库,我却在libcore库本末倒置地使用Logcat。)
所以在BaseDexClassLoader.java里打印日志,直接使用Logger类,没有必要折腾自己搞个log工具库了。
源码里BaseDexClassLoader.java自身就调用了java.util.List等类,所以再调用个Logger类肯定没有问题了。但是BaseDexClassLoader和mmap函数里,都不能随便地加日志,否则系统就会卡死起不来。要加以限制:
public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;
private final String TAG = "BaseDexClassLoader";
private static boolean allowLog = false;
/**
* Constructs an instance.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param optimizedDirectory directory where optimized dex files
* should be written; may be {@code null}
* @param libraryPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
if(allowLog){
Logger logger = Logger.getLogger("CZLog11");
logger.warning("BaseDexClassLoader: " + ",dexPath = " + dexPath + "\npathList = " + pathList);
}
}
如上图,我在源码里加一个boolean值allowLog
用以控制Logger的创建和输出。
然后用反射写个控制allowLog
的apk:
ReflectManger.setStaticField(Class.forName("dalvik.system.BaseDexClassLoader"),"allowLog",true);
Log.e(TAG, "设置成功1");
待系统起来并初始化完毕之后,再调用这个apk开启日志,这时输出日志就不会有啥问题了。
Object allowLog = ReflectManger.getField(Class.forName("dalvik.system.BaseDexClassLoader"), null, "allowLog");
Log.e(TAG, "allowLog: " + allowLog);
ReflectManger.setStaticField(Class.forName("dalvik.system.BaseDexClassLoader"),"allowLog",true);
Log.e(TAG, "设置成功1");
MyClassLoader myClassLoader = new MyClassLoader(Environment.getExternalStorageDirectory().getAbsolutePath(), null, null, getClassLoader());
Object allowLog2 = ReflectManger.getField(Class.forName("dalvik.system.BaseDexClassLoader"), null, "allowLog");
Log.e(TAG, "allowLog2: " + allowLog2);
控制台输出
MainActivity: allowLog: false
MainActivity: 设置成功1
CZLog11: BaseDexClassLoader: ,dexPath = /storage/emulated/0
tory "/storage/emulated/0"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
MainActivity: allowLog2: true
CZLog11就是我系统设置的日志TAG了。
网友评论