Skip to content

Commit

Permalink
Merge pull request #2666 from square/py/alpha2_more
Browse files Browse the repository at this point in the history
More alpha2 work
  • Loading branch information
pyricau committed May 3, 2024
2 parents 7e3a9ad + 4cf7d99 commit 152152c
Show file tree
Hide file tree
Showing 177 changed files with 644 additions and 428 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Expand Up @@ -98,7 +98,7 @@ jobs:
touch emulator.log # create log file
chmod 777 emulator.log # allow writing to log file
adb logcat >> emulator.log & # pipe all logcat messages into log file as a background process
./gradlew leakcanary:leakcanary-android-debug:connectedCheck leakcanary:leakcanary-android:connectedCheck leakcanary:leakcanary-android-instrumentation:connectedCheck --no-build-cache --no-daemon --stacktrace
./gradlew leakcanary:leakcanary-android-core:connectedCheck leakcanary:leakcanary-android:connectedCheck leakcanary:leakcanary-android-instrumentation:connectedCheck --no-build-cache --no-daemon --stacktrace
- name: Upload results
if: ${{ always() }}
uses: actions/upload-artifact@v3
Expand Down
36 changes: 20 additions & 16 deletions docs/changelog.md
Expand Up @@ -5,34 +5,25 @@ Please thank our [contributors](https://github.com/square/leakcanary/graphs/cont

## Version 3.0 Alpha 2 (not released yet)

### Heap Growth

* Deleted the `shark-heap-growth` artifact, the code has been merged into the `shark*` and `leakcanary*` modules.
* The `leakcanary-android-core` artifact was renamed `leakcanary-android-debug`. `leakcanary-android-core` is now a much smaller artifact with a few shared utilities.
* Undo of breaking API changes that were introduced in alpha 1. The goal is to make the upgrade seamless. Please file an issue if you find an API breaking change from a 2.x release.
* New `leakcanary-core` module that includes runtime leak detection utilities that aren't Android specific.
* Optimization: for known data structures that don't reference the rest of the graph beyond the references we
known about, we explore them locally at once and stop enqueuing their internals, which reduces the memory
footprint and the IO reads.
* Revamped the APIs for setup. Here's an updated example usage:
* Revamped the heap growth detection APIs. Here's the updated Espresso test example:

```groovy
dependencies {
androidTestImplementation 'com.squareup.leakcanary:leakcanary-core:3.0-alpha-2'
androidTestImplementation 'com.squareup.leakcanary:shark-android:3.0-alpha-2'
androidTestImplementation 'com.squareup.leakcanary:leakcanary-android-test:3.0-alpha-2'
}
```

```kotlin
class MyEspressoTest {
val detector = ObjectGrowthDetector
.androidDetector()
.fromHeapDumpingRepeatedScenario(
heapGraphProvider = HeapGraphProvider.dumpingAndDeletingGraphProvider(
heapDumper = { Debug.dumpHprofData(it.absolutePath) },
),
maxHeapDumps = 5,
scenarioLoopsPerDump = 1,
)
.forAndroidHeap()
.repeatingAndroidInProcessScenario()

@Test
fun greeter_says_hello_does_not_leak() {
Expand All @@ -48,6 +39,19 @@ class MyEspressoTest {
}
```

Ensure your UI tests have enough heap by updating `src/androidTest/AndroidManifest.xml`:

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Performing the heap growth analysis in process requires more heap. -->
<application
android:largeHeap="true"/>
</manifest>
```

## Version 2.14 (2024-04-17)

* 🐛 [#2650](https://github.com/square/leakcanary/issues/2650) Removed accidental usage of `SettableFuture`, a `WorkManager` internal class, which will be removed in a **future release** of WorkManager. After updating WorkManager to that future release, **all versions of LeakCanary from 2.8 to 2.13 will crash on leak analysis**. To avoid a nasty surprise in the near future, **update to LeakCanary 2.14**.
Expand Down Expand Up @@ -563,7 +567,7 @@ dependencies {
}
```

Note 1: `leakcanary-android` adds the code for automatic install to `leakcanary-android-core`. If you're calling `AppWatcher.manualInstall()`, you can depend directly on `leakcanary-android-core` instead of `leakcanary-android`, and you won't need the disable any automatic install.
Note 1: `leakcanary-android` adds the code for automatic installl to `leakcanary-android-core`. If you're calling `AppWatcher.manualInstall()`, you can depend directly on `leakcanary-android-core` instead of `leakcanary-android`, and you won't need the disable any automatic install.

Note 2: the same principle applies to `leakcanary-object-watcher-android`: it depends on `leakcanary-object-watcher-android-core` and adds automatic install, while `leakcanary-object-watcher-android-startup` leverages the App Startup library. Same for `plumber-android`, `plumber-android-core` and `plumber-android-startup`.

Expand Down Expand Up @@ -1432,7 +1436,7 @@ For more details, see the [2.0-beta-2 Milestone](https://github.com/square/leakc
* New standalone library! [Shark](shark.md) is the heap analyzer that powers LeakCanary 2, and it can run in any Java VM. It comes with a [CLI](shark.md#shark-cli): you can now run `shark-cli analyze-process com.example.myapp` from your computer.
* New Heap Explorer directly on device! Open a Heap Analysis in LeakCanary, tap the options menu and select "Heap Explorer". This is still experimental and not very user friendly, contributions welcome!
* **Large API rewrite** to improve usability. If you used the alpha with a customized configuration, there are breaking changes. Of note: LeakSentry became [AppWatcher](/leakcanary/api/leakcanary-object-watcher-android/leakcanary/-app-watcher/), RefWatcher became [ObjectWatcher](/leakcanary/api/leakcanary-object-watcher/leakcanary/-object-watcher/), AndroidExcludedRefs became [AndroidReferenceMatchers](/leakcanary/api/shark-android/shark/-android-reference-matchers/), AnalysisResultListener became [OnHeapAnalyzedListener](/leakcanary/api/leakcanary-android-debug/leakcanary/-on-heap-analyzed-listener/), AndroidLeakTraceInspectors became [AndroidObjectInspectors](/leakcanary/api/shark-android/shark/-android-object-inspectors/).
* **Large API rewrite** to improve usability. If you used the alpha with a customized configuration, there are breaking changes. Of note: LeakSentry became [AppWatcher](/leakcanary/api/leakcanary-object-watcher-android/leakcanary/-app-watcher/), RefWatcher became [ObjectWatcher](/leakcanary/api/leakcanary-object-watcher/leakcanary/-object-watcher/), AndroidExcludedRefs became [AndroidReferenceMatchers](/leakcanary/api/shark-android/shark/-android-reference-matchers/), AnalysisResultListener became [OnHeapAnalyzedListener](/leakcanary/api/leakcanary-android-core/leakcanary/-on-heap-analyzed-listener/), AndroidLeakTraceInspectors became [AndroidObjectInspectors](/leakcanary/api/shark-android/shark/-android-object-inspectors/).
* The entire API surface is now documented and the documentation is available on this website: see the **LeakCanary API** tab at the top.
* Removed the **dependency on Android X**. No more configuration issues! [#1462](https://github.com/square/leakcanary/issues/1462)
* Added **Proguard rules** for LeakCanary and ObjectWatcher. [#1500](https://github.com/square/leakcanary/pull/1500)
Expand Down
6 changes: 3 additions & 3 deletions docs/dev-env.md
Expand Up @@ -5,13 +5,13 @@
* We use two spaces code indentation, use `SquareAndroid` code style settings from https://github.com/square/java-code-styles.
* Build with `./gradlew build`.
* Running the failing UI tests to confirm leak detection correctly fails UI tests: `./gradlew leakcanary-android-sample:connectedCheck`.
* Normal UI tests: `./gradlew leakcanary-android-debug:connectedCheck`.
* Normal UI tests: `./gradlew leakcanary-android-core:connectedCheck`.

## Static Code Analysis
## Static Code Analysis
* LeakCanary [uses](https://github.com/square/leakcanary/pull/1535) [Detekt](https://arturbosch.github.io/detekt/) for static Code analysis.
* Analyze the entire project with `./gradlew check` or particular modules with `./gradlew :module-name:check`. Detekt will fail the build if any ruleset violations are found. **You should fix all issues before pushing the branch to remote**.
* There's also a **git pre-push** hook that will run analysis automatically before pushing a branch to the remote. If there are any violations - it will prevent the push. Fix the issues!
* You can bypass the git hook though; Travis CI will still run checks and will fail if any violations are found.
* You can bypass the git hook though; Travis CI will still run checks and will fail if any violations are found.
* Detekt report will be printed in the console and saved to `/moduleDir/build/reports/`.

## Deploying locally
Expand Down
2 changes: 1 addition & 1 deletion docs/upgrading-to-leakcanary-2.0.md
Expand Up @@ -150,7 +150,7 @@ class DebugExampleApplication : ExampleApplication() {
}
```

LeakCanary is in charge of taking heap dumps and analyzing them. Its configuration can be updated at any time by replacing [LeakCanary.config](/leakcanary/api/leakcanary-android-debug/leakcanary/-leak-canary/config/):
LeakCanary is in charge of taking heap dumps and analyzing them. Its configuration can be updated at any time by replacing [LeakCanary.config](/leakcanary/api/leakcanary-android-core/leakcanary/-leak-canary/config/):

```kotlin
disableLeakCanaryButton.setOnClickListener {
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Expand Up @@ -44,13 +44,15 @@ androidX-fragment = { module = "androidx.fragment:fragment", version = "1.0.0" }
# Exposed transitively, avoid increasing
androidX-startup = { module = "androidx.startup:startup-runtime", version = "1.0.0" }
androidX-test-core = { module = "androidx.test:core", version = "1.4.0" }
androidX-test-monitor = { module = "androidx.test:monitor", version = "1.4.0" }
androidX-test-rules = { module = "androidx.test:rules", version.ref = "androidXTest" }
# Exposed transitively, avoid increasing
androidX-test-runner = { module = "androidx.test:runner", version = "1.4.0" }
androidX-test-orchestrator = { module = "androidx.test:orchestrator", version = "1.4.1" }
androidX-test-espresso = { module = "androidx.test.espresso:espresso-core", version = "3.4.0" }
androidX-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidXJunit" }
androidX-test-junitKtx = { module = "androidx.test.ext:junit-ktx", version.ref = "androidXJunit" }
androidX-test-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version = "2.2.0" }
androidX-work-runtime = { module = "androidx.work:work-runtime", version.ref = "workManager" }
androidX-work-multiprocess = { module = "androidx.work:work-multiprocess", version.ref = "workManager" }

Expand Down
162 changes: 154 additions & 8 deletions leakcanary/leakcanary-android-core/api/leakcanary-android-core.api
@@ -1,14 +1,160 @@
public final class leakcanary/AndroidDebugHeapDumper : leakcanary/HeapDumper {
public static final field INSTANCE Lleakcanary/AndroidDebugHeapDumper;
public fun dumpHeap (Ljava/io/File;)V
public final class com/squareup/leakcanary/core/BuildConfig {
public static final field BUILD_TYPE Ljava/lang/String;
public static final field DEBUG Z
public static final field GIT_SHA Ljava/lang/String;
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
public static final field LIBRARY_VERSION Ljava/lang/String;
public fun <init> ()V
}

public final class leakcanary/AndroidDebugHeapDumperKt {
public static final fun forAndroidInProcess (Lleakcanary/HeapDumper$Companion;)Lleakcanary/AndroidDebugHeapDumper;
public final class leakcanary/BackgroundThreadHeapAnalyzer : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/BackgroundThreadHeapAnalyzer;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/RepeatingAndroidInProcessScenarioKt {
public static final fun repeatingAndroidInProcessScenario (Lshark/ObjectGrowthDetector;II)Lshark/RepeatingScenarioObjectGrowthDetector;
public static synthetic fun repeatingAndroidInProcessScenario$default (Lshark/ObjectGrowthDetector;IIILjava/lang/Object;)Lshark/RepeatingScenarioObjectGrowthDetector;
public abstract interface class leakcanary/EventListener {
public abstract fun onEvent (Lleakcanary/EventListener$Event;)V
}

public abstract class leakcanary/EventListener$Event : java/io/Serializable {
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getUniqueId ()Ljava/lang/String;
}

public final class leakcanary/EventListener$Event$DumpingHeap : leakcanary/EventListener$Event {
public fun <init> (Ljava/lang/String;)V
}

public abstract class leakcanary/EventListener$Event$HeapAnalysisDone : leakcanary/EventListener$Event {
public synthetic fun <init> (Ljava/lang/String;Lshark/HeapAnalysis;Landroid/content/Intent;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getHeapAnalysis ()Lshark/HeapAnalysis;
public final fun getShowIntent ()Landroid/content/Intent;
}

public final class leakcanary/EventListener$Event$HeapAnalysisDone$HeapAnalysisFailed : leakcanary/EventListener$Event$HeapAnalysisDone {
public fun <init> (Ljava/lang/String;Lshark/HeapAnalysisFailure;Landroid/content/Intent;)V
}

public final class leakcanary/EventListener$Event$HeapAnalysisDone$HeapAnalysisSucceeded : leakcanary/EventListener$Event$HeapAnalysisDone {
public fun <init> (Ljava/lang/String;Lshark/HeapAnalysisSuccess;Ljava/util/Set;Landroid/content/Intent;)V
public final fun getUnreadLeakSignatures ()Ljava/util/Set;
}

public final class leakcanary/EventListener$Event$HeapAnalysisProgress : leakcanary/EventListener$Event {
public fun <init> (Ljava/lang/String;Lshark/OnAnalysisProgressListener$Step;D)V
public final fun getProgressPercent ()D
public final fun getStep ()Lshark/OnAnalysisProgressListener$Step;
}

public final class leakcanary/EventListener$Event$HeapDump : leakcanary/EventListener$Event {
public fun <init> (Ljava/lang/String;Ljava/io/File;JLjava/lang/String;)V
public final fun getDurationMillis ()J
public final fun getFile ()Ljava/io/File;
public final fun getReason ()Ljava/lang/String;
}

public final class leakcanary/EventListener$Event$HeapDumpFailed : leakcanary/EventListener$Event {
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;Z)V
public final fun getException ()Ljava/lang/Throwable;
public final fun getWillRetryLater ()Z
}

public final class leakcanary/LazyForwardingEventListener : leakcanary/EventListener {
public fun <init> (Lkotlin/jvm/functions/Function0;)V
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/LeakCanary {
public static final field INSTANCE Lleakcanary/LeakCanary;
public final fun dumpHeap ()V
public static final fun getConfig ()Lleakcanary/LeakCanary$Config;
public final fun newLeakDisplayActivityIntent ()Landroid/content/Intent;
public static final fun setConfig (Lleakcanary/LeakCanary$Config;)V
public final fun showLeakDisplayActivityLauncherIcon (Z)V
}

public final class leakcanary/LeakCanary$Config {
public fun <init> ()V
public fun <init> (ZZILjava/util/List;Ljava/util/List;Lshark/MetadataExtractor;ZIZLshark/LeakingObjectFinder;Lleakcanary/HeapDumper;Ljava/util/List;Z)V
public synthetic fun <init> (ZZILjava/util/List;Ljava/util/List;Lshark/MetadataExtractor;ZIZLshark/LeakingObjectFinder;Lleakcanary/HeapDumper;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun component10 ()Lshark/LeakingObjectFinder;
public final fun component11 ()Lleakcanary/HeapDumper;
public final fun component12 ()Ljava/util/List;
public final fun component13 ()Z
public final fun component2 ()Z
public final fun component3 ()I
public final fun component4 ()Ljava/util/List;
public final fun component5 ()Ljava/util/List;
public final fun component6 ()Lshark/MetadataExtractor;
public final fun component7 ()Z
public final fun component8 ()I
public final fun component9 ()Z
public final fun copy (ZZILjava/util/List;Ljava/util/List;Lshark/MetadataExtractor;ZIZLshark/LeakingObjectFinder;Lleakcanary/HeapDumper;Ljava/util/List;Z)Lleakcanary/LeakCanary$Config;
public static synthetic fun copy$default (Lleakcanary/LeakCanary$Config;ZZILjava/util/List;Ljava/util/List;Lshark/MetadataExtractor;ZIZLshark/LeakingObjectFinder;Lleakcanary/HeapDumper;Ljava/util/List;ZILjava/lang/Object;)Lleakcanary/LeakCanary$Config;
public fun equals (Ljava/lang/Object;)Z
public final fun getComputeRetainedHeapSize ()Z
public final fun getDumpHeap ()Z
public final fun getDumpHeapWhenDebugging ()Z
public final fun getEventListeners ()Ljava/util/List;
public final fun getHeapDumper ()Lleakcanary/HeapDumper;
public final fun getLeakingObjectFinder ()Lshark/LeakingObjectFinder;
public final fun getMaxStoredHeapDumps ()I
public final fun getMetadataExtractor ()Lshark/MetadataExtractor;
public final fun getObjectInspectors ()Ljava/util/List;
public final fun getReferenceMatchers ()Ljava/util/List;
public final fun getRequestWriteExternalStoragePermission ()Z
public final fun getRetainedVisibleThreshold ()I
public final fun getShowNotifications ()Z
public fun hashCode ()I
public final fun newBuilder ()Lleakcanary/LeakCanary$Config$Builder;
public fun toString ()Ljava/lang/String;
}

public final class leakcanary/LeakCanary$Config$Builder {
public final fun build ()Lleakcanary/LeakCanary$Config;
public final fun computeRetainedHeapSize (Z)Lleakcanary/LeakCanary$Config$Builder;
public final fun dumpHeap (Z)Lleakcanary/LeakCanary$Config$Builder;
public final fun dumpHeapWhenDebugging (Z)Lleakcanary/LeakCanary$Config$Builder;
public final fun eventListeners (Ljava/util/List;)Lleakcanary/LeakCanary$Config$Builder;
public final fun heapDumper (Lleakcanary/HeapDumper;)Lleakcanary/LeakCanary$Config$Builder;
public final fun leakingObjectFinder (Lshark/LeakingObjectFinder;)Lleakcanary/LeakCanary$Config$Builder;
public final fun maxStoredHeapDumps (I)Lleakcanary/LeakCanary$Config$Builder;
public final fun metadataExtractor (Lshark/MetadataExtractor;)Lleakcanary/LeakCanary$Config$Builder;
public final fun objectInspectors (Ljava/util/List;)Lleakcanary/LeakCanary$Config$Builder;
public final fun referenceMatchers (Ljava/util/List;)Lleakcanary/LeakCanary$Config$Builder;
public final fun requestWriteExternalStoragePermission (Z)Lleakcanary/LeakCanary$Config$Builder;
public final fun retainedVisibleThreshold (I)Lleakcanary/LeakCanary$Config$Builder;
public final fun showNotifications (Z)Lleakcanary/LeakCanary$Config$Builder;
}

public final class leakcanary/LogcatEventListener : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/LogcatEventListener;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/NotificationEventListener : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/NotificationEventListener;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/RemoteWorkManagerHeapAnalyzer : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/RemoteWorkManagerHeapAnalyzer;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/ToastEventListener : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/ToastEventListener;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/TvEventListener : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/TvEventListener;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

public final class leakcanary/WorkManagerHeapAnalyzer : leakcanary/EventListener {
public static final field INSTANCE Lleakcanary/WorkManagerHeapAnalyzer;
public fun onEvent (Lleakcanary/EventListener$Event;)V
}

0 comments on commit 152152c

Please sign in to comment.