当前位置:网站首页>使用StrictMode-StrictMode原理(1)
使用StrictMode-StrictMode原理(1)
2022-07-01 00:40:00 【怪叔叔萝莉控】
1. strictmode入门使用:
strictmode是android提供的一种调试环境的动态检测机制,主要的作用有两类:
1.1 线程策略
检测主线程读写卡顿
detectDiskReads(); detectDiskWrites();检测是否主线程使用网络
detectNetwork();检测自定义的慢检测
detectCustomSlowCalls()资源不匹配检测
detectResourceMismatches()没有buffer的IO操作
detectUnbufferedIo()
具体的代码位置:
StrictMode#ThreadPolicy#Builder.detectAll
public @NonNull Builder detectAll() {
detectDiskReads();
detectDiskWrites();
detectNetwork();
final int targetSdk = VMRuntime.getRuntime().getTargetSdkVersion();
if (targetSdk >= Build.VERSION_CODES.HONEYCOMB) {
detectCustomSlowCalls();
}
if (targetSdk >= Build.VERSION_CODES.M) {
detectResourceMismatches();
}
if (targetSdk >= Build.VERSION_CODES.O) {
detectUnbufferedIo();
}
return this;
}
1.2 虚拟机VM策略
检测sqlite泄漏
detectLeakedSqlLiteObjects();检测activity泄漏:注意这里是引用计数,实际无法检测出真的泄漏,后续会进行详细讲解
detectActivityLeaks()检测是否需要关闭的没有关闭,比如IO流
detectLeakedClosableObjects检测是否有组件忘记反注册(BroadCastReceiver,Service)
detectLeakedRegistrationObjects()检测File Uri是否暴露
detectFileUriExposure()检测是否明文网络请求
detectCleartextNetwork()检测不正确的conext使用
detectIncorrectContextUse()检测不安全的intent launch
detectUnsafeIntentLaunch()源代码:
public @NonNull Builder detectAll() {
detectLeakedSqlLiteObjects();
final int targetSdk = VMRuntime.getRuntime().getTargetSdkVersion();
if (targetSdk >= Build.VERSION_CODES.HONEYCOMB) {
detectActivityLeaks();
detectLeakedClosableObjects();
}
if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN) {
detectLeakedRegistrationObjects();
}
if (targetSdk >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
detectFileUriExposure();
}
if (targetSdk >= Build.VERSION_CODES.M) {
// TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have
// facility for apps to mark sockets that should be ignored
if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) {
detectCleartextNetwork();
}
}
if (targetSdk >= Build.VERSION_CODES.O) {
detectContentUriWithoutPermission();
detectUntaggedSockets();
}
if (targetSdk >= Build.VERSION_CODES.Q) {
detectCredentialProtectedWhileLocked();
}
if (targetSdk >= Build.VERSION_CODES.R) {
detectIncorrectContextUse();
}
if (targetSdk >= Build.VERSION_CODES.S) {
detectUnsafeIntentLaunch();
}
// TODO: Decide whether to detect non SDK API usage beyond a certain API level.
// TODO: enable detectImplicitDirectBoot() once system is less noisy
return this;
}
1.3 入门使用
private fun strictModeOnDebug() {
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= 28) {
StrictMode.setThreadPolicy(
ThreadPolicy.Builder()
.detectAll() //检测Thread所有选项
.penaltyLog() //打印日志
.build()
)
StrictMode.setVmPolicy(
VmPolicy.Builder()
.detectAll() //检测VM所有选项
.penaltyLog() //打印日志
.build()
)
TrafficStats.setThreadStatsTag(0xF00D)
}
}
1.3.1 Thread检测操作
- 监控写操作
findViewById<Button>(R.id.io_read_btn).setOnClickListener {
val outputStream = FileOutputStream(File(getExternalFilesDir("")?.path + "hello.json"))
outputStream.write("hello world".toByteArray())
outputStream.flush()
outputStream.close()
}
logcat日志:
2022-06-20 07:57:35.043 13012-13012/com.ifreedomer.strictmode D/StrictMode: StrictMode policy violation; ~duration=1 ms: android.os.strictmode.DiskWriteViolation
at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1460)
at libcore.io.BlockGuardOs.write(BlockGuardOs.java:347)
at libcore.io.IoBridge.write(IoBridge.java:526)
at java.io.FileOutputStream.write(FileOutputStream.java:381)
at java.io.FileOutputStream.write(FileOutputStream.java:359)
at com.ifreedomer.strictmode.MainActivity.onCreate$lambda-0(MainActivity.kt:26)
at com.ifreedomer.strictmode.MainActivity.$r8$lambda$J_2M7j2bq49wREm_StCdiMLvSuc(Unknown Source:0)
at com.ifreedomer.strictmode.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:6597)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
读日志也同理。需要注意的是,IO我们确实需要经常性的在主线程进行,为避免过多的日志对开发造成干扰,推荐使用时可以屏蔽此选项
1.3.2 VM检测操作
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() }logcat:
2022-06-20 08:11:36.071 13677-13687/com.ifreedomer.strictmode D/StrictMode: StrictMode policy violation: android.os.strictmode.LeakedClosableViolation: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. at android.os.StrictMode$AndroidCloseGuardReporter.report(StrictMode.java:1786) at dalvik.system.CloseGuard.warnIfOpen(CloseGuard.java:264) at java.io.FileOutputStream.finalize(FileOutputStream.java:475) at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:250) at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:237) at java.lang.Daemons$Daemon.run(Daemons.java:103) at java.lang.Thread.run(Thread.java:764) Caused by: java.lang.Throwable: Explicit termination method 'close' not called at dalvik.system.CloseGuard.open(CloseGuard.java:221) at java.io.FileOutputStream.<init>(FileOutputStream.java:241) at java.io.FileOutputStream.<init>(FileOutputStream.java:180) at com.ifreedomer.strictmode.MainActivity.onCreate$lambda-4(MainActivity.kt:57) at com.ifreedomer.strictmode.MainActivity.$r8$lambda$sFdQJzxyBqsXzAQCFxp0PCpUtgg(Unknown Source:0) at com.ifreedomer.strictmode.MainActivity$$ExternalSyntheticLambda3.onClick(Unknown Source:2) at android.view.View.performClick(View.java:6597) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194) at android.view.View.performClickInternal(View.java:6574) at android.view.View.access$3100(View.java:778) at android.view.View$PerformClick.run(View.java:25885) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)数据库泄漏检测
cursor未关闭
findViewById<Button>(R.id.database_open_btn).setOnClickListener {
val readableDatabase =
dbHelper.readableDatabase
var rawQuery = readableDatabase.rawQuery("select * from user", null)
val sqLiteCursor = rawQuery as SQLiteCursor
sqLiteCursor.moveToFirst()
Log.d(TAG,"sql window = ${sqLiteCursor.window}")
rawQuery = null
readableDatabase.close()
Runtime.getRuntime().gc()
}
logcat:
2022-06-20 08:00:19.687 13012-13022/com.ifreedomer.strictmode D/StrictMode: StrictMode policy violation: android.os.strictmode.SqliteObjectLeakedViolation: Finalizing a Cursor that has not been deactivated or closed. database = /data/user/0/com.ifreedomer.strictmode/databases/haha.db, table = null, query = select * from user
at android.os.StrictMode.onSqliteObjectLeaked(StrictMode.java:1956)
at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:285)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:250)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:237)
at java.lang.Daemons$Daemon.run(Daemons.java:103)
at java.lang.Thread.run(Thread.java:764)
Caused by: android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
at android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:103)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:52)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)
at com.ifreedomer.strictmode.MainActivity.onCreate$lambda-2(MainActivity.kt:43)
at com.ifreedomer.strictmode.MainActivity.$r8$lambda$KlEPG7__y4DedDU3EV-gqJ4mzpo(Unknown Source:0)
at com.ifreedomer.strictmode.MainActivity$$ExternalSyntheticLambda3.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:6597)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1194)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
1.4 设置监听
如果你想获得这些泄漏的信息,你可以自己实现StrictMode的Listener
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= 28) {
StrictMode.setThreadPolicy(
ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyListener(Executors.newSingleThreadExecutor(),{
})
.build()
)
StrictMode.setVmPolicy(
VmPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyListener(Executors.newSingleThreadExecutor(),{
})
.build()
)
}
边栏推荐
- [2023 MediaTek approved the test questions in advance] ~ questions and reference answers
- Win11安装redis 数据库以及redis desktop manager的下载
- 解决IDEA:Class ‘XXX‘ not found in module ‘XXX‘
- [LeetCode] 两数之和【1】
- The question of IBL precomputation is finally solved
- 解析创客教育实践中的智慧原理
- Koa koa-combine-routers 分路由管理
- What is the difference between Pipeline and Release Pipeline in azure devops?
- js中把数字转换成汉字输出
- 二十多年来第一次!CVPR最佳学生论文授予中国高校学生!
猜你喜欢

