手写一个IO泄露监测框架_android bhook,2024年最新基于HarmonyOS鸿蒙的app开发详细步骤

为了避免操作完读写流忘记close,java和kotlin两种编程语言分别给我们提供了以下语法糖:

1. 实现java的AutoCloseable并搭配try-with-resource

看一段常见的代码:

public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream(new File(“test.txt”))) {
byte[] data = new byte[1024];
int read = fis.read(data);
//执行其他操纵
} catch (Exception e) {
e.printStackTrace();
}
}

FileInputStream实现了AutoCloseable接口,并重写了接口的close()方法,通过上面的try-with-resource语法,我们就不需要显示调用close方法关闭io,java会自动帮助我们完成这个操作:

常见的InputStream、OutputStream 、Scanner 、PrintWriter都实现了AutoCloseable接口,所以文件读写时可以非常方便的使用上面的语法糖。

2. 使用kotlin中的use()扩展

kotlin针对Closeable(实现了AutoCloseable)接口提供了下面的扩展:

我们常见的InputStream、OutputStream 、Scanner 、PrintWriter等都是支持这个扩展函数的:

override fun create(context: Context) {
FileInputStream(“”).use {
//执行某些操作
}
}

虽然kotlin和java都从语言层面上帮助尽可能我们读写io流实现安全关闭,但是真正到写代码时忘了是真的忘了;而且项目中还可能存在历史代码也忘记了关闭流,查找起来也是毫无头绪的。

面对上面这中情况,就需要一种io泄漏的检测机制,不管是针对项目的历史代码还是新写的代码,能够检测文件流是否关闭,没有关闭则获取流创建的堆栈并上报帮助开发定位问题,接下来我们来一步步的实现这种能力吧。

二. IO泄漏检测的实现思路

头脑风暴一下,想要检测流有没有关闭,关键就是检测诸如FileInputStream等操作文件流的类close方法有没有调用;那什么时机才应该去检测呢,当FileInputStream等流类准备销毁的时候就可以去检测了,而类销毁的时候会调用finalize()方法(PS:暂时不考虑finalize()特殊场景下的表现,这里认为都会被正常执行),所以检测的最佳时机就是在流类的finalize() 方法执行的时候

经过上面的分析,我们可以写出下面的代码:

public class FileInputStream {

private Object flag = null;

public void open() {
//打开文件流时赋值
flag = “open”;
}

public void close() throws Exception {
//关闭文件流置空
flag = null;
}

@Override
protected void finalize() throws Throwable {
super.finalize();
//flag等于null,说明忘记执行close方法关闭流,io泄漏
if (flag != null) {
Throwable throwable = new Throwable(“io leak”);
//执行异常日志的打印,或者回调给外部。
//兜底流的关闭
close();
}
}
}

代码中有非常详细的注释,这里就不再一一进行讲述。

所以如果能在我们常见的FileInputStreamFileOutputStreamRandomAccessFile等流类中也增加上面的代码,io泄漏监测这不就成了!!

Android官方自然也能够想到,并且还干了,常见的官方流类FileInputStream FileOutputStream RandomAccessFile CursorWindow等都增加了上面类似监控逻辑,接下来我们以FileInputStream为例进行分析。

三 瞅瞅官方FileInputStream源码

这里我们先提前说下,官方监控流类是否泄漏,并不是直接在里面增加逻辑代码,想想也是,那么多流类,一个个增加过去导致模板代码太多,不如封装一个工具类供各个流类使用,这里的工具类就是CloseGuard

说清了上面,我们就看下FileInputStream的源码:

1. 获取工具类CloseGuard

由于CloseGuard的源码无法直接在AS中查看,这里我们借助 aospxref.com/android-12.… 网站查看下该类的源码:

CloseGuard.get()方法就是创建了一个CloseGuard对象。

2. 打开文件流

FileInputStream构造方法主要干了两件事情:

  • 通过传入的文件路径调用IoBridge.open()打开文件流(这个底层最终会调用了open(const char *pathname,int flags,mode_t mode),做io监控时一般需要hook该方法)。
  • 同时还会调用CloseGuard.open()方法:

这个方法主要干的事情就是创建了一个Throwable对象,获取当前流创建的堆栈,并赋值给CloseGuardcloserNameOrAllocationInfo字段。


3. 关闭文件流

FileInputStreamclose()方法主要干了两件事:

  • 调用CloseGuardclose()方法:

很简单,就是将上面赋值的closerNameOrAllocationInfo字段重新置空。

  • 关闭文件流;
4. 重写finalize()监控FileInputStream的销毁

FileInputStreamfinalize()方法主要干了两件事:

  • 调用CloseGuardwarnIfOpen()方法:

如果closerNameOrAllocationInfo字段不为空,说明FileInputStreamclose() 关闭文件流的方法漏了调用,发生了io泄漏,调用reporter.report() 方法并传入closerNameOrAllocationInfo参数(这个参数上面有说:保存了流创建时的堆栈,一旦获取到我们就能很快知道哪个地方创建的流发生了泄漏)。

  • 兜底关闭流;

通过上面的分析可以得知,一旦发生io泄漏,就会通过reporter.report() 上报,这就是我们监控应用整体io泄漏的关键。

看下reporter是个啥:

reporter是一个静态变量,本质上是一个实现了Reporter接口的默认实现类DefaultReporter ,默认通过report() 方法打印io泄漏的系统日志。

同时外部可以注入自定义的实现了Reporter接口的类:

讲到这里大家是不是明白了,如果实现应用层的io泄漏检测,只要我们通过动态代理+反射代理掉reporter这个静态变量,替换成我们自定义实现的Reporter接口的类,并在自定义类中实现io泄漏异常上报的逻辑,不就完美实现监听了吗!!

想象很美好,现实很残酷,CloseGuard是个系统类,且被@hide隐藏,同时上面的setReporter()方法被@UnsupportedAppUsage注解,所以这个是官方非公开的api。在Android P以下自然可以通过反射调用,但是在Android P及以上使用反射就会报错,所以还得探索一种高版本能够成功反射系统非公开api的方法。

四. Android P及以上非公开api访问的实现

想要访问系统非公开api,那就只有系统api才能调用,一般有两种方式:

  1. 将我们自己的类的classloader转换为系统的classloader去调用系统非公开api;
  2. 借助于系统类方法去调用系统非公开api,即双反射实现机制;

这里我们采用的是第二种双反射实现方式,并且weishu大佬提供了一个github库方面我们拿来使用:

dependencies {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新**

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-fpqKHkdz-1712772512976)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值