Android Matrix总结
2022-01-12 本文已影响0人
曾大稳丶
Matrix地址:https://github.com/Tencent/matrix
matrix fps检测
监控Choreographer的CALLBACK_INPUT,CALLBACK_ANIMATION,CALLBACK_TRAVERSAL三个阶段并且结合handler的dispath logging打印完成时间监控,计算掉帧然后上传。
Choreographer:https://www.cnblogs.com/huansky/p/13912202.html
matrix anr监控
通过handler的dispath logging打印完成,start的时候 anrHandler.post 5s的延迟task来相应anr,end移除这个事件
matrix 函数耗时记录
通过asm插桩函数统计,每个函数对应一个id,asm编译的时候生成函数id,在方法的进和出分别调用i和o函数进行统计。采用空间换时间的方式,预先申请一个100 * 10000 约为7.6m的long数组buffer,long存储方法id,时间戳,以及出入栈信息。计算函数耗时的时候只需要记录方法开始的index以及结束的index,然后从buffer里面取出即可。
martix 慢函数检测
通过handler的dispath logging打印以及结合函数耗时记录,获取handler的dispath start和end中间的所有函数计算即可,超过阀值报警通知
martix io监控
https://github.com/Tencent/matrix/wiki/Matrix-Android-IOCanary
主要监控内容:
1. 主线程的文件读写操作耗时
2. 读写的buf过小,BufferedOutputStream优化
3. 重复读取,常用文件,加cache
4. 句柄和游标没有关闭
实现方式
- 通过xhook把libopenjdkjvm.so,libjavacore.so,libopenjdk.so的open,open64,read,__read_chk,write,__write_chk,close给hook,然后记录统计。主要用于统计文件读写,在close的时候触发检测逻辑。
JNIEXPORT jboolean JNICALL
Java_com_tencent_matrix_iocanary_core_IOCanaryJniBridge_doHook(JNIEnv *env, jclass type) {
__android_log_print(ANDROID_LOG_INFO, kTag, "doHook");
for (int i = 0; i < TARGET_MODULE_COUNT; ++i) {
const char* so_name = TARGET_MODULES[i];
__android_log_print(ANDROID_LOG_INFO, kTag, "try to hook function in %s.", so_name);
void* soinfo = xhook_elf_open(so_name);
if (!soinfo) {
__android_log_print(ANDROID_LOG_WARN, kTag, "Failure to open %s, try next.", so_name);
continue;
}
xhook_hook_symbol(soinfo, "open", (void*)ProxyOpen, (void**)&original_open);
xhook_hook_symbol(soinfo, "open64", (void*)ProxyOpen64, (void**)&original_open64);
bool is_libjavacore = (strstr(so_name, "libjavacore.so") != nullptr);
if (is_libjavacore) {
if (xhook_hook_symbol(soinfo, "read", (void*)ProxyRead, (void**)&original_read) != 0) {
__android_log_print(ANDROID_LOG_WARN, kTag, "doHook hook read failed, try __read_chk");
if (xhook_hook_symbol(soinfo, "__read_chk", (void*)ProxyReadChk, (void**)&original_read_chk) != 0) {
__android_log_print(ANDROID_LOG_WARN, kTag, "doHook hook failed: __read_chk");
xhook_elf_close(soinfo);
return JNI_FALSE;
}
}
if (xhook_hook_symbol(soinfo, "write", (void*)ProxyWrite, (void**)&original_write) != 0) {
__android_log_print(ANDROID_LOG_WARN, kTag, "doHook hook write failed, try __write_chk");
if (xhook_hook_symbol(soinfo, "__write_chk", (void*)ProxyWriteChk, (void**)&original_write_chk) != 0) {
__android_log_print(ANDROID_LOG_WARN, kTag, "doHook hook failed: __write_chk");
xhook_elf_close(soinfo);
return JNI_FALSE;
}
}
}
xhook_hook_symbol(soinfo, "close", (void*)ProxyClose, (void**)&original_close);
xhook_elf_close(soinfo);
}
__android_log_print(ANDROID_LOG_INFO, kTag, "doHook done.");
return JNI_TRUE;
}
补充:android 10兼容处理:
//android 10 close hook
//https://www.cnblogs.com/seekting/p/14423095.html
// "libjavacore.so"
if(xhook_register(so_name, "android_fdsan_close_with_tag",
(void *) proxy_android_fdsan_close_with_tag,
(void **) &original_android_fdsan_close_with_tag)!=0){
LOGE( "xhook_register android_fdsan_close_with_tag %s error",so_name);
}
- 通过动态代理hook CloseGuard的report函数实现句柄和游标没有关闭检测。
private boolean tryUnHook() {
try {
Class<?> closeGuardCls = Class.forName("dalvik.system.CloseGuard");
Class<?> closeGuardReporterCls = Class.forName("dalvik.system.CloseGuard$Reporter");
Method methodSetReporter = closeGuardCls.getDeclaredMethod("setReporter", closeGuardReporterCls);
Method methodSetEnabled = closeGuardCls.getDeclaredMethod("setEnabled", boolean.class);
methodSetReporter.invoke(null, sOriginalReporter);
methodSetEnabled.invoke(null, false);
// close matrix close guard also
MatrixCloseGuard.setEnabled(false);
return true;
} catch (Throwable e) {
MatrixLog.e(TAG, "tryHook exp=%s", e);
}
return false;
}