当前位置:网站首页>StrictMode卡顿与泄漏检测-StrictMode原理(2)
StrictMode卡顿与泄漏检测-StrictMode原理(2)
2022-07-01 00:40:00 【怪叔叔萝莉控】
2. StrictMode关闭检测原理
StrictMode的关闭检测其实是比较简单的,基本上就是在开启的时候埋桩,释放的时候检测桩子是否有关闭,没有关闭则检测为泄漏。
2.1 CloseGuard
这里有一个预备知识,那就是CloseGuard,它是一个StrictMode专门为了处理此类事情的类,主要包括三个函数:
- open 开始埋桩
- close 拆桩
- warnIfOpen 爆炸
SystemApi(client = MODULE_LIBRARIES)
@libcore.api.IntraCoreApi
public final class CloseGuard {
private static volatile boolean stackAndTrackingEnabled = true;
private static volatile Reporter reporter = new DefaultReporter();
private static volatile Tracker currentTracker = null; // Disabled by default.
@UnsupportedAppUsage
@SystemApi(client = MODULE_LIBRARIES)
public static void setEnabled(boolean enabled) {
CloseGuard.stackAndTrackingEnabled = enabled;
}
public static boolean isEnabled() {
return stackAndTrackingEnabled;
}
@UnsupportedAppUsage(trackingBug=111170242)
@SystemApi(client = MODULE_LIBRARIES)
@libcore.api.IntraCoreApi
public void open(String closer) {
openWithCallSite(closer, null /* callsite */);
}
//关闭之前,
@UnsupportedAppUsage
@SystemApi(client = MODULE_LIBRARIES)
@libcore.api.IntraCoreApi
public void close() {
Tracker tracker = currentTracker;
if (tracker != null && closerNameOrAllocationInfo instanceof Throwable) {
// Invoke tracker on close only if we invoked it on open. Tracker may have changed.
tracker.close((Throwable) closerNameOrAllocationInfo);
}
closerNameOrAllocationInfo = null;
}
public void warnIfOpen() {
if (closerNameOrAllocationInfo != null) {
if (closerNameOrAllocationInfo instanceof Throwable) {
reporter.report(MESSAGE, (Throwable) closerNameOrAllocationInfo);
} else if (stackAndTrackingEnabled) {
reporter.report(MESSAGE + " Callsite: " + closerNameOrAllocationInfo);
} else {
System.logW("A resource failed to call "
+ (String) closerNameOrAllocationInfo + ". ");
}
}
}
}
2.1 IO关闭检测
回顾一下之前的例子
findViewById<Button>(R.id.io_not_close_btn).setOnClickListener {
var outputStream = FileOutputStream(File(getExternalFilesDir("")?.path + "hello.json"))
outputStream.write("hello world".toByteArray())
outputStream = FileOutputStream(File(getExternalFilesDir("")?.path + "hello.json"))
Runtime.getRuntime().gc()
Runtime.getRuntime().gc()
}
埋炸弹 -首先来看看构造函数:
private final CloseGuard guard = CloseGuard.get();
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
String name = (file != null ? file.getPath() : null);
.......
// Android-added: CloseGuard support. Android添加的
guard.open("close");
}
拆炸弹 - 关闭输出流
public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
// Android-added: CloseGuard support.
guard.close();
}
爆炸 - 没有调用close便被回收
protected void finalize() throws IOException {
// Android-added: CloseGuard support.
if (guard != null) {
guard.warnIfOpen();
}
...
}
同理推断其他的流也会有其他的机制来检测泄漏。
2.2 IO卡顿检测
看卡顿前,我们需要先准备点预备知识,IO读取与写出的预备知识:
FileInputStream/FileOutputStream -> IOBridge -> ForwardingOs -> BlockGuardOS -> LibCore.OS
我们需要关注的主要在BlockGuardOS这一层,我们先看看源代码:
public class BlockGuardOs extends ForwardingOs {
@Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
BlockGuard.getThreadPolicy().onReadFromDisk();//检测IO读
BlockGuard.getVmPolicy().onPathAccess(path);//检测VM策略路径访问
if ((flags & O_ACCMODE) != O_RDONLY) {
BlockGuard.getThreadPolicy().onWriteToDisk(); //检测IO写
}
....
}
@UnsupportedAppUsage
@Override public void close(FileDescriptor fd) throws ErrnoException {
try {
if (fd.isSocket$()) {
if (isLingerSocket(fd)) {
BlockGuard.getThreadPolicy().onNetwork(); //是否主线程访问网络
}
}
} catch (ErrnoException ignored) {
}
super.close(fd);
}
}
这里比较清晰的看到,BlockGuardOs内部代理了BlockGuard,每次调用函数前,都会检测一下是否有卡顿问题。最后再回到StrictMode.
public void onReadFromDisk() {
if ((mThreadPolicyMask & DETECT_THREAD_DISK_READ) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
return;
}
//这个函数里面会进行打印
startHandlingViolationException(new DiskReadViolation());
}
2.3 SqliteCursor泄漏检测
location:frameworks/base/core/java/android/database/sqlite/SQLiteCursor.java
protected void finalize() {
try {
// if the cursor hasn't been closed yet, close it first
if (mWindow != null) {
// Report original sql statement
if (StrictMode.vmSqliteObjectLeaksEnabled()) {
String sql = mQuery.getSql();
int len = sql.length();
StrictMode.onSqliteObjectLeaked(
"Finalizing a Cursor that has not been deactivated or closed. "
+ "database = " + mQuery.getDatabase().getLabel()
+ ", table = " + mEditTable
+ ", query = " + sql.substring(0, (len > 1000) ? 1000 : len),
null);
}
}
} finally {
super.finalize();
}
}
很明显就可以看出,当mWindow不为空时,会进行泄漏的消息上报。这里的window指的是cursor的查询窗口,执行过move函数会赋值
边栏推荐
- C语言一点点(未来可会增加)
- 解决IDEA:Class ‘XXX‘ not found in module ‘XXX‘
- Mustache syntax
- ArrayList analysis 1-cycle, capacity expansion, version
- 機器人編程的培訓學科類原理
- 软硬件基础知识学习--小日记(1)
- A letter to 5000 fans!
- Interpreting the scientific and technological literacy contained in maker Education
- Sword finger offer 19 Regular Expression Matching
- CSDN common complex formula template record
猜你喜欢
Windows环境下安装MongoDB数据库
Sword finger offer 18 Delete the node of the linked list
Service
Get to know the drawing component of flutter - custompaint
【学习笔记】构造
Analyzing the wisdom principle in maker education practice
Kongyiji's first question: how much do you know about service communication?
二十多年来第一次!CVPR最佳学生论文授予中国高校学生!
探索互联网时代STEAM教育创新之路
孔乙己第一问之服务通信知多少?
随机推荐
Detailed analysis of operators i++ and ++i in JS, i++ and ++i
Length of the longest integrable subarray
Sword finger offer 18 Delete the node of the linked list
解决IDEA:Class ‘XXX‘ not found in module ‘XXX‘
Installing mongodb database in Windows Environment
机器人编程的培训学科类原理
Docker deployment MySQL 8
What is product thinking
Implementation of date class
Analysis of blocktoken principle
TCP三次握手为什么不是两次或四次
Openmv and k210 of the f question of the 2021 video game call the openmv API for line patrol, which is completely open source.
Training discipline principle of robot programming
Pytorch installs and uses GPU acceleration
js中把数字转换成汉字输出
Shift operators
【go】go 实现行专列 将集合进行转列
探索互联网时代STEAM教育创新之路
Orb-slam2 source code learning (II) map initialization
解读创客教育所蕴含的科技素养