StrictMode是Android提供的一个开发工具,用于检测一些异常的操作,以便开发者进行修复。StrictMode可以监控以下问题,
- 不应该在应用主线程中完成的工作,包括磁盘读写、网络访问等。
- 内存泄露,包括Activity泄露、SQLite泄露、未正确释放的对象等。
使能StrictMode
通常在Application和Activity的开始处(如onCreate)添加代码使能StrictMode,
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
开启StrictMode需要进行两方面的设置:ThreadPolicy和VmPolicy。两种策略中以“detect”开头命名的方法代表需要检测的问题,以“penalty”开头命名地 方法代表探测到问题后的处理方式。
- ThreadPolicy为线程方面使用的策略,包括磁盘读写检测,网络访问检测等。
- VmPolicy为VM相关的策略,用于检测内存泄露,未释放的对象等。
两种策略中使用的主要方法如下,
ThreadPolicy | |
---|---|
detectAll() | 检测所有潜在的问题 |
detectCustomSlowCalls() | 检测慢速调用 |
detectDiskReads() | 检测磁盘读操作 |
detectDiskWrites() | 检测磁盘写操作 |
detectNetwork() | 检测网络操作 |
detectResourceMismatches() | 检测定义资源类型和getter调用之间的不匹配 |
detectUnbufferedIo() | 检测未缓存的I/O操作 |
penaltyDeath() | 检测到问题后crash整个进程 |
penaltyDeathOnNetwork() | 检测到问题后crash任何使用网络的进程 |
penaltyDialog() | 检测到问题后弹出对话框 |
penaltyDropBox() | 检测到问题后将堆栈和数据写到DropBox中 |
penaltyFlashScreen() | 检测到问题后闪烁屏幕 |
penaltyLog() | 检测到问题后记录到系统日志中。 |
VmPolicy | |
---|---|
detectAll() | 检测所有潜在的问题 |
detectActivityLeaks() | 检测Activity内存泄露 |
detectCleartextNetwork() | 检测未使用SSL / TLS打包的任何网络传输 |
detectContentUriWithoutPermission() | 检测未设置读写权限的"content://Uri"传输 |
detectFileUriExposure() | 检测“file://Uri"传输 |
detectLeakedClosableObjects() | 检测对象未正常关闭。 |
detectLeakedRegistrationObjects() | 检测BroadcastReceiver或ServiceConnection在Context拆卸时发生的泄露 |
detectLeakedSqlLiteObjects() | 检测SQLite对象未正常关闭 |
detectNonSdkApiUsage() | 检测非Android SDK API的反射用法。 |
detectUntaggedSockets() | 检测未使用TrafficStats标记的套接字 |
penaltyDeath() | 检测到问题后crash整个进程 |
penaltyDeathOnCleartextNetwork() | 检测到问题后crash任何使用网络的进程 |
penaltyDeathOnFileUriExposure() | 当“file://Uri"暴露在应用之外时,crash整个进程 |
penaltyDropBox() | 检测到问题后将堆栈和数据写到DropBox中 |
penaltyLog() | 检测到问题后记录到系统日志中。 |
setClassInstanceLimit(Class klass, int instanceLimit) | 设置同时在内存中存储一个类实例的上限。 |
检查StrictMode的结果
当在策略中设置penaltyLog()时,可以在系统log中打印相关log,可以使用”adb logcat -s StrictMode“进行查看。例如下面这段log,说明涉嫌违规的操作是StrickMode:DiskReadViolation,耗时48ms。
D StrictMode: StrictMode policy violation; ~duration=48 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=4390919 violation=2
at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1263)
at android.database.sqlite.SQLiteConnection.applyBlockGuardPolicy(SQLiteConnection.java:1039)
at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:840)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:836)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:132)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:219)
at android.database.AbstractCursor.moveToNext(AbstractCursor.java:268)
at com.gm.android.emojistore.provider.EmojiStoreProvider.handleEtxetQuery(EmojiStoreProvider.java:108)
at android.content.ContentProvider.query(ContentProvider.java:1017)
at android.content.ContentProvider$Transport.query(ContentProvider.java:238)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:453)
当在设备端通过设置打开严格模式时,出现违规操作时屏幕会闪烁。
设置-》开发人员选项-》监控-》启用严格模式
当在策略中设置penaltyDropBox() 时,出现违规操作时会在/data/system/dropbox/下生成文件。文件包括system_app_strictmode 和 data_app_strictmode两种,内容包括问题发生时的堆栈和进程相关信息。
参考文档:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。