为什么安装的java println可以输出到logcat
起因:鸿蒙系统中,******* 的println没有在hilog里打印日志,而arkts的Console.log会在hilog里打印日志,有点不友好。
安卓系统中,java的println能在logcat里直接打印,而C的printf无法在logcat里直接打印。
众所周知的常识
安卓APP进程来自 zygote 进程,由于它是 GUI 的而且没有命令行交互,所以它的 stdin/stdout/stderr 都是被关闭的。这就解释了C语言printf没有任何效果。
从我记事起,Java的 System.out.println("HelloWorld") 会打印到logcat里,对新手很友好。
另外,如果使用 adb shell 里的 am 、 pm 系列的指令,或者调用任意的jar,Java的 System.out.println("HelloWorld") 会打印到控制台、不打印到logcat里,交互也很友好。
阅读 Java Library 源码,未找到原因
System.java的实现在
1 | // https://xrefandroid.com/android-6.0.1_r66/xref/libcore/luni/src/main/java/java/lang/System.java#108 |
看起来没什么特殊的,简单的io操作,猜想:可能是操作系统在底层进行了重定向。
尝试构造poc,创建对象直接打印内容
1 | PrintStream out = System.out; |
很遗憾,失败了,使用 System.out 可以正常打印,手动创建的 myStream 无法打印。猜想错误。
调试和观测,细微差异,找到原因
经过调试,发现 out 的类型是 com.android.internal.os.AndroidPrintStream,而 myStream 的类型是 PrintStream。
恰好它只有一处引用
1 | // https://xrefandroid.com/android-6.0.1_r66/xref/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java#332 |
这下彻底破案了,System有另一个接口叫 setOut,从而可以定义输出流,属于 Java 原生支持。
反观 *******
emmmmm,短期内看来是无法实现了
1 | // https://gitcode.com/Cangjie/cangjie_runtime/blob/main/stdlib/libs/std/core/print.cj |