利用 Kotlin inline 解决日志泄漏风险

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 利用 Kotlin inline 解决日志泄漏风险

写这个话题主要是因为看到一篇文章《淘宝系App图片为什么在北京电信网络加载这么慢?》,文章作者通过 xposed hook 了淘宝的 ALog 日志,最终分析到问题原因。这不觉让我有点警惕,Log 日志是我们平时开发中经常使用的调试工具,但却成为了三方了解应用流程的助推器。


因何泄漏?


我来列一个我们平时开发最常用的 LogUtils:


object LogUtils {
    fun i(tag: String, msg: String) {
        if (App.isDebug) {
            Log.i(tag, msg)
        }
    }
}
复制代码


通过 isDebug 来保护在 Release 环境中  Log.i 日志不会被打印,在 MainActivity 中我们可以这么调用:


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 打印日志
        LogUtils.i("TAG", "MainActivity onCreate") 
    }
}
复制代码


我们来反编译看下 Release 包:


image.png


由于 Release 包的 isDebug 为 false,经过代码优化,LogUtils.i  在判断 log 内容不为空时直接 return 不处理,可是 LogUtils.i 方法依然存在,这导致 MainActivity 中调用 LogUtils.i 的日志,可以被三方通过 hook  LogUtils.i 方法,读取该方法中的参数并打印出来,例子中的 ALog 就是这么被 hook 泄漏的。 我们需要的是,在 isDebug 为 false 的时候,调用  LogUtils.i 的地方和 LogUtils.i 这个方法都从 Release 包中消失,这样才能从根本上消除日志。


如何解决?


我们可以用 kotlin inline 来解决这个问题,尝试写个工具类:


inline fun <reified T : Any> T.logE(msg: String) {
    if (App.isDebug) {
        val tag = this::class.java.simpleName
        Log.e(tag, msg)
    }
}
复制代码


在 MainActivity 中调用:


class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 打印日志
        this.logE("MainActivity onCreate")
    }
}
复制代码


反编译看下 Release 包:

image.png

为什么 kotlin inline 可以呢?我来写个转换过程可能方便理解些:


//1、 原始调用
override fun onCreate(savedInstanceState: Bundle?) {
    this.logE("MainActivity onCreate")
}
//2、kotlin inline 转换
override fun onCreate(savedInstanceState: Bundle?) {
     if (App.isDebug) {
        val tag = MainActivity::class.java.simpleName
        Log.e(tag, msg)
    }
}
//3、经过编译器优化
override fun onCreate(savedInstanceState: Bundle?) {
}
复制代码


由于 App.isDebug 为 false,永远走不到这个分支,编译器经过代码优化,将该代码直接移除,最终,MainActivity 中 Log 相关的信息全部消失。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
8月前
|
存储 Java 编译器
Kotlin 学习笔记(四)—— 作用域函数、inline 关键字、反引号等 Kotlin 基本用法(下)
Kotlin 学习笔记(四)—— 作用域函数、inline 关键字、反引号等 Kotlin 基本用法(下)
37 0
|
8月前
|
Java Android开发 开发者
Kotlin 学习笔记(四)—— 作用域函数、inline 关键字、反引号等 Kotlin 基本用法(上)
Kotlin 学习笔记(四)—— 作用域函数、inline 关键字、反引号等 Kotlin 基本用法(上)
66 0
|
Java Kotlin
Kotlin内联函数inline、noinline、crossinline
如果一个函数接收另一个函数作为参数,或返回类型是一个函数类型,那么该函数被称为是高阶函数
139 0
|
监控 Java 开发者
Kotlin学习日志(六)控件使用(下)
Kotlin学习日志(六)控件使用(下)
297 0
Kotlin学习日志(六)控件使用(下)
|
安全 Java 程序员
Kotlin学习日志(六)控件使用(上)
Kotlin学习日志(六)控件使用(上)
231 0
Kotlin学习日志(六)控件使用(上)
|
搜索推荐 Java Android开发
Kotlin学习日志(五)类与对象(下)
Kotlin学习日志(五)类与对象(下)
Kotlin学习日志(五)类与对象(下)
|
Java 编译器 Android开发
Kotlin学习日志(五)类与对象(中)
Kotlin学习日志(五)类与对象(中)
143 0
Kotlin学习日志(五)类与对象(中)
|
Java C语言 Android开发
Kotlin学习日志(五)类与对象(上)
Kotlin学习日志(五)类与对象(上)
Kotlin学习日志(五)类与对象(上)
|
安全 Java 编译器
Kotlin学习日志(四)函数
Kotlin学习日志(四)函数
118 0
Kotlin学习日志(四)函数
|
存储 安全 Java
Kotlin学习日志(三)控制语句(下)
Kotlin学习日志(三)控制语句(下)
Kotlin学习日志(三)控制语句(下)