美文网首页
跨模块的Java类调用(Java类打印日志)

跨模块的Java类调用(Java类打印日志)

作者: 修符道人 | 来源:发表于2020-01-09 16:38 被阅读0次

场景:想在libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java类里打印一下Android日志,研究一下这个类。Log类已经导入

image.png
编译报错,找不到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了。

相关文章

网友评论

      本文标题:跨模块的Java类调用(Java类打印日志)

      本文链接:https://www.haomeiwen.com/subject/rkykactx.html