机器人编程的培训学科类原理

Unhandled Exception: MissingPluginException(No implementation found for method launch on channel)

Orb-slam2 source code learning (II) map initialization

Chapter 53 overall understanding of procedures from the perspective of business logic implementation

C # generates PPK files in putty format (supports passphrase)

C # Generate PPK files in Putty format (passthrough support)

用recyclerReview展示Banner,很简单

Flutter Error: Cannot run with sound null safety, because the following dependencies don‘t support

Analyzing the wisdom principle in maker education practice

Analyze the maker education path integrating the essence of discipline
随机推荐
Q play soft large toast to bring more comfortable sleep
染色法判断二分图
Split the linked list [take next first and then cut the linked list to prevent chain breakage]
New content violation degree determination scana bad information monitoring capability update issue 5
P4 learning - Basic tunneling
MATLAB 最远点采样(FPS改进版)
Using asyncio for concurrency
集群与LVS介绍及原理解析
Golang treasure house recommendation
fluttertoast
ArrayList analysis 1-cycle, capacity expansion, version
技术人进阶画业务大图,手把手教学来了
PHP online confusion encryption tutorial sharing + basically no solution
Vnctf 2022 cm CM1 re reproduction
奇偶链表[链表操作的两种大方向]
ASCII、Unicode、GBK、UTF-8之间的关系
DLS-42/6-4 DC110V双位置继电器
[original] PLSQL index sorting optimization
分割链表[先取next再斩断链表防止断链]
Unhandled Exception: MissingPluginException(No implementation found for method launch on channel)