From 2fe93c46ae8755bdba450266432ba4fd481e6304 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ricau Date: Sun, 10 May 2015 09:10:14 -0700 Subject: [PATCH] Fix Strict mode violations * Enable Strict Mode thread policy in the sample app. * Fixed violation when cleaning up files on startup. * Fixed violation when enabling components, the other side of the binder does IO operations. Fixes #15 --- .../leakcanary/AndroidHeapDumper.java | 21 +++++++++------ .../internal/LeakCanaryInternals.java | 26 ++++++++++++++----- .../leakcanary/ExampleApplication.java | 21 ++++++++------- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/library/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java b/library/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java index f410065d43..130ad6d024 100644 --- a/library/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java +++ b/library/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java @@ -17,6 +17,7 @@ import android.os.Debug; import android.util.Log; +import com.squareup.leakcanary.internal.LeakCanaryInternals; import java.io.File; import java.io.IOException; @@ -57,13 +58,17 @@ private File getHeapDumpFile() { * the app process was killed. */ public void cleanup() { - if (isExternalStorageWritable()) { - Log.d(TAG, "Could not attempt cleanup, external storage not mounted."); - } - File heapDumpFile = getHeapDumpFile(); - if (heapDumpFile.exists()) { - Log.d(TAG, "Previous analysis did not complete correctly, cleaning: " + heapDumpFile); - heapDumpFile.delete(); - } + LeakCanaryInternals.executeOnFileIoThread(new Runnable() { + @Override public void run() { + if (isExternalStorageWritable()) { + Log.d(TAG, "Could not attempt cleanup, external storage not mounted."); + } + File heapDumpFile = getHeapDumpFile(); + if (heapDumpFile.exists()) { + Log.d(TAG, "Previous analysis did not complete correctly, cleaning: " + heapDumpFile); + heapDumpFile.delete(); + } + } + }); } } diff --git a/library/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanaryInternals.java b/library/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanaryInternals.java index efeaa3ab81..ffd7fcde83 100644 --- a/library/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanaryInternals.java +++ b/library/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanaryInternals.java @@ -25,6 +25,8 @@ import android.os.Environment; import android.util.Log; import java.io.File; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; @@ -34,6 +36,12 @@ public final class LeakCanaryInternals { + private static final Executor fileIoExecutor = Executors.newSingleThreadExecutor(); + + public static void executeOnFileIoThread(Runnable runnable) { + fileIoExecutor.execute(runnable); + } + public static File storageDirectory() { File downloadsDirectory = Environment.getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS); File leakCanaryDirectory = new File(downloadsDirectory, "leakcanary"); @@ -78,12 +86,18 @@ public static String classSimpleName(String className) { } } - public static void setEnabled(Context context, Class componentClass, boolean enabled) { - ComponentName component = new ComponentName(context, componentClass); - PackageManager packageManager = context.getPackageManager(); - int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED; - // Blocks on IPC. - packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP); + public static void setEnabled(Context context, final Class componentClass, + final boolean enabled) { + final Context appContext = context.getApplicationContext(); + executeOnFileIoThread(new Runnable() { + @Override public void run() { + ComponentName component = new ComponentName(appContext, componentClass); + PackageManager packageManager = appContext.getPackageManager(); + int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED; + // Blocks on IPC. + packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP); + } + }); } public static boolean isInServiceProcess(Context context, Class serviceClass) { diff --git a/library/leakcanary-sample/src/main/java/com/example/leakcanary/ExampleApplication.java b/library/leakcanary-sample/src/main/java/com/example/leakcanary/ExampleApplication.java index 220e05ec06..5330a7ca31 100644 --- a/library/leakcanary-sample/src/main/java/com/example/leakcanary/ExampleApplication.java +++ b/library/leakcanary-sample/src/main/java/com/example/leakcanary/ExampleApplication.java @@ -16,21 +16,22 @@ package com.example.leakcanary; import android.app.Application; -import android.content.Context; +import android.os.StrictMode; import com.squareup.leakcanary.LeakCanary; -import com.squareup.leakcanary.RefWatcher; public class ExampleApplication extends Application { - public static RefWatcher getRefWatcher(Context context) { - ExampleApplication application = (ExampleApplication) context.getApplicationContext(); - return application.refWatcher; - } - - private RefWatcher refWatcher; - @Override public void onCreate() { super.onCreate(); - refWatcher = LeakCanary.install(this); + enabledStrictMode(); + LeakCanary.install(this); + } + + private void enabledStrictMode() { + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() // + .detectAll() // + .penaltyLog() // + .penaltyDeath() // + .build()); } }