The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .editorconfig
├── .gitattributes
├── .github
    ├── CODE_OF_CONDUCT.md
    ├── CONTRIBUTING.md
    ├── ISSUE_TEMPLATE
    │   ├── 1-leak.md
    │   ├── 2-bug.md
    │   ├── 3-feature.md
    │   ├── 4-doc.md
    │   └── 5-sdk.md
    ├── SUPPORT.md
    ├── workflows-disabled
    │   └── greetings.yml
    └── workflows
    │   ├── main.yml
    │   └── stale.yaml
├── .gitignore
├── LICENSE.txt
├── README.md
├── build.gradle.kts
├── config
    ├── detekt-config.yml
    └── hooks
    │   └── pre-push
├── docs
    ├── assets
    │   ├── adaptative_icon.sketch
    │   ├── icon_1024.png
    │   ├── icon_512.png
    │   ├── kanary-200px.png
    │   ├── kanary-large.png
    │   ├── leakcanary_shirt.psd
    │   ├── repository-open-graph.png
    │   ├── screenshot.png
    │   ├── shark.psd
    │   ├── source_icon.png
    │   ├── sticker.png
    │   ├── vector_falling_canary.svg
    │   ├── vector_icon.afdesign
    │   └── vector_icon.svg
    ├── blog-articles.md
    ├── changelog.md
    ├── code_of_conduct.md
    ├── dev-env.md
    ├── faq.md
    ├── fundamentals-fixing-a-memory-leak.md
    ├── fundamentals-how-leakcanary-works.md
    ├── fundamentals.md
    ├── getting_started.md
    ├── how_to_help.md
    ├── images
    │   ├── analysis-done.png
    │   ├── android-tv-leaks.png
    │   ├── bugsnag-leak.png
    │   ├── bugsnag-list.png
    │   ├── building-leak-traces-notification.png
    │   ├── disable_dumping.png
    │   ├── dumping-toast.png
    │   ├── finding-retained-notification.png
    │   ├── heap-dump.png
    │   ├── launcher.png
    │   ├── leak-screen.png
    │   ├── library-leak.png
    │   ├── logo-2.0-200px.png
    │   ├── logo-2.0.png
    │   ├── logo.png
    │   ├── retained-notification.png
    │   ├── screenshot-2.0.png
    │   ├── shark.png
    │   └── signature.png
    ├── index.md
    ├── leakcanary-for-releases.md
    ├── recipes.md
    ├── recorded-presentations.md
    ├── releasing.md
    ├── requirements.txt
    ├── shark.md
    ├── snippets
    │   └── bugsnag-uploader.md
    ├── support.md
    ├── theme
    │   └── main.html
    ├── ui-tests.md
    ├── upgrading-to-leakcanary-2.0.md
    └── uploading.md
├── gradle.properties
├── gradle
    ├── libs.versions.toml
    └── wrapper
    │   ├── gradle-wrapper.jar
    │   └── gradle-wrapper.properties
├── gradlew
├── leakcanary
    ├── leakcanary-android-core
    │   ├── api
    │   │   └── leakcanary-android-core.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   ├── lint.xml
    │   └── src
    │   │   ├── androidTest
    │   │       ├── AndroidManifest.xml
    │   │       ├── assets
    │   │       │   └── leaks-v24.db
    │   │       └── java
    │   │       │   └── leakcanary
    │   │       │       ├── AndroidExtensionsTest.kt
    │   │       │       ├── DatabaseMigrationTest.kt
    │   │       │       ├── DatabaseRule.kt
    │   │       │       ├── LeakActivityTest.kt
    │   │       │       └── ManualInstallTest.kt
    │   │   ├── main
    │   │       ├── AndroidManifest.xml
    │   │       ├── ic_launcher-web.png
    │   │       ├── java
    │   │       │   └── leakcanary
    │   │       │   │   ├── BackgroundThreadHeapAnalyzer.kt
    │   │       │   │   ├── EventListener.kt
    │   │       │   │   ├── LazyForwardingEventListener.kt
    │   │       │   │   ├── LeakCanary.kt
    │   │       │   │   ├── LeakCanaryAndroidInternalUtils.kt
    │   │       │   │   ├── LogcatEventListener.kt
    │   │       │   │   ├── NotificationEventListener.kt
    │   │       │   │   ├── RemoteWorkManagerHeapAnalyzer.kt
    │   │       │   │   ├── ToastEventListener.kt
    │   │       │   │   ├── TvEventListener.kt
    │   │       │   │   ├── WorkManagerHeapAnalyzer.kt
    │   │       │   │   └── internal
    │   │       │   │       ├── AndroidDebugHeapAnalyzer.kt
    │   │       │   │       ├── DebuggerControl.kt
    │   │       │   │       ├── DisplayLeakAdapter.kt
    │   │       │   │       ├── DisplayLeakConnectorView.kt
    │   │       │   │       ├── HeapAnalyzerWorker.kt
    │   │       │   │       ├── HeapDumpControl.kt
    │   │       │   │       ├── HeapDumpTrigger.kt
    │   │       │   │       ├── InternalLeakCanary.kt
    │   │       │   │       ├── LazyImmediateFuture.kt
    │   │       │   │       ├── LeakCanaryFileProvider.kt
    │   │       │   │       ├── LeakCanarySingleThreadFactory.kt
    │   │       │   │       ├── LeakCanaryTextView.kt
    │   │       │   │       ├── LeakDirectoryProvider.kt
    │   │       │   │       ├── NotificationReceiver.kt
    │   │       │   │       ├── NotificationType.kt
    │   │       │   │       ├── Notifications.kt
    │   │       │   │       ├── OnRetainInstanceListener.kt
    │   │       │   │       ├── RemoteHeapAnalyzerWorker.kt
    │   │       │   │       ├── RequestPermissionActivity.kt
    │   │       │   │       ├── RowElementLayout.kt
    │   │       │   │       ├── SerializableIntent.kt
    │   │       │   │       ├── Serializables.kt
    │   │       │   │       ├── SquigglySpan.kt
    │   │       │   │       ├── SquigglySpanRenderer.kt
    │   │       │   │       ├── VisibilityTracker.kt
    │   │       │   │       ├── activity
    │   │       │   │           ├── LeakActivity.kt
    │   │       │   │           ├── LeakViews.kt
    │   │       │   │           ├── db
    │   │       │   │           │   ├── Cursors.kt
    │   │       │   │           │   ├── Db.kt
    │   │       │   │           │   ├── HeapAnalysisTable.kt
    │   │       │   │           │   ├── Io.kt
    │   │       │   │           │   ├── LeakTable.kt
    │   │       │   │           │   ├── LeakTraceTable.kt
    │   │       │   │           │   ├── LeaksDbHelper.kt
    │   │       │   │           │   └── ScopedLeaksDb.kt
    │   │       │   │           ├── screen
    │   │       │   │           │   ├── AboutScreen.kt
    │   │       │   │           │   ├── HeapAnalysisFailureScreen.kt
    │   │       │   │           │   ├── HeapDumpRenderer.kt
    │   │       │   │           │   ├── HeapDumpScreen.kt
    │   │       │   │           │   ├── HeapDumpsScreen.kt
    │   │       │   │           │   ├── HprofExplorerScreen.kt
    │   │       │   │           │   ├── LeakScreen.kt
    │   │       │   │           │   ├── LeakTraceWrapper.kt
    │   │       │   │           │   ├── LeaksScreen.kt
    │   │       │   │           │   └── RenderHeapDumpScreen.kt
    │   │       │   │           └── ui
    │   │       │   │           │   ├── SimpleListAdapter.kt
    │   │       │   │           │   ├── TimeFormatter.kt
    │   │       │   │           │   └── UiUtils.kt
    │   │       │   │       ├── friendly
    │   │       │   │           └── Friendly.kt
    │   │       │   │       ├── navigation
    │   │       │   │           ├── BackstackFrame.kt
    │   │       │   │           ├── NavigatingActivity.kt
    │   │       │   │           ├── Screen.kt
    │   │       │   │           └── Views.kt
    │   │       │   │       ├── tv
    │   │       │   │           ├── TvOnRetainInstanceListener.kt
    │   │       │   │           └── TvToast.kt
    │   │       │   │       └── utils
    │   │       │   │           ├── Size.kt
    │   │       │   │           └── Tuples.kt
    │   │       └── res
    │   │       │   ├── anim
    │   │       │       ├── leak_canary_enter_alpha.xml
    │   │       │       ├── leak_canary_enter_backward.xml
    │   │       │       ├── leak_canary_enter_forward.xml
    │   │       │       ├── leak_canary_exit_alpha.xml
    │   │       │       ├── leak_canary_exit_backward.xml
    │   │       │       └── leak_canary_exit_forward.xml
    │   │       │   ├── color
    │   │       │       ├── leak_canary_bottom_menu.xml
    │   │       │       └── leak_canary_count_text.xml
    │   │       │   ├── drawable-v21
    │   │       │       ├── leak_canary_gray_fill.xml
    │   │       │       ├── leak_canary_list_selector.xml
    │   │       │       ├── leak_canary_primary_button.xml
    │   │       │       ├── leak_canary_secondary_button.xml
    │   │       │       ├── leak_canary_tab_background.xml
    │   │       │       └── leak_canary_tab_selector_ripple.xml
    │   │       │   ├── drawable
    │   │       │       ├── leak_canary_count_background.xml
    │   │       │       ├── leak_canary_dump.xml
    │   │       │       ├── leak_canary_gray_fill.xml
    │   │       │       ├── leak_canary_icon.xml
    │   │       │       ├── leak_canary_icon_foreground.xml
    │   │       │       ├── leak_canary_icon_monochrome.xml
    │   │       │       ├── leak_canary_info.xml
    │   │       │       ├── leak_canary_info_rectangle.xml
    │   │       │       ├── leak_canary_leak.xml
    │   │       │       ├── leak_canary_list_selector.xml
    │   │       │       ├── leak_canary_primary_button.xml
    │   │       │       ├── leak_canary_secondary_button.xml
    │   │       │       ├── leak_canary_tab_background.xml
    │   │       │       ├── leak_canary_toast_background.xml
    │   │       │       └── leak_canary_tv_icon.xml
    │   │       │   ├── layout
    │   │       │       ├── leak_canary_about_screen.xml
    │   │       │       ├── leak_canary_heap_analysis_failure_screen.xml
    │   │       │       ├── leak_canary_heap_dump_leak_title.xml
    │   │       │       ├── leak_canary_heap_dump_toast.xml
    │   │       │       ├── leak_canary_heap_dumps_screen.xml
    │   │       │       ├── leak_canary_heap_render.xml
    │   │       │       ├── leak_canary_hprof_explorer.xml
    │   │       │       ├── leak_canary_leak_activity.xml
    │   │       │       ├── leak_canary_leak_chips.xml
    │   │       │       ├── leak_canary_leak_header.xml
    │   │       │       ├── leak_canary_leak_row.xml
    │   │       │       ├── leak_canary_leak_screen.xml
    │   │       │       ├── leak_canary_list.xml
    │   │       │       ├── leak_canary_ref_row.xml
    │   │       │       └── leak_canary_simple_row.xml
    │   │       │   ├── mipmap-anydpi-v26
    │   │       │       └── leak_canary_icon.xml
    │   │       │   ├── mipmap-hdpi
    │   │       │       └── leak_canary_icon.png
    │   │       │   ├── mipmap-mdpi
    │   │       │       └── leak_canary_icon.png
    │   │       │   ├── mipmap-xhdpi
    │   │       │       └── leak_canary_icon.png
    │   │       │   ├── mipmap-xxhdpi
    │   │       │       └── leak_canary_icon.png
    │   │       │   ├── mipmap-xxxhdpi
    │   │       │       └── leak_canary_icon.png
    │   │       │   ├── values-v21
    │   │       │       └── leak_canary_themes.xml
    │   │       │   ├── values
    │   │       │       ├── leak_canary_attrs.xml
    │   │       │       ├── leak_canary_bools.xml
    │   │       │       ├── leak_canary_colors.xml
    │   │       │       ├── leak_canary_dimens.xml
    │   │       │       ├── leak_canary_ids.xml
    │   │       │       ├── leak_canary_public.xml
    │   │       │       ├── leak_canary_strings.xml
    │   │       │       └── leak_canary_themes.xml
    │   │       │   └── xml
    │   │       │       └── leak_canary_file_paths.xml
    │   │   └── test
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── LeakCanaryConfigTest.kt
    │   │               └── internal
    │   │                   └── activity
    │   │                       └── screen
    │   │                           └── LeakTraceWrapperTest.kt
    ├── leakcanary-android-instrumentation
    │   ├── api
    │   │   └── leakcanary-android-instrumentation.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   ├── androidTest
    │   │       ├── AndroidManifest.xml
    │   │       ├── assets
    │   │       │   └── large-dump.hprof
    │   │       ├── java
    │   │       │   └── leakcanary
    │   │       │   │   ├── AndroidDetectLeaksAssertTest.kt
    │   │       │   │   ├── Benchmark.kt
    │   │       │   │   ├── DetectLeaksAfterTestSuccessTest.kt
    │   │       │   │   ├── IndexingTest.kt
    │   │       │   │   ├── LifecycleLeaksTest.kt
    │   │       │   │   ├── LifecycleTestUtils.kt
    │   │       │   │   ├── ObjectInspectorTest.kt
    │   │       │   │   ├── ProfiledTest.kt
    │   │       │   │   ├── Profiler.kt
    │   │       │   │   ├── SkipLeakDetectionTest.kt
    │   │       │   │   ├── TestActivity.kt
    │   │       │   │   ├── TestDescriptionHolderTest.kt
    │   │       │   │   └── TestUtils.kt
    │   │       └── res
    │   │       │   └── layout
    │   │       │       └── activity_test.xml
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── AndroidDetectLeaksAssert.kt
    │   │               ├── AndroidDetectLeaksInterceptor.kt
    │   │               ├── DetectLeaksAfterTestSuccess.kt
    │   │               ├── DetectLeaksAssert.kt
    │   │               ├── DetectLeaksInterceptor.kt
    │   │               ├── HeapAnalysisDecision.kt
    │   │               ├── HeapAnalysisReporter.kt
    │   │               ├── LeakAssertions.kt
    │   │               ├── NoLeakAssertionFailedError.kt
    │   │               ├── SkipLeakDetection.kt
    │   │               └── internal
    │   │                   ├── InstrumentationHeapAnalyzer.kt
    │   │                   ├── RetryingHeapAnalyzer.kt
    │   │                   └── friendly
    │   │                       └── Friendly.kt
    ├── leakcanary-android-process
    │   ├── api
    │   │   └── leakcanary-android-process.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── LeakCanaryProcess.kt
    │   │               └── internal
    │   │                   └── RemoteLeakCanaryWorkerService.kt
    ├── leakcanary-android-release
    │   ├── api
    │   │   └── leakcanary-android-release.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── BackgroundTrigger.kt
    │   │               ├── ConditionalInterceptor.kt
    │   │               ├── GoodAndroidVersionInterceptor.kt
    │   │               ├── HeapAnalysisClient.kt
    │   │               ├── HeapAnalysisConfig.kt
    │   │               ├── HeapAnalysisInterceptor.kt
    │   │               ├── HeapAnalysisJob.kt
    │   │               ├── JobContext.kt
    │   │               ├── MinimumDiskSpaceInterceptor.kt
    │   │               ├── MinimumElapsedSinceStartInterceptor.kt
    │   │               ├── MinimumMemoryInterceptor.kt
    │   │               ├── OncePerPeriodInterceptor.kt
    │   │               ├── ProcessInfo.kt
    │   │               ├── SaveResourceIdsInterceptor.kt
    │   │               ├── ScreenOffTrigger.kt
    │   │               └── internal
    │   │                   ├── BackgroundListener.kt
    │   │                   ├── RealHeapAnalysisJob.kt
    │   │                   └── friendly
    │   │                       └── Friendly.kt
    ├── leakcanary-android-startup
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       └── AndroidManifest.xml
    ├── leakcanary-android-test
    │   ├── api
    │   │   └── leakcanary-android-test.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   ├── androidTest
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │       │   └── leakcanary
    │   │       │       └── RepeatingAndroidInProcessScenarioTest.kt
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── RepeatingAndroidInProcessScenario.kt
    │   │               └── TargetContextHeapDumpDirectoryProvider.kt
    ├── leakcanary-android-uiautomator
    │   ├── api
    │   │   └── leakcanary-android-uiautomator.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── AndroidDeviceTempHeapDumpDirectoryProvider.kt
    │   │               ├── RepeatingUiAutomatorScenario.kt
    │   │               ├── UiAutomatorShellFileDeleter.kt
    │   │               └── UiAutomatorShellHeapDumper.kt
    ├── leakcanary-android-utils
    │   ├── api
    │   │   └── leakcanary-android-utils.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── AndroidDebugHeapDumper.kt
    │   │               ├── LogcatSharkLog.kt
    │   │               └── internal
    │   │                   ├── Handlers.kt
    │   │                   ├── Objects.kt
    │   │                   └── Timing.kt
    ├── leakcanary-android
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   ├── androidTest
    │   │       └── java
    │   │       │   └── leakcanary
    │   │       │       └── LeakActivityTest.kt
    │   │   └── main
    │   │       └── AndroidManifest.xml
    ├── leakcanary-app-aidl
    │   ├── api
    │   │   └── leakcanary-app-aidl.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       ├── aidl
    │   │           └── org
    │   │           │   └── leakcanary
    │   │           │       └── internal
    │   │           │           └── LeakUiApp.aidl
    │   │       └── java
    │   │           └── org
    │   │               └── leakcanary
    │   │                   └── internal
    │   │                       └── ParcelableHeapAnalysis.kt
    ├── leakcanary-app-service
    │   ├── api
    │   │   └── leakcanary-app-service.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── org
    │   │               └── leakcanary
    │   │                   └── internal
    │   │                       └── LeakUiAppClient.kt
    ├── leakcanary-app
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       ├── java
    │   │           └── org
    │   │           │   └── leakcanary
    │   │           │       ├── LeakCanaryApp.kt
    │   │           │       ├── MainActivity.kt
    │   │           │       ├── WhileSubscribedOrRetained.kt
    │   │           │       ├── data
    │   │           │           ├── DatabaseDispatchers.kt
    │   │           │           ├── DatabaseModule.kt
    │   │           │           └── HeapRepository.kt
    │   │           │       ├── screens
    │   │           │           ├── BackStackViewModel.kt
    │   │           │           ├── ClientAppAnalysesScreen.kt
    │   │           │           ├── ClientAppAnalysisScreen.kt
    │   │           │           ├── ClientAppsScreen.kt
    │   │           │           ├── Destination.kt
    │   │           │           ├── LeakScreen.kt
    │   │           │           ├── ScreenHost.kt
    │   │           │           ├── TreeMapScreen.kt
    │   │           │           └── TreemapLayout.kt
    │   │           │       ├── service
    │   │           │           └── LeakUiAppService.kt
    │   │           │       ├── ui
    │   │           │           └── theme
    │   │           │           │   ├── Color.kt
    │   │           │           │   ├── Theme.kt
    │   │           │           │   └── Type.kt
    │   │           │       └── util
    │   │           │           ├── CurrentActivityProvider.kt
    │   │           │           ├── Handlers.kt
    │   │           │           ├── LeakTraceWrapper.kt
    │   │           │           ├── Serializables.kt
    │   │           │           ├── Sharer.kt
    │   │           │           └── TimeFormatter.kt
    │   │       ├── res
    │   │           ├── drawable-v24
    │   │           │   └── ic_launcher_foreground.xml
    │   │           ├── drawable
    │   │           │   └── ic_launcher_background.xml
    │   │           ├── mipmap-anydpi-v26
    │   │           │   ├── ic_launcher.xml
    │   │           │   └── ic_launcher_round.xml
    │   │           ├── mipmap-hdpi
    │   │           │   ├── ic_launcher.webp
    │   │           │   └── ic_launcher_round.webp
    │   │           ├── mipmap-mdpi
    │   │           │   ├── ic_launcher.webp
    │   │           │   └── ic_launcher_round.webp
    │   │           ├── mipmap-xhdpi
    │   │           │   ├── ic_launcher.webp
    │   │           │   └── ic_launcher_round.webp
    │   │           ├── mipmap-xxhdpi
    │   │           │   ├── ic_launcher.webp
    │   │           │   └── ic_launcher_round.webp
    │   │           ├── mipmap-xxxhdpi
    │   │           │   ├── ic_launcher.webp
    │   │           │   └── ic_launcher_round.webp
    │   │           ├── values
    │   │           │   ├── colors.xml
    │   │           │   ├── strings.xml
    │   │           │   └── themes.xml
    │   │           └── xml
    │   │           │   ├── backup_rules.xml
    │   │           │   └── data_extraction_rules.xml
    │   │       └── sqldelight
    │   │           └── dev
    │   │               └── leakcanary
    │   │                   └── sqldelight
    │   │                       ├── App.sq
    │   │                       ├── HeapAnalysis.sq
    │   │                       ├── Leak.sq
    │   │                       └── LeakTrace.sq
    ├── leakcanary-core
    │   ├── api
    │   │   └── leakcanary-core.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   ├── main
    │   │       └── java
    │   │       │   └── leakcanary
    │   │       │       ├── DatetimeFormattedHeapDumpFileProvider.kt
    │   │       │       ├── DumpingRepeatingScenarioObjectGrowthDetector.kt
    │   │       │       ├── HeapDumpDirectoryProvider.kt
    │   │       │       ├── HeapDumpFileProvider.kt
    │   │       │       ├── HeapDumpStorageStrategy.kt
    │   │       │       ├── HeapDumper.kt
    │   │       │       └── ObjectGrowthWarmupHeapDumper.kt
    │   │   └── test
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── DumpingRepeatingScenarioObjectGrowthDetectorTest.kt
    │   │               └── ObjectGrowthWarmupHeapDumperTest.kt
    ├── leakcanary-deobfuscation-gradle-plugin
    │   ├── api
    │   │   └── leakcanary-deobfuscation-gradle-plugin.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   ├── main
    │   │       └── java
    │   │       │   └── com
    │   │       │       └── squareup
    │   │       │           └── leakcanary
    │   │       │               └── deobfuscation
    │   │       │                   ├── CopyObfuscationMappingFileTask.kt
    │   │       │                   ├── LeakCanaryDeobfuscationExtension.kt
    │   │       │                   └── LeakCanaryLeakDeobfuscationPlugin.kt
    │   │   └── test
    │   │       ├── java
    │   │           └── com
    │   │           │   └── squareup
    │   │           │       └── leakcanary
    │   │           │           └── deobfuscation
    │   │           │               ├── CopyObfuscationMappingFileTaskTest.kt
    │   │           │               └── LeakCanaryLeakDeobfuscationPluginTest.kt
    │   │       └── test-project
    │   │           └── src
    │   │               └── main
    │   │                   ├── AndroidManifest.xml
    │   │                   └── java
    │   │                       └── com
    │   │                           └── leakcanary
    │   │                               └── test
    │   │                                   └── TestProjectClass.java
    ├── leakcanary-gc
    │   ├── api
    │   │   └── leakcanary-gc.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── FinalizingInProcessGcTrigger.kt
    │   │               └── GcTrigger.kt
    ├── leakcanary-jvm-test
    │   ├── api
    │   │   └── leakcanary-jvm-test.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   ├── main
    │   │       └── java
    │   │       │   └── leakcanary
    │   │       │       ├── HotSpotHeapDumper.kt
    │   │       │       ├── RepeatingJvmInProcessScenario.kt
    │   │       │       └── RepositoryRootHeapDumpDirectoryProvider.kt
    │   │   └── test
    │   │       └── java
    │   │           └── leakcanary
    │   │               └── JvmLiveObjectGrowthDetectorTest.kt
    └── leakcanary-test-core
    │   ├── api
    │       └── leakcanary-test-core.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │       ├── main
    │           └── java
    │           │   └── leakcanary
    │           │       ├── TestDescriptionHolder.kt
    │           │       ├── TestHeapDumpFileProvider.kt
    │           │       └── TestNameProvider.kt
    │       └── test
    │           └── java
    │               └── leakcanary
    │                   └── TestNameProviderTest.kt
├── mkdocs.yml
├── object-watcher
    ├── object-watcher-android-androidx
    │   ├── api
    │   │   └── object-watcher-android-androidx.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               └── internal
    │   │                   ├── AndroidXFragmentDestroyWatcher.kt
    │   │                   └── ViewModelClearedWatcher.kt
    ├── object-watcher-android-core
    │   ├── api
    │   │   └── object-watcher-android-core.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   ├── main
    │   │       ├── AndroidManifest.xml
    │   │       ├── java
    │   │       │   └── leakcanary
    │   │       │   │   ├── ActivityWatcher.kt
    │   │       │   │   ├── AppWatcher.kt
    │   │       │   │   ├── FragmentAndViewModelWatcher.kt
    │   │       │   │   ├── InstallableWatcher.kt
    │   │       │   │   ├── RootViewWatcher.kt
    │   │       │   │   ├── ServiceWatcher.kt
    │   │       │   │   └── internal
    │   │       │   │       ├── AndroidOFragmentDestroyWatcher.kt
    │   │       │   │       ├── Applications.kt
    │   │       │   │       ├── LeakCanaryDelegate.kt
    │   │       │   │       └── friendly
    │   │       │   │           └── Friendly.kt
    │   │       └── res
    │   │       │   └── values
    │   │       │       ├── leak_canary_public.xml
    │   │       │       └── watcher_bools.xml
    │   │   └── test
    │   │       └── java
    │   │           └── leakcanary
    │   │               └── AppWatcherTest.kt
    ├── object-watcher-android-startup
    │   ├── api
    │   │   └── object-watcher-android-startup.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               └── AppWatcherStartupInitializer.kt
    ├── object-watcher-android
    │   ├── api
    │   │   └── object-watcher-android.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       ├── java
    │   │           └── leakcanary
    │   │           │   └── internal
    │   │           │       └── MainProcessAppWatcherInstaller.kt
    │   │       └── res
    │   │           └── values
    │   │               ├── leak_canary_public.xml
    │   │               └── watcher_bools.xml
    └── object-watcher
    │   ├── api
    │       └── object-watcher.api
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │       ├── main
    │           └── java
    │           │   └── leakcanary
    │           │       ├── Clock.kt
    │           │       ├── DefaultDelayDeletableObjectReporter.kt
    │           │       ├── DelayedDeletableObjectReporter.kt
    │           │       ├── DelayedExecutor.kt
    │           │       ├── DeletableObjectReporter.kt
    │           │       ├── KeyedWeakReference.kt
    │           │       ├── ObjectWatcher.kt
    │           │       ├── OnObjectRetainedListener.kt
    │           │       ├── ReachabilityWatcher.kt
    │           │       ├── ReferenceQueueRetainedObjectTracker.kt
    │           │       ├── RetainedObjectTracker.kt
    │           │       ├── TrackedObjectReachability.kt
    │           │       ├── TriggeredDeletableObjectReporter.kt
    │           │       └── UptimeClock.kt
    │       └── test
    │           └── java
    │               └── leakcanary
    │                   └── ReferenceQueueRetainedObjectTrackerTest.kt
├── plumber
    ├── plumber-android-core
    │   ├── api
    │   │   └── plumber-android-core.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               ├── AndroidLeakFixes.kt
    │   │               ├── FixedWindowCallback.java
    │   │               ├── ViewLocationHolderLeakFix.kt
    │   │               └── internal
    │   │                   ├── FragmentExtensions.kt
    │   │                   ├── ReferenceCleaner.kt
    │   │                   └── friendly
    │   │                       └── Friendly.kt
    ├── plumber-android-startup
    │   ├── api
    │   │   └── plumber-android-startup.api
    │   ├── build.gradle.kts
    │   ├── gradle.properties
    │   └── src
    │   │   └── main
    │   │       ├── AndroidManifest.xml
    │   │       └── java
    │   │           └── leakcanary
    │   │               └── PlumberStartupInitializer.kt
    └── plumber-android
    │   ├── api
    │       └── plumber-android.api
    │   ├── build.gradle.kts
    │   ├── consumer-proguard-rules.pro
    │   ├── detekt-baseline.xml
    │   ├── gradle.properties
    │   └── src
    │       └── main
    │           ├── AndroidManifest.xml
    │           ├── java
    │               └── leakcanary
    │               │   └── internal
    │               │       └── PlumberInstaller.kt
    │           └── res
    │               └── values
    │                   ├── plumber_bools.xml
    │                   └── plumber_public.xml
├── samples
    └── leakcanary-android-sample
    │   ├── build.gradle.kts
    │   ├── detekt-baseline.xml
    │   └── src
    │       ├── androidTest
    │           ├── AndroidManifest.xml
    │           └── java
    │           │   └── leakcanary
    │           │       └── tests
    │           │           └── TuPeuxPasTest.kt
    │       ├── debug
    │           ├── AndroidManifest.xml
    │           └── java
    │           │   └── com
    │           │       └── example
    │           │           └── leakcanary
    │           │               ├── DebugExampleApplication.kt
    │           │               └── ExampleSetup.kt
    │       ├── main
    │           ├── AndroidManifest.xml
    │           ├── java
    │           │   └── com
    │           │   │   └── example
    │           │   │       └── leakcanary
    │           │   │           ├── ExampleApplication.kt
    │           │   │           ├── LeakingService.kt
    │           │   │           ├── LeakingSingleton.kt
    │           │   │           ├── LeakingThread.kt
    │           │   │           └── MainActivity.kt
    │           └── res
    │           │   ├── drawable
    │           │       └── leak_canary_sample_icon.png
    │           │   ├── layout
    │           │       └── main_activity.xml
    │           │   ├── mipmap-hdpi
    │           │       └── ic_launcher.png
    │           │   ├── mipmap-mdpi
    │           │       └── ic_launcher.png
    │           │   ├── mipmap-xhdpi
    │           │       └── ic_launcher.png
    │           │   ├── mipmap-xxhdpi
    │           │       └── ic_launcher.png
    │           │   ├── mipmap-xxxhdpi
    │           │       └── ic_launcher.png
    │           │   └── values
    │           │       └── strings.xml
    │       └── release
    │           ├── AndroidManifest.xml
    │           └── java
    │               └── com
    │                   └── example
    │                       └── leakcanary
    │                           └── ReleaseExampleApplication.kt
├── settings.gradle
├── shark-cli.sh
└── shark
    ├── shark-android
        ├── api
        │   └── shark-android.api
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        ├── gradle.properties
        └── src
        │   ├── main
        │       ├── java
        │       │   └── shark
        │       │   │   ├── AndroidBuildMirror.kt
        │       │   │   ├── AndroidExtensions.kt
        │       │   │   ├── AndroidMetadataExtractor.kt
        │       │   │   ├── AndroidObjectGrowthDetector.kt
        │       │   │   ├── AndroidObjectGrowthReferenceMatchers.kt
        │       │   │   ├── AndroidObjectInspectors.kt
        │       │   │   ├── AndroidReferenceMatchers.kt
        │       │   │   ├── AndroidResourceIdNames.kt
        │       │   │   ├── AndroidServices.kt
        │       │   │   └── internal
        │       │   │       └── friendly
        │       │   │           └── Friendly.kt
        │       └── resources
        │       │   └── META-INF
        │       │       └── proguard
        │       │           └── shark.pro
        │   └── test
        │       ├── java
        │           └── shark
        │           │   ├── AndroidObjectInspectorsTest.kt
        │           │   ├── AndroidReferenceMatcher_XIAMI__RESOURCES_IMPL_Test.kt
        │           │   ├── AndroidResourceIdNamesTest.kt
        │           │   ├── HprofIOPerfTest.kt
        │           │   ├── HprofRetainedHeapPerfTest.kt
        │           │   ├── LegacyHprofTest.kt
        │           │   ├── LruCacheTuning.kt
        │           │   ├── MetricsDualSourceProvider.kt
        │           │   ├── Resources.kt
        │           │   └── StringPathFinderOptimTest.kt
        │       └── resources
        │           ├── compose_leak.hprof
        │           ├── gc_root_in_non_primary_heap.hprof
        │           ├── gcroot_unknown_object.hprof
        │           ├── leak_asynctask_m.hprof
        │           ├── leak_asynctask_o.hprof
        │           ├── leak_asynctask_pre_m.hprof
        │           └── unloaded_classes-stripped.hprof
    ├── shark-cli
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        ├── gradle.properties
        └── src
        │   └── main
        │       └── java
        │           └── shark
        │               ├── AnalyzeCommand.kt
        │               ├── DeobfuscateHprofCommand.kt
        │               ├── DumpProcessCommand.kt
        │               ├── HeapGrowthCommand.kt
        │               ├── InteractiveCommand.kt
        │               ├── Main.kt
        │               ├── Neo4JCommand.kt
        │               ├── SharkCliCommand.kt
        │               └── StripHprofCommand.kt
    ├── shark-graph
        ├── api
        │   └── shark-graph.api
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        ├── gradle.properties
        └── src
        │   ├── main
        │       └── java
        │       │   └── shark
        │       │       ├── CloseableHeapGraph.kt
        │       │       ├── GraphContext.kt
        │       │       ├── HeapField.kt
        │       │       ├── HeapGraph.kt
        │       │       ├── HeapObject.kt
        │       │       ├── HeapValue.kt
        │       │       ├── HprofHeapGraph.kt
        │       │       ├── HprofIndex.kt
        │       │       └── internal
        │       │           ├── ByteSubArray.kt
        │       │           ├── ClassFieldsReader.kt
        │       │           ├── FieldValuesReader.kt
        │       │           ├── HprofInMemoryIndex.kt
        │       │           ├── IndexedObject.kt
        │       │           ├── LruCache.kt
        │       │           ├── SortedBytesMap.kt
        │       │           ├── UnsortedByteEntries.kt
        │       │           ├── aosp
        │       │               ├── ByteArrayComparator.kt
        │       │               └── ByteArrayTimSort.kt
        │       │           └── hppc
        │       │               ├── HPPC.kt
        │       │               ├── LongLongScatterMap.kt
        │       │               ├── LongObjectScatterMap.kt
        │       │               ├── LongScatterSet.kt
        │       │               └── Tuples.kt
        │   └── test
        │       └── java
        │           └── shark
        │               ├── ByteArrayTimSortTest.kt
        │               ├── HprofDeobfuscatorTest.kt
        │               ├── HprofHeapGraphEdgeCasesTest.kt
        │               ├── HprofIndexParsingTest.kt
        │               ├── HprofPrimitiveArrayStripperTest.kt
        │               ├── HprofWriterTest.kt
        │               ├── JvmHprofParsingTest.kt
        │               ├── LongScatterSetAssertion.kt
        │               ├── LongScatterSetTest.kt
        │               └── SortedBytesMapTest.kt
    ├── shark-hprof-test
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        └── src
        │   └── main
        │       └── kotlin
        │           └── shark
        │               ├── HprofWriterHelper.kt
        │               └── ProguardMappingHelper.kt
    ├── shark-hprof
        ├── api
        │   └── shark-hprof.api
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        ├── gradle.properties
        └── src
        │   ├── main
        │       └── java
        │       │   └── shark
        │       │       ├── ByteArraySourceProvider.kt
        │       │       ├── ConstantMemoryMetricsDualSourceProvider.kt
        │       │       ├── DualSourceProvider.kt
        │       │       ├── FileSourceProvider.kt
        │       │       ├── GcRoot.kt
        │       │       ├── HprofDeobfuscator.kt
        │       │       ├── HprofHeader.kt
        │       │       ├── HprofPrimitiveArrayStripper.kt
        │       │       ├── HprofRecord.kt
        │       │       ├── HprofRecordReader.kt
        │       │       ├── HprofRecordTag.kt
        │       │       ├── HprofVersion.kt
        │       │       ├── HprofWriter.kt
        │       │       ├── OnHprofRecordListener.kt
        │       │       ├── OnHprofRecordTagListener.kt
        │       │       ├── PrimitiveType.kt
        │       │       ├── ProguardMapping.kt
        │       │       ├── ProguardMappingReader.kt
        │       │       ├── RandomAccessHprofReader.kt
        │       │       ├── RandomAccessSource.kt
        │       │       ├── RandomAccessSourceProvider.kt
        │       │       ├── StreamingHprofReader.kt
        │       │       ├── StreamingRecordReaderAdapter.kt
        │       │       ├── StreamingSourceProvider.kt
        │       │       ├── ThrowingCancelableFileSourceProvider.kt
        │       │       └── ValueHolder.kt
        │   └── test
        │       └── java
        │           └── shark
        │               ├── HprofReaderPrimitiveArrayTest.kt
        │               └── ProguardMappingTest.kt
    ├── shark-log
        ├── api
        │   └── shark-log.api
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        ├── gradle.properties
        └── src
        │   ├── main
        │       └── java
        │       │   └── shark
        │       │       └── SharkLog.kt
        │   └── test
        │       └── java
        │           └── shark
        │               └── SharkLogTest.kt
    ├── shark-test
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        └── src
        │   └── main
        │       └── kotlin
        │           └── shark
        │               ├── HeapDumpRule.kt
        │               └── JvmTestHeapDumper.kt
    └── shark
        ├── api
            └── shark.api
        ├── build.gradle.kts
        ├── detekt-baseline.xml
        ├── gradle.properties
        └── src
            ├── main
                └── java
                │   └── shark
                │       ├── ActualMatchingReferenceReaderFactory.kt
                │       ├── AndroidNativeSizeMapper.kt
                │       ├── AndroidObjectSizeCalculator.kt
                │       ├── AndroidReferenceReaderFactory.kt
                │       ├── AndroidReferenceReaders.kt
                │       ├── ApacheHarmonyInstanceRefReaders.kt
                │       ├── AppSingletonInspector.kt
                │       ├── ByteSize.kt
                │       ├── ChainingInstanceReferenceReader.kt
                │       ├── ClassReferenceReader.kt
                │       ├── DelegatingObjectReferenceReader.kt
                │       ├── DominatorTree.kt
                │       ├── Dominators.kt
                │       ├── FieldInstanceReferenceReader.kt
                │       ├── FilteringLeakingObjectFinder.kt
                │       ├── FlatteningPartitionedInstanceReferenceReader.kt
                │       ├── GcRootProvider.kt
                │       ├── GcRootReference.kt
                │       ├── HeapAnalysis.kt
                │       ├── HeapAnalysisException.kt
                │       ├── HeapAnalyzer.kt
                │       ├── HeapTraversal.kt
                │       ├── JavaLocalReferenceReader.kt
                │       ├── JdkReferenceMatchers.kt
                │       ├── JvmObjectGrowthDetector.kt
                │       ├── JvmObjectGrowthReferenceMatchers.kt
                │       ├── KeyedWeakReferenceFinder.kt
                │       ├── LeakNodeStatus.kt
                │       ├── LeakTrace.kt
                │       ├── LeakTraceObject.kt
                │       ├── LeakTraceReference.kt
                │       ├── LeakTracer.kt
                │       ├── LeakingObjectFinder.kt
                │       ├── LeaksAndUnreachableObjects.kt
                │       ├── MatchingGcRootProvider.kt
                │       ├── MetadataExtractor.kt
                │       ├── ObjectArrayReferenceReader.kt
                │       ├── ObjectDominators.kt
                │       ├── ObjectGrowthDetector.kt
                │       ├── ObjectInspector.kt
                │       ├── ObjectInspectors.kt
                │       ├── ObjectReporter.kt
                │       ├── OnAnalysisProgressListener.kt
                │       ├── OpenJdkInstanceRefReaders.kt
                │       ├── OpenJdkReferenceReaderFactory.kt
                │       ├── PathFindingResults.kt
                │       ├── PrioritizingShortestPathFinder.kt
                │       ├── RealLeakTracerFactory.kt
                │       ├── Reference.kt
                │       ├── ReferenceLocationType.kt
                │       ├── ReferenceMatcher.kt
                │       ├── ReferencePattern.kt
                │       ├── ReferenceReader.kt
                │       ├── RepeatingScenarioObjectGrowthDetector.kt
                │       ├── Retained.kt
                │       ├── ShortestPathFinder.kt
                │       ├── ShortestPathObjectNode.kt
                │       ├── VirtualizingMatchingReferenceReaderFactory.kt
                │       └── internal
                │           ├── ByteStringCompat.java
                │           ├── FieldIdReader.kt
                │           ├── IntIntPairUtils.kt
                │           ├── InternalSharedExpanderHelpers.kt
                │           ├── InternalSharkCollectionsHelper.kt
                │           ├── JavaFrames.kt
                │           ├── KeyedWeakReferenceMirror.kt
                │           ├── ReferencePathNode.kt
                │           ├── ShallowSizeCalculator.kt
                │           ├── Strings.kt
                │           └── ThreadObjects.kt
            └── test
                ├── java
                    └── shark
                    │   ├── FlatteningPartitionedInstanceReferenceReaderTest.kt
                    │   ├── HeapAnalysisStringRenderingTest.kt
                    │   ├── HeapAnalyzerTest.kt
                    │   ├── HeapDumps.kt
                    │   ├── HprofHeapGraphTest.kt
                    │   ├── LabelerTest.kt
                    │   ├── LeakStatusTest.kt
                    │   ├── LeakTraceRenderingTest.kt
                    │   ├── MetadataExtractorTest.kt
                    │   ├── ObjectGrowthDetectorTest.kt
                    │   ├── OpenJdkInstanceRefReadersTest.kt
                    │   ├── ReferenceMatcherTest.kt
                    │   ├── RetainedSizeTest.kt
                    │   ├── TestUtil.kt
                    │   ├── UnreachableObjectRenderingTest.kt
                    │   └── internal
                    │       ├── AndroidReferenceReadersHprofTest.kt
                    │       ├── DominatorTreeTest.kt
                    │       └── ShallowSizeCalculatorTest.kt
                └── resources
                    ├── hashmap_api_25.hprof
                    └── safe_iterable_map.hprof


/.editorconfig:
--------------------------------------------------------------------------------
 1 | root = true
 2 | 
 3 | [*]
 4 | indent_size = 2
 5 | charset = utf-8
 6 | trim_trailing_whitespace = true
 7 | insert_final_newline = true
 8 | 
 9 | [*.{kt,kts}]
10 | kotlin_imports_layout=ascii
11 | 


--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 | 
3 | *.bat text eol=crlf
4 | *.jar binary
5 | 


--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | See https://square.github.io/leakcanary/code_of_conduct


--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | See https://square.github.io/leakcanary/how_to_help/


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/1-leak.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: "\U0001F424Leak in your app"
 3 | about: Use Stack Overflow instead
 4 | title: "\U0001F649 [This issue will be immediately closed]"
 5 | labels: 'Close immediately'
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | 🛑 𝙎𝙏𝙊𝙋
11 | 
12 | This issue tracker is not for help with memory leaks detected by LeakCanary in your own app.
13 | 
14 | To fix a leak: 
15 | 
16 | * First, learn the fundamentals: https://square.github.io/leakcanary/fundamentals/
17 | * Then, create a Stack Overflow question: https://stackoverflow.com/questions/tagged/leakcanary
18 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/2-bug.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: "\U0001F41BBug report"
 3 | about: 'Build errors, bugs and runtime crashes in version 2.0'
 4 | title: ''
 5 | labels: 'type: bug'
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | ### Description
11 | 
12 | [Description of the issue]
13 | 
14 | ### Steps to Reproduce
15 | 
16 | [Provide a sample project, a .hprof file or a failing test]
17 | 
18 | 1. [First Step]
19 | 2. [Second Step]
20 | 3. [and so on...]
21 | 
22 | **Expected behavior:** [What you expect to happen]
23 | 
24 | ### Version Information
25 | 
26 | * LeakCanary version:
27 | * Android OS version:
28 | * Gradle version:
29 | 
30 | ### Additional Information
31 | 
32 | Any additional information, configuration or data that might be necessary to reproduce the issue.
33 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/3-feature.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: "\U0001F64FFeature request"
 3 | about: Suggest an idea for LeakCanary
 4 | title: ''
 5 | labels: 'type: enhancement'
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | ### Problem description
11 | 
12 | ### Potential solutions
13 | 
14 | ### Additional information
15 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/4-doc.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: "\U0001F4DADocumentation request"
 3 | about: Point out what's confusing or missing
 4 | title: ''
 5 | labels: 'type: documentation'
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | 
11 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/5-sdk.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: "\U0001F916Leak in Android SDK / support library"
 3 | about: Help LeakCanary identify known leaks
 4 | title: ''
 5 | labels: 'type: leak'
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | Read this first: https://square.github.io/leakcanary/faq/#can-a-leak-be-caused-by-the-android-sdk
11 | 
12 | ### LeakTrace information
13 | 
14 | ```
15 | {REPLACE THIS LINE WITH THE OUTPUT FROM LEAKCANARY}
16 | ```
17 | 


--------------------------------------------------------------------------------
/.github/SUPPORT.md:
--------------------------------------------------------------------------------
1 | See https://square.github.io/leakcanary/support


--------------------------------------------------------------------------------
/.github/workflows-disabled/greetings.yml:
--------------------------------------------------------------------------------
 1 | name: Greetings
 2 | 
 3 | on: [pull_request, issues]
 4 | 
 5 | jobs:
 6 |   greeting:
 7 |     runs-on: ubuntu-latest
 8 |     steps:
 9 |     - uses: actions/first-interaction@v1
10 |       with:
11 |         repo-token: ${{ secrets.GITHUB_TOKEN }}
12 |         issue-message: '🙏Thank you for opening an issue! LeakCanary is maintained by [volunteers](https://github.com/square/leakcanary/graphs/contributors) from the community. Please be kind and remember that LeakCanary isn''t anyone''s main job 😘.'
13 | 


--------------------------------------------------------------------------------
/.github/workflows/stale.yaml:
--------------------------------------------------------------------------------
 1 | name: Mark stale issues
 2 | on:
 3 |   schedule:
 4 |     - cron: "30 1 * * *"
 5 | 
 6 | jobs:
 7 |   stale:
 8 |     runs-on: ubuntu-latest
 9 |     permissions:
10 |       issues: write
11 |     steps:
12 |       - uses: actions/stale@v5
13 |         with:
14 |           repo-token: ${{ secrets.GITHUB_TOKEN }}
15 |           days-before-stale: 30
16 |           days-before-close: 7
17 |           stale-issue-message: 'This issue is not actionable without the required information. Please comment or this will be closed in 7 days.'
18 |           close-issue-message: 'This issue was closed because it did not provide enough information to make it actionable.'
19 |           stale-issue-label: stale
20 |           stale-pr-label: stale
21 |           any-of-labels: 'status: needs more info, status: needs heap dump'
22 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | # Gradle
 2 | .gradle
 3 | gradlew.bat
 4 | build
 5 | local.properties
 6 | reports
 7 | 
 8 | # Maven
 9 | target
10 | pom.xml.*
11 | release.properties
12 | gen-external-apklibs
13 | 
14 | # Eclipse
15 | .classpath
16 | .project
17 | .settings
18 | eclipsebin
19 | 
20 | # IntelliJ IDEA
21 | .idea
22 | *.iml
23 | *.ipl
24 | *.iws
25 | classes/
26 | idea-classes/
27 | coverage-error.log
28 | 
29 | # Android
30 | gen
31 | bin
32 | project.properties
33 | out
34 | 
35 | # Finder
36 | .DS_Store
37 | 
38 | # Docs
39 | site
40 | 
41 | # Generated dokka
42 | docs/api
43 | 
44 | # Python virtual env
45 | venv


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # LeakCanary 🐤
 2 | 
 3 | A memory leak detection library for Android.
 4 | 
 5 | ### [square.github.io/leakcanary](https://square.github.io/leakcanary)
 6 | 
 7 | 🙏 If you like LeakCanary you can show support by starring ⭐ this repository.
 8 | 
 9 | ## License
10 | 
11 |     Copyright 2015 Square, Inc.
12 | 
13 |     Licensed under the Apache License, Version 2.0 (the "License");
14 |     you may not use this file except in compliance with the License.
15 |     You may obtain a copy of the License at
16 | 
17 |        http://www.apache.org/licenses/LICENSE-2.0
18 | 
19 |     Unless required by applicable law or agreed to in writing, software
20 |     distributed under the License is distributed on an "AS IS" BASIS,
21 |     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 |     See the License for the specific language governing permissions and
23 |     limitations under the License.
24 | 


--------------------------------------------------------------------------------
/config/hooks/pre-push:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | echo "Running static analysis..."
 4 | 
 5 | # Run static analysis tools
 6 | ./gradlew detekt --no-configuration-cache
 7 | 
 8 | status=$?
 9 | 
10 | if [ "$status" = 0 ] ; then
11 |     echo "Static analysis found no problems."
12 |     exit 0
13 | else
14 |     echo 1>&2 "Static analysis found violations! Fix them before pushing your code!"
15 |     echo "See generated reports above or in /<project_dir>/build/reports folder"
16 |     exit 1
17 | fi
18 | 


--------------------------------------------------------------------------------
/docs/assets/adaptative_icon.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/adaptative_icon.sketch


--------------------------------------------------------------------------------
/docs/assets/icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/icon_1024.png


--------------------------------------------------------------------------------
/docs/assets/icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/icon_512.png


--------------------------------------------------------------------------------
/docs/assets/kanary-200px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/kanary-200px.png


--------------------------------------------------------------------------------
/docs/assets/kanary-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/kanary-large.png


--------------------------------------------------------------------------------
/docs/assets/leakcanary_shirt.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/leakcanary_shirt.psd


--------------------------------------------------------------------------------
/docs/assets/repository-open-graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/repository-open-graph.png


--------------------------------------------------------------------------------
/docs/assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/screenshot.png


--------------------------------------------------------------------------------
/docs/assets/shark.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/shark.psd


--------------------------------------------------------------------------------
/docs/assets/source_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/source_icon.png


--------------------------------------------------------------------------------
/docs/assets/sticker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/sticker.png


--------------------------------------------------------------------------------
/docs/assets/vector_icon.afdesign:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/assets/vector_icon.afdesign


--------------------------------------------------------------------------------
/docs/blog-articles.md:
--------------------------------------------------------------------------------
1 | * [Memory Leaks in Android](https://www.raywenderlich.com/4690472-memory-leaks-in-android)
2 | * [Detect memory leaks in your instrumentation tests using LeakCanary](https://proandroiddev.com/detecting-memory-leaks-in-your-instrumentation-tests-using-leakcanary-1268e911d5ce)
3 | * [9 ways to avoid memory leaks in Android](https://android.jlelse.eu/9-ways-to-avoid-memory-leaks-in-android-b6d81648e35e)
4 | * [LeakCanary - Deobfuscation Feature Explained](https://www.polidea.com/blog/leakcanary-deobfuscation-feature-explained/)
5 | * [LeakCanary - An in-depth example of Android memory-leaks in MVP architecture](https://github.com/tricknology/MVPMemoryLeak/wiki)
6 | * [Detecting memory leaks in Android applications](https://dropbox.tech/mobile/detecting-memory-leaks-in-android-applications)
7 | 
8 | Your article should be here, please update this list! Any technical level welcome.
9 | 


--------------------------------------------------------------------------------
/docs/getting_started.md:
--------------------------------------------------------------------------------
 1 | # Getting started
 2 | 
 3 | To use LeakCanary, add the `leakcanary-android` dependency to your app's `build.gradle` file:
 4 | 
 5 | ```groovy
 6 | dependencies {
 7 |   // debugImplementation because LeakCanary should only run in debug builds.
 8 |   debugImplementation 'com.squareup.leakcanary:leakcanary-android:{{ leak_canary.release }}'
 9 | }
10 | ```
11 | 
12 | **That's it, there is no code change needed!**
13 | 
14 | Confirm that LeakCanary is running on startup by filtering on the `LeakCanary` tag in [Logcat](https://developer.android.com/studio/command-line/logcat):
15 | 
16 | ```
17 | D LeakCanary: LeakCanary is running and ready to detect leaks
18 | ```
19 | 
20 | !!! info
21 |     LeakCanary automatically detects leaks of the following objects:
22 |     
23 |     * destroyed `Activity` instances
24 |     * destroyed `Fragment` instances
25 |     * destroyed fragment `View` instances
26 |     * cleared `ViewModel` instances
27 |     * destroyed `Service` instance
28 | 
29 | What's next? Learn the [Fundamentals](fundamentals.md)!
30 | 


--------------------------------------------------------------------------------
/docs/how_to_help.md:
--------------------------------------------------------------------------------
 1 | # How to help
 2 | 
 3 | 🙏🙏🙏
 4 | 
 5 | LeakCanary is maintained by volunteers. Your help is welcome and will benefit the entire Android community!
 6 | 
 7 | Here's how you can help:
 8 | 
 9 | * Contribute to [Help Wanted](https://github.com/square/leakcanary/issues?q=is%3Aissue+is%3Aopen+label%3A%22status%3A+help+wanted%22) issues.
10 | * Answer [StackOverflow questions](http://stackoverflow.com/questions/tagged/leakcanary?sort=active).
11 | * Provide feedback on [pull requests](https://github.com/square/leakcanary/pulls).
12 | * Contribute code by forking the repository on GitHub and sending a pull request. Please read [Dev Environment for LeakCanary contributors](dev-env.md). When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible.
13 | 


--------------------------------------------------------------------------------
/docs/images/analysis-done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/analysis-done.png


--------------------------------------------------------------------------------
/docs/images/android-tv-leaks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/android-tv-leaks.png


--------------------------------------------------------------------------------
/docs/images/bugsnag-leak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/bugsnag-leak.png


--------------------------------------------------------------------------------
/docs/images/bugsnag-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/bugsnag-list.png


--------------------------------------------------------------------------------
/docs/images/building-leak-traces-notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/building-leak-traces-notification.png


--------------------------------------------------------------------------------
/docs/images/disable_dumping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/disable_dumping.png


--------------------------------------------------------------------------------
/docs/images/dumping-toast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/dumping-toast.png


--------------------------------------------------------------------------------
/docs/images/finding-retained-notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/finding-retained-notification.png


--------------------------------------------------------------------------------
/docs/images/heap-dump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/heap-dump.png


--------------------------------------------------------------------------------
/docs/images/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/launcher.png


--------------------------------------------------------------------------------
/docs/images/leak-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/leak-screen.png


--------------------------------------------------------------------------------
/docs/images/library-leak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/library-leak.png


--------------------------------------------------------------------------------
/docs/images/logo-2.0-200px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/logo-2.0-200px.png


--------------------------------------------------------------------------------
/docs/images/logo-2.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/logo-2.0.png


--------------------------------------------------------------------------------
/docs/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/logo.png


--------------------------------------------------------------------------------
/docs/images/retained-notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/retained-notification.png


--------------------------------------------------------------------------------
/docs/images/screenshot-2.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/screenshot-2.0.png


--------------------------------------------------------------------------------
/docs/images/shark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/shark.png


--------------------------------------------------------------------------------
/docs/images/signature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/docs/images/signature.png


--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
 1 | # LeakCanary 🐤
 2 | 
 3 | LeakCanary is a memory leak detection library for Android.
 4 | 
 5 | <p align="center">
 6 | <img src="images/screenshot-2.0.png" />
 7 | </p>
 8 | 
 9 | LeakCanary's knowledge of the internals of the Android Framework gives it a unique ability to narrow
10 | down the cause of each leak, helping developers dramatically reduce jank, `Application Not Responding`
11 | freezes and `OutOfMemoryError` crashes.
12 | 
13 | [Get started!](getting_started.md)
14 | 
15 | !!! quote
16 |     *“A small leak will sink a great ship.”* - Benjamin Franklin
17 | 
18 | 


--------------------------------------------------------------------------------
/docs/recorded-presentations.md:
--------------------------------------------------------------------------------
 1 | * [Live leak investigations](https://www.youtube.com/watch?v=Sx0k4ipqwBs), investigating leaks on Stack Overflow and fixes for AOSP leaks
 2 | * [Fixing leaks in Firefox](https://www.youtube.com/watch?v=kHHOhPPRytc)
 3 | * [Shark: Diving into the guts of LeakCanary's Hprof parser](https://www.droidcon.com/media-detail?video=362742252)
 4 | * [LeakCanary 2: Leaner, Better, Faster, Kotliner!](https://www.youtube.com/watch?v=LEX8dn4BLUw)
 5 | * [LeakCanary, then what? Nuking Nasty Memory Leaks](https://www.youtube.com/watch?v=fhE--eTEW84)
 6 | * [Memory Leak Hunt](https://www.youtube.com/watch?v=KwArTJHLq5g), a live investigation.
 7 | * [Installing LeakCanary](https://caster.io/lessons/installing-leakcanary) (LeakCanary 1.5)
 8 | * [How to use LeakCanary](https://www.youtube.com/watch?v=qtrZVPGdDkU)
 9 | 
10 | Your presentation should be here, please update this list! Any technical level welcome.
11 | 


--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | mkdocs==1.4.2
2 | mkdocs-material==9.1.3
3 | mkdocs-markdownextradata-plugin==0.2.5
4 | 


--------------------------------------------------------------------------------
/docs/support.md:
--------------------------------------------------------------------------------
 1 | # LeakCanary Support
 2 | 
 3 | If you're looking for help with LeakCanary:
 4 | 
 5 | * Learn the [Fundamentals](fundamentals.md)
 6 | * Try the [code recipes](recipes.md)
 7 | * Read the [FAQ](https://square.github.io/leakcanary/faq/)
 8 | * Watch [recorded presentations](recorded-presentations.md)
 9 | * Read [blog articles](blog-articles.md)
10 | * Ask a question [on StackOverflow](http://stackoverflow.com/questions/tagged/leakcanary?sort=active)
11 | 
12 | 
13 | 


--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
 1 | GROUP=com.squareup.leakcanary
 2 | VERSION_NAME=3.0-alpha-9
 3 | 
 4 | POM_DESCRIPTION=LeakCanary
 5 | POM_INCEPTION_YEAR=2015
 6 | POM_URL=https://github.com/square/leakcanary/
 7 | POM_SCM_URL=https://github.com/square/leakcanary/
 8 | POM_SCM_CONNECTION=scm:git:https://github.com/square/leakcanary.git
 9 | POM_SCM_DEV_CONNECTION=scm:git:git@github.com:square/leakcanary.git
10 | 
11 | POM_LICENSE_NAME=The Apache Software License, Version 2.0
12 | POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
13 | POM_LICENSE_DIST=repo
14 | 
15 | POM_DEVELOPER_ID=square
16 | POM_DEVELOPER_NAME=Square, Inc.
17 | POM_DEVELOPER_URL=https://github.com/square/
18 | SONATYPE_STAGING_PROFILE=com.squareup
19 | 
20 | android.useAndroidX=true
21 | #Gradle properties: https://docs.gradle.org/current/userguide/build_environment.html
22 | org.gradle.caching=true
23 | org.gradle.configureondemand=true
24 | org.gradle.jvmargs=-XX:+UseParallelGC -Dfile.encoding=UTF-8
25 | org.gradle.parallel=true
26 | android.defaults.buildfeatures.buildconfig=true
27 | android.nonTransitiveRClass=false
28 | android.nonFinalResIds=false
29 | 


--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/gradle/wrapper/gradle-wrapper.jar


--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Loaded via reflection & referenced by shark.AndroidReferenceMatchers.LEAK_CANARY_INTERNAL and shark.AndroidReferenceMatchers.LEAK_CANARY_HEAP_DUMPER
2 | -keep class leakcanary.internal.InternalLeakCanary { *; }
3 | # Marshmallow removed Notification.setLatestEventInfo()
4 | -dontwarn android.app.Notification
5 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-core
2 | POM_NAME=LeakCanary for Android - Core
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/lint.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <lint>
3 |   <issue id="SetTextI18n" severity="ignore" />
4 | </lint>
5 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2019 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest />
18 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/androidTest/assets/leaks-v24.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/androidTest/assets/leaks-v24.db


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/androidTest/java/leakcanary/DatabaseRule.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.database.sqlite.SQLiteDatabase
 4 | import androidx.test.platform.app.InstrumentationRegistry
 5 | import leakcanary.internal.activity.db.LeaksDbHelper
 6 | import leakcanary.internal.activity.db.ScopedLeaksDb
 7 | import org.junit.rules.TestRule
 8 | import org.junit.runner.Description
 9 | import org.junit.runners.model.Statement
10 | 
11 | class DatabaseRule(private val updateDb: (SQLiteDatabase) -> Unit = {}) : TestRule {
12 |   override fun apply(
13 |     base: Statement,
14 |     description: Description
15 |   ): Statement {
16 |     return object : Statement() {
17 |       override fun evaluate() {
18 |         val instrumentation = InstrumentationRegistry.getInstrumentation()
19 |         val context = instrumentation.targetContext
20 |         context.deleteDatabase(LeaksDbHelper.DATABASE_NAME)
21 |         ScopedLeaksDb.writableDatabase(context, updateDb)
22 |         base.evaluate()
23 |         context.deleteDatabase(LeaksDbHelper.DATABASE_NAME)
24 |       }
25 |     }
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/main/ic_launcher-web.png


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/BackgroundThreadHeapAnalyzer.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.os.Handler
 4 | import android.os.HandlerThread
 5 | import leakcanary.EventListener.Event
 6 | import leakcanary.EventListener.Event.HeapDump
 7 | import leakcanary.internal.AndroidDebugHeapAnalyzer
 8 | import leakcanary.internal.InternalLeakCanary
 9 | 
10 | /**
11 |  * Starts heap analysis on a background [HandlerThread] when receiving a [HeapDump] event.
12 |  */
13 | object BackgroundThreadHeapAnalyzer : EventListener {
14 | 
15 |   internal val heapAnalyzerThreadHandler by lazy {
16 |     val handlerThread = HandlerThread("HeapAnalyzer")
17 |     handlerThread.start()
18 |     Handler(handlerThread.looper)
19 |   }
20 | 
21 |   override fun onEvent(event: Event) {
22 |     if (event is HeapDump) {
23 |       heapAnalyzerThreadHandler.post {
24 |         val doneEvent = AndroidDebugHeapAnalyzer.runAnalysisBlocking(event) { event ->
25 |           InternalLeakCanary.sendEvent(event)
26 |         }
27 |         InternalLeakCanary.sendEvent(doneEvent)
28 |       }
29 |     }
30 |   }
31 | }
32 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/LazyForwardingEventListener.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import leakcanary.EventListener.Event
 4 | 
 5 | /**
 6 |  * Forwards events to the [EventListener] provided by lazyEventListener which
 7 |  * is evaluated lazily, when the first comes in.
 8 |  */
 9 | class LazyForwardingEventListener(
10 |   lazyEventListener: () -> EventListener
11 | ) : EventListener {
12 | 
13 |   private val eventListenerDelegate by lazy(lazyEventListener)
14 | 
15 |   override fun onEvent(event: Event) {
16 |     eventListenerDelegate.onEvent(event)
17 |   }
18 | }
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/DebuggerControl.kt:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * Copyright (C) 2015 Square, Inc.
 3 |  *
 4 |  * Licensed under the Apache License, Version 2.0 (the "License");
 5 |  * you may not use this file except in compliance with the License.
 6 |  * You may obtain a copy of the License at
 7 |  *
 8 |  *      http://www.apache.org/licenses/LICENSE-2.0
 9 |  *
10 |  * Unless required by applicable law or agreed to in writing, software
11 |  * distributed under the License is distributed on an "AS IS" BASIS,
12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |  * See the License for the specific language governing permissions and
14 |  * limitations under the License.
15 |  */
16 | package leakcanary.internal
17 | 
18 | import android.os.Debug
19 | 
20 | /**
21 |  * Gives the opportunity to skip checking if a reference is gone when the debugger is connected.
22 |  * An attached debugger might retain references and create false positives.
23 |  */
24 | internal object DebuggerControl {
25 | 
26 |   val isDebuggerAttached: Boolean
27 |     get() = Debug.isDebuggerConnected()
28 | }
29 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/LazyImmediateFuture.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import com.google.common.util.concurrent.ListenableFuture
 4 | import java.util.concurrent.Executor
 5 | import java.util.concurrent.TimeUnit
 6 | 
 7 | internal class LazyImmediateFuture<V>(
 8 |   valueProvider: () -> V
 9 | ) : ListenableFuture<V> {
10 | 
11 |   private val value by lazy {
12 |     valueProvider()
13 |   }
14 | 
15 |   override fun cancel(mayInterruptIfRunning: Boolean) = false
16 | 
17 |   override fun isCancelled() = false
18 | 
19 |   override fun isDone() = true
20 | 
21 |   override fun get() = value
22 | 
23 |   override fun get(
24 |     timeout: Long,
25 |     unit: TimeUnit?
26 |   ): V = value
27 | 
28 |   override fun addListener(
29 |     listener: Runnable,
30 |     executor: Executor
31 |   ) {
32 |     executor.execute(listener)
33 |   }
34 | }
35 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/NotificationType.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import com.squareup.leakcanary.core.R
 4 | 
 5 | internal enum class NotificationType(
 6 |   val nameResId: Int,
 7 |   val importance: Int
 8 | ) {
 9 |   LEAKCANARY_LOW(
10 |     R.string.leak_canary_notification_channel_low, IMPORTANCE_LOW
11 |   ),
12 |   LEAKCANARY_MAX(
13 |     R.string.leak_canary_notification_channel_result, IMPORTANCE_MAX
14 |   );
15 | }
16 | 
17 | private const val IMPORTANCE_LOW = 2
18 | private const val IMPORTANCE_MAX = 5


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/OnRetainInstanceListener.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | internal sealed class RetainInstanceEvent {
 4 |   object NoMoreObjects : RetainInstanceEvent()
 5 |   sealed class CountChanged : RetainInstanceEvent() {
 6 |     class BelowThreshold(val retainedCount: Int) : RetainInstanceEvent()
 7 |     class DumpingDisabled(val reason: String) : RetainInstanceEvent()
 8 |     object DumpHappenedRecently : RetainInstanceEvent()
 9 |   }
10 | }
11 | 
12 | /**
13 |  * Called by LeakCanary when the number of retained instances updates .
14 |  */
15 | internal fun interface OnRetainInstanceListener {
16 | 
17 |   /**
18 |    * Called when there's a change to the Retained Instances. See [RetainInstanceEvent] for
19 |    * possible events.
20 |    */
21 |   fun onEvent(event: RetainInstanceEvent)
22 | }
23 | 
24 | internal class DefaultOnRetainInstanceListener : OnRetainInstanceListener {
25 | 
26 |   override fun onEvent(event: RetainInstanceEvent) {}
27 | }
28 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/SerializableIntent.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import android.content.Intent
 4 | import java.io.Serializable
 5 | 
 6 | /**
 7 |  * Wraps an Intent to serialize it as its URI string.
 8 |  */
 9 | internal class SerializableIntent(intent: Intent) : Serializable {
10 | 
11 |   private val uri = intent.toUri(0)
12 | 
13 |   // Intent is not Serializable
14 |   @Transient
15 |   private var _intent: Intent? = intent
16 | 
17 |   val intent: Intent
18 |     get() = _intent.run {
19 |       this ?: Intent.parseUri(uri, 0)
20 |         .apply { _intent = this }
21 |     }
22 | }
23 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/Serializables.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import shark.SharkLog
 4 | import java.io.ByteArrayInputStream
 5 | import java.io.ByteArrayOutputStream
 6 | import java.io.ObjectInputStream
 7 | import java.io.ObjectOutputStream
 8 | import java.io.Serializable
 9 | 
10 | internal fun Serializable.toByteArray(): ByteArray {
11 |   val outputStream = ByteArrayOutputStream()
12 |   ObjectOutputStream(outputStream).writeObject(this)
13 |   return outputStream.toByteArray()
14 | }
15 | 
16 | internal object Serializables {
17 | 
18 |   inline fun <reified T> fromByteArray(byteArray: ByteArray): T? {
19 |     val inputStream = ByteArrayInputStream(byteArray)
20 |     return try {
21 |       ObjectInputStream(inputStream).readObject() as? T
22 |     } catch (ignored: Throwable) {
23 |       SharkLog.d(ignored) { "Could not deserialize bytes, ignoring" }
24 |       null
25 |     }
26 |   }
27 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/activity/ui/SimpleListAdapter.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal.activity.ui
 2 | 
 3 | import android.view.View
 4 | import android.view.ViewGroup
 5 | import android.widget.BaseAdapter
 6 | import leakcanary.internal.navigation.inflate
 7 | 
 8 | internal class SimpleListAdapter<T>(
 9 |   private val rowResId: Int,
10 |   private val items: List<T>,
11 |   private val bindView: SimpleListAdapter<T>.(View, Int) -> Unit
12 | ) : BaseAdapter() {
13 |   override fun getView(
14 |     position: Int,
15 |     convertView: View?,
16 |     parent: ViewGroup
17 |   ): View {
18 |     val view = convertView ?: parent.inflate(rowResId)
19 |     bindView(view, position)
20 |     return view
21 |   }
22 | 
23 |   override fun getItem(position: Int) = items[position]
24 | 
25 |   override fun getItemId(position: Int) = position.toLong()
26 | 
27 |   override fun getCount() = items.size
28 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/activity/ui/UiUtils.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal.activity.ui
 2 | 
 3 | import android.text.SpannableStringBuilder
 4 | import android.text.style.ClickableSpan
 5 | import android.text.style.URLSpan
 6 | import android.view.View
 7 | 
 8 | internal object UiUtils {
 9 | 
10 |   internal fun replaceUrlSpanWithAction(
11 |     title: SpannableStringBuilder,
12 |     urlAction: (String) -> (() -> Unit)?
13 |   ) {
14 |     val urlSpans = title.getSpans(0, title.length, URLSpan::class.java)
15 |     for (span in urlSpans) {
16 |       val action: (() -> Unit)? = urlAction(span.url)
17 |       if (action != null) {
18 |         val start = title.getSpanStart(span)
19 |         val end = title.getSpanEnd(span)
20 |         val flags = title.getSpanFlags(span)
21 |         title.removeSpan(span)
22 |         val newSpan = object : ClickableSpan() {
23 |           override fun onClick(widget: View) {
24 |             action()
25 |           }
26 |         }
27 |         title.setSpan(newSpan, start, end, flags)
28 |       }
29 |     }
30 |   }
31 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/friendly/Friendly.kt:
--------------------------------------------------------------------------------
 1 | @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "NOTHING_TO_INLINE")
 2 | @file:JvmName("leakcanary-android-core_Friendly")
 3 | 
 4 | package leakcanary.internal.friendly
 5 | 
 6 | internal inline val mainHandler
 7 |   get() = leakcanary.internal.mainHandler
 8 | 
 9 | internal inline fun checkMainThread() = leakcanary.internal.checkMainThread()
10 | 
11 | internal inline fun checkNotMainThread() = leakcanary.internal.checkNotMainThread()
12 | 
13 | internal inline fun <reified T : Any> noOpDelegate(): T = leakcanary.internal.noOpDelegate()
14 | 
15 | internal inline fun measureDurationMillis(block: () -> Unit) =
16 |   leakcanary.internal.measureDurationMillis(block)
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/navigation/Screen.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal.navigation
 2 | 
 3 | import android.view.View
 4 | import android.view.ViewGroup
 5 | import java.io.Serializable
 6 | 
 7 | /**
 8 |  * Replaces Fragments, MVP, MVC, MVVM, MVMVMVM and everything else in just one tiny class.
 9 |  * A screen is a location to go to, and it can build a view to display.
10 |  */
11 | internal abstract class Screen : Serializable {
12 | 
13 |   abstract fun createView(container: ViewGroup): View
14 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/utils/Size.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal.utils
 2 | 
 3 | import kotlin.math.ln
 4 | import kotlin.math.pow
 5 | 
 6 | // https://stackoverflow.com/a/3758880
 7 | internal fun humanReadableByteCount(
 8 |   bytes: Long,
 9 |   si: Boolean
10 | ): String {
11 |   val unit = if (si) 1000 else 1024
12 |   if (bytes < unit) return "$bytes B"
13 |   val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
14 |   val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
15 |   return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
16 | }
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/java/leakcanary/internal/utils/Tuples.kt:
--------------------------------------------------------------------------------
1 | package leakcanary.internal.utils
2 | 
3 | internal infix fun <A, B, C> Pair<A, B>.to(that: C): Triple<A, B, C> = Triple(first, second, that)
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/anim/leak_canary_enter_alpha.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <alpha
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:fromAlpha="0"
5 |     android:toAlpha="1"
6 |     android:duration="@android:integer/config_mediumAnimTime"/>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/anim/leak_canary_enter_backward.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <translate
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:fromXDelta="-100%" android:toXDelta="0%"
5 |     android:fromYDelta="0%" android:toYDelta="0%"
6 |     android:duration="@android:integer/config_mediumAnimTime"/>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/anim/leak_canary_enter_forward.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <translate
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:fromXDelta="100%" android:toXDelta="0%"
5 |     android:fromYDelta="0%" android:toYDelta="0%"
6 |     android:duration="@android:integer/config_mediumAnimTime"/>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/anim/leak_canary_exit_alpha.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <alpha
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:fromAlpha="1"
5 |     android:toAlpha="0"
6 |     android:duration="@android:integer/config_mediumAnimTime"/>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/anim/leak_canary_exit_backward.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <translate
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:fromXDelta="0%" android:toXDelta="100%"
5 |     android:fromYDelta="0%" android:toYDelta="0%"
6 |     android:duration="@android:integer/config_mediumAnimTime"/>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/anim/leak_canary_exit_forward.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <translate
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:fromXDelta="0%" android:toXDelta="-100%"
5 |     android:fromYDelta="0%" android:toYDelta="0%"
6 |     android:duration="@android:integer/config_mediumAnimTime"/>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/color/leak_canary_bottom_menu.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <item android:state_selected="false" android:color="@color/leak_canary_gray_darkest_40p" />
4 |   <item android:state_selected="true"  android:color="@color/leak_canary_gray_darkest" />
5 | </selector>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/color/leak_canary_count_text.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <item android:state_enabled="true" android:color="@color/leak_canary_gray_darkest" />
4 |   <item android:color="@color/leak_canary_yellow" />
5 | </selector>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable-v21/leak_canary_gray_fill.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <ripple xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:color="?android:attr/colorControlHighlight">
 4 |     <item android:id="@android:id/mask">
 5 |         <shape>
 6 |             <solid android:color="@color/leak_canary_gray" />
 7 |             <corners android:radius="20dp" />
 8 |         </shape>
 9 |     </item>
10 |     <item>
11 |         <shape>
12 |             <solid android:color="@color/leak_canary_gray" />
13 |             <corners android:radius="20dp" />
14 |         </shape>
15 |     </item>
16 | </ripple>
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable-v21/leak_canary_list_selector.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
 3 |     <item android:state_focused="true" android:state_pressed="false">
 4 |         <color android:color="?android:attr/colorControlHighlight" />
 5 |     </item>
 6 |     <item>
 7 |         <color android:color="@android:color/transparent" />
 8 |     </item>
 9 | </selector>
10 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable-v21/leak_canary_primary_button.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <ripple xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:color="@color/leak_canary_yellow_button_pressed">
 4 |   <item>
 5 |     <shape>
 6 |       <solid android:color="@color/leak_canary_yellow_button" />
 7 |       <corners android:radius="12dp" />
 8 |     </shape>
 9 |   </item>
10 |   <item android:id="@android:id/mask">
11 |     <shape>
12 |       <solid android:color="@color/leak_canary_yellow_button" />
13 |       <corners android:radius="12dp" />
14 |     </shape>
15 |   </item>
16 | </ripple>
17 | 
18 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable-v21/leak_canary_secondary_button.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <ripple xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:color="@color/leak_canary_gray_6f">
 4 |   <item>
 5 |     <shape>
 6 |       <solid android:color="@color/leak_canary_gray_3f" />
 7 |       <corners android:radius="12dp" />
 8 |     </shape>
 9 |   </item>
10 |   <item android:id="@android:id/mask">
11 |     <shape>
12 |       <solid android:color="@color/leak_canary_gray_3f" />
13 |       <corners android:radius="12dp" />
14 |     </shape>
15 |   </item>
16 | </ripple>
17 | 
18 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable-v21/leak_canary_tab_background.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <item android:drawable="@drawable/leak_canary_tab_selector_ripple" />
4 | </selector>
5 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable-v21/leak_canary_tab_selector_ripple.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <ripple
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     android:color="@color/leak_canary_gray_darkest_25p"
5 |     />
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_count_background.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
 3 |   <item android:state_enabled="true">
 4 |     <shape>
 5 |       <solid android:color="@color/leak_canary_count_new" />
 6 |       <corners android:radius="20dp" />
 7 |       <stroke android:width="2dp" android:color="@color/leak_canary_count_new_border" />
 8 |     </shape>
 9 |   </item>
10 |   <item>
11 |     <shape>
12 |       <solid android:color="@color/leak_canary_count_default" />
13 |       <corners android:radius="20dp" />
14 |     </shape>
15 |   </item>
16 | </selector>
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_dump.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |     android:width="24dp"
 3 |     android:height="23dp"
 4 |     android:viewportWidth="24"
 5 |     android:viewportHeight="23">
 6 |   <path
 7 |       android:pathData="M3.25,5H10.25"
 8 |       android:strokeWidth="2.5"
 9 |       android:fillColor="#00000000"
10 |       android:strokeColor="#000000"
11 |       android:strokeLineCap="round"/>
12 |   <path
13 |       android:pathData="M2.25,5.25h0.5v2.5h-0.5z"
14 |       android:strokeWidth="0.5"
15 |       android:fillColor="#000000"
16 |       android:strokeColor="#000000"/>
17 |   <path
18 |       android:pathData="M3,8C3,6.8954 3.8954,6 5,6H19C20.1046,6 21,6.8954 21,8V16C21,17.1046 20.1046,18 19,18H5C3.8954,18 3,17.1046 3,16V8Z"
19 |       android:strokeWidth="2"
20 |       android:fillColor="#00000000"
21 |       android:strokeColor="#000000"/>
22 | </vector>
23 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_gray_fill.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
 3 |     <item android:state_pressed="true">
 4 |         <shape>
 5 |             <solid android:color="@color/leak_canary_gray_3f" />
 6 |             <corners android:radius="20dp" />
 7 |         </shape>
 8 |     </item>
 9 |     <item>
10 |         <shape>
11 |             <solid android:color="@color/leak_canary_gray" />
12 |             <corners android:radius="20dp" />
13 |         </shape>
14 |     </item>
15 | </selector>
16 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_info.xml:
--------------------------------------------------------------------------------
1 | <vector android:height="24dp" android:tint="#151C1F"
2 |     android:viewportHeight="24.0" android:viewportWidth="24.0"
3 |     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4 |     <path android:fillColor="#FF000000" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
5 | </vector>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_info_rectangle.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android">
3 |     <stroke android:width="2dp" android:color="@color/leak_canary_class_name" />
4 |     <corners android:radius="6dp" />
5 | </shape>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_list_selector.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
 3 |     <item android:state_focused="true" android:state_pressed="false">
 4 |         <color android:color="@color/leak_canary_gray_3f" />
 5 |     </item>
 6 |     <item>
 7 |         <color android:color="@android:color/transparent" />
 8 |     </item>
 9 | </selector>
10 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_primary_button.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
 3 |   <item android:state_pressed="true">
 4 |     <shape>
 5 |       <solid android:color="@color/leak_canary_yellow_button_pressed" />
 6 |       <corners android:radius="12dp" />
 7 |     </shape>
 8 |   </item>
 9 |   <item>
10 |     <shape>
11 |       <solid android:color="@color/leak_canary_yellow_button" />
12 |       <corners android:radius="12dp" />
13 |     </shape>
14 |   </item>
15 | </selector>
16 | 
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_secondary_button.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
 3 | <item android:state_pressed="true">
 4 |     <shape>
 5 |         <solid android:color="@color/leak_canary_gray_6f" />
 6 |         <corners android:radius="12dp" />
 7 |     </shape>
 8 | </item>
 9 | <item>
10 |     <shape>
11 |         <solid android:color="@color/leak_canary_gray_3f" />
12 |         <corners android:radius="12dp" />
13 |     </shape>
14 | </item>
15 | </selector>
16 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_tab_background.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <item android:state_pressed="false" android:drawable="@android:color/transparent" />
4 |   <item android:drawable="@color/leak_canary_gray_darkest_25p" />
5 | </selector>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/drawable/leak_canary_toast_background.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <solid android:color="#cc000000"/>
4 |   <corners android:radius="16dp"/>
5 | </shape>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/layout/leak_canary_heap_analysis_failure_screen.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:layout_width="match_parent"
 4 |     android:layout_height="match_parent"
 5 |     >
 6 | 
 7 | 
 8 | <LinearLayout
 9 |     android:layout_width="match_parent"
10 |     android:layout_height="wrap_content"
11 |     android:orientation="vertical"
12 |     >
13 | 
14 |   <include layout="@layout/leak_canary_leak_header" />
15 | 
16 |   <TextView
17 |       android:id="@+id/leak_canary_stacktrace"
18 |       android:layout_width="match_parent"
19 |       android:layout_height="wrap_content"
20 |       android:layout_margin="20dp"
21 |       android:textSize="12sp"
22 |       android:fontFamily="monospace"
23 |       />
24 | </LinearLayout>
25 | 
26 | </ScrollView>
27 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/layout/leak_canary_heap_dump_leak_title.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <TextView xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:id="@+id/leak_canary_heap_dump_leaks"
 4 |     android:layout_width="match_parent"
 5 |     android:layout_height="wrap_content"
 6 |     android:paddingLeft="20dp"
 7 |     android:paddingTop="32dp"
 8 |     android:paddingBottom="24dp"
 9 |     android:textStyle="bold"
10 |     android:textSize="20sp"
11 |     android:textColor="@color/leak_canary_white"
12 |     />
13 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/layout/leak_canary_heap_render.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:layout_width="match_parent"
 4 |     android:layout_height="match_parent"
 5 |     >
 6 |   <ProgressBar
 7 |       android:id="@+id/leak_canary_loading"
 8 |       android:layout_width="wrap_content"
 9 |       android:layout_height="wrap_content"
10 |       android:layout_gravity="center"
11 |       android:indeterminate="true"
12 |       style="?android:attr/progressBarStyleLarge"
13 |       />
14 |   <ImageView
15 |       android:id="@+id/leak_canary_heap_rendering"
16 |       android:layout_width="wrap_content"
17 |       android:layout_height="wrap_content"
18 |       />
19 | 
20 | </FrameLayout>
21 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/layout/leak_canary_leak_header.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | 
 3 | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 4 |     android:layout_width="match_parent"
 5 |     android:layout_height="wrap_content"
 6 |     >
 7 |   <leakcanary.internal.LeakCanaryTextView
 8 |       android:id="@+id/leak_canary_header_text"
 9 |       android:layout_width="match_parent"
10 |       android:layout_height="wrap_content"
11 |       android:layout_marginStart="20dp"
12 |       android:layout_marginEnd="20dp"
13 |       android:background="@drawable/leak_canary_info_rectangle"
14 |       android:padding="16dp"
15 |       />
16 | </FrameLayout>
17 | 
18 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/layout/leak_canary_list.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:layout_width="match_parent"
 4 |     android:layout_height="match_parent"
 5 |     >
 6 |   <ListView
 7 |       android:id="@+id/leak_canary_list"
 8 |       android:layout_width="match_parent"
 9 |       android:layout_height="match_parent"
10 |       android:listSelector="@drawable/leak_canary_list_selector"
11 |       android:divider="@null"
12 |       android:dividerHeight="0dp"
13 |       android:requiresFadingEdge="vertical"
14 |       />
15 | </FrameLayout>
16 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/mipmap-anydpi-v26/leak_canary_icon.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <background android:drawable="@color/leak_canary_white"/>
4 |   <foreground android:drawable="@drawable/leak_canary_icon_foreground"/>
5 |   <monochrome android:drawable="@drawable/leak_canary_icon_monochrome" />
6 | </adaptive-icon>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/mipmap-hdpi/leak_canary_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/main/res/mipmap-hdpi/leak_canary_icon.png


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/mipmap-mdpi/leak_canary_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/main/res/mipmap-mdpi/leak_canary_icon.png


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/mipmap-xhdpi/leak_canary_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/main/res/mipmap-xhdpi/leak_canary_icon.png


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/mipmap-xxhdpi/leak_canary_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/main/res/mipmap-xxhdpi/leak_canary_icon.png


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/mipmap-xxxhdpi/leak_canary_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-core/src/main/res/mipmap-xxxhdpi/leak_canary_icon.png


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/values/leak_canary_attrs.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <resources>
18 |   <declare-styleable name="leak_canary_MoreDetailsView">
19 |     <attr name="leak_canary_plus_color" format="color" />
20 |   </declare-styleable>
21 | </resources>
22 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/values/leak_canary_bools.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <bool name="leak_canary_add_dynamic_shortcut">true</bool>
4 |   <bool name="leak_canary_add_launcher_icon">true</bool>
5 |   <bool name="leak_canary_allow_in_non_debuggable_build">false</bool>
6 | </resources>
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/main/res/xml/leak_canary_file_paths.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <paths>
3 |   <external-path name="downloads" path="Download/" />
4 |   <files-path name="leakcanary" path="leakcanary/" />
5 |   <cache-path name="leakcanary_cache" path="leakcanary/" />
6 | 
7 | </paths>
8 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-core/src/test/java/leakcanary/LeakCanaryConfigTest.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import org.assertj.core.api.Assertions.assertThat
 4 | import org.junit.Test
 5 | import kotlin.reflect.full.memberFunctions
 6 | import kotlin.reflect.full.memberProperties
 7 | 
 8 | class LeakCanaryConfigTest {
 9 | 
10 |   /**
11 |    * Validates that each field in [LeakCanary.Config] has a matching builder function
12 |    * in [LeakCanary.Config.Builder]
13 |    */
14 |   @Test fun `LeakCanary Config Builder matches LeakCanary Config`() {
15 |     assertThat(configProperties())
16 |       .containsExactlyInAnyOrderElementsOf(configBuilderFunctions())
17 |   }
18 | 
19 |   private fun configBuilderFunctions() = LeakCanary.Config.Builder::class.memberFunctions
20 |     .map { it.name }
21 |     .subtract(setOf("build", "equals", "hashCode", "toString"))
22 | 
23 |   private fun configProperties() = LeakCanary.Config::class.memberProperties
24 |     .map { it.name }
25 | }
26 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>MaximumLineLength:NoLeakAssertionFailedError.kt$NoLeakAssertionFailedError.Companion$ </ID>
 6 |     <ID>MultiLineIfElse:InstrumentationHeapAnalyzer.kt$InstrumentationHeapAnalyzer$result</ID>
 7 |     <ID>NoConsecutiveBlankLines:DetectLeaksAfterTestSuccess.kt$ </ID>
 8 |     <ID>NoConsecutiveBlankLines:LeakAssertions.kt$ </ID>
 9 |     <ID>NoConsecutiveBlankLines:SkipLeakDetection.kt$ </ID>
10 |     <ID>StringTemplate:AndroidDetectLeaksAssert.kt$AndroidDetectLeaksAssert${classSimpleName}</ID>
11 |     <ID>StringTemplate:AndroidDetectLeaksAssert.kt$AndroidDetectLeaksAssert${methodName}</ID>
12 |   </CurrentIssues>
13 | </SmellBaseline>
14 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-instrumentation
2 | POM_NAME=LeakCanary extension for Android instrumentation tests.
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest xmlns:android="http://schemas.android.com/apk/res/android">
18 | 
19 |   <application
20 |     android:name="androidx.multidex.MultiDexApplication"
21 |     >
22 |     <activity android:name="leakcanary.TestActivity"/>
23 |   </application>
24 | </manifest>
25 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/androidTest/assets/large-dump.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-instrumentation/src/androidTest/assets/large-dump.hprof


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/androidTest/java/leakcanary/AndroidDetectLeaksAssertTest.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import leakcanary.TestUtils.assertLeak
 4 | import org.junit.After
 5 | import org.junit.Before
 6 | import org.junit.Test
 7 | import java.util.Date
 8 | 
 9 | /**
10 |  * Tests that the [AndroidDetectLeaksAssert] can detect leaks
11 |  * in instrumentation tests
12 |  */
13 | class AndroidDetectLeaksAssertTest {
14 | 
15 |   @Before fun setUp() {
16 |     AppWatcher.objectWatcher
17 |       .clearAllObjectsTracked()
18 |   }
19 | 
20 |   @After fun tearDown() {
21 |     AppWatcher.objectWatcher
22 |       .clearAllObjectsTracked()
23 |   }
24 | 
25 |   @Test fun detectsLeak() {
26 |     leaking = Date()
27 |     val objectWatcher = AppWatcher.objectWatcher
28 |     objectWatcher.expectWeaklyReachable(leaking, "This date should not live beyond the test")
29 |     assertLeak(Date::class.java)
30 |   }
31 | 
32 |   companion object {
33 |     private lateinit var leaking: Any
34 |   }
35 | }
36 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/androidTest/java/leakcanary/TestActivity.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.os.Bundle
 4 | import androidx.fragment.app.FragmentActivity
 5 | import com.squareup.leakcanary.instrumentation.test.R
 6 | 
 7 | class TestActivity : FragmentActivity() {
 8 |   override fun onCreate(savedInstanceState: Bundle?) {
 9 |     super.onCreate(savedInstanceState)
10 |     setContentView(R.layout.activity_test)
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/androidTest/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 |     android:id="@+id/fragments"
4 |     android:layout_width="match_parent"
5 |     android:layout_height="match_parent"
6 |     />
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest>
18 | </manifest>
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/java/leakcanary/DetectLeaksAssert.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | /**
 4 |  * The interface for the implementation that [LeakAssertions.assertNoLeaks] delegates to.
 5 |  * You can call [DetectLeaksAssert.update] to provide your own implementation.
 6 |  *
 7 |  * The default implementation is [AndroidDetectLeaksAssert].
 8 |  */
 9 | fun interface DetectLeaksAssert {
10 | 
11 |   fun assertNoLeaks(tag: String)
12 | 
13 |   companion object {
14 |     @Volatile
15 |     internal var delegate: DetectLeaksAssert = AndroidDetectLeaksAssert()
16 | 
17 |     fun update(delegate: DetectLeaksAssert) {
18 |       DetectLeaksAssert.delegate = delegate
19 |     }
20 |   }
21 | }
22 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/java/leakcanary/DetectLeaksInterceptor.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | /**
 4 |  * Decides whether to dump & analyze the heap to look for leaks in instrumentation tests.
 5 |  * The implementation might block for a while to allow temporary leaks to be flushed out, as those
 6 |  * aren't that interesting to report and heap analysis increases test duration significantly.
 7 |  */
 8 | fun interface DetectLeaksInterceptor {
 9 |   fun waitUntilReadyForHeapAnalysis(): HeapAnalysisDecision
10 | }
11 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/java/leakcanary/HeapAnalysisDecision.kt:
--------------------------------------------------------------------------------
1 | package leakcanary
2 | 
3 | sealed class HeapAnalysisDecision {
4 |   object AnalyzeHeap : HeapAnalysisDecision()
5 |   class NoHeapAnalysis(val reason: String) : HeapAnalysisDecision()
6 | }
7 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/java/leakcanary/HeapAnalysisReporter.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import shark.HeapAnalysis
 4 | 
 5 | /**
 6 |  * Reports the results of a heap analysis created by [AndroidDetectLeaksAssert].
 7 |  */
 8 | fun interface HeapAnalysisReporter {
 9 |   fun reportHeapAnalysis(heapAnalysis: HeapAnalysis)
10 | }
11 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/java/leakcanary/LeakAssertions.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | object LeakAssertions {
 4 | 
 5 |   /**
 6 |    * Asserts that there are no leak in the heap at this point in time.
 7 |    *
 8 |    * This method should be called on the instrumentation thread.
 9 |    *
10 |    * This method is may block the current thread for a significant amount of time,
11 |    * as it might need to dump the heap and analyze it.
12 |    *
13 |    * If leaks are found, this method is expected to throw an exception, which will fail the test.
14 |    *
15 |    * The specific details depend on what you configured in [DetectLeaksAssert.update].
16 |    *
17 |    * [tag] identifies the calling code, which can then be used for reporting purposes or to skip
18 |    * leak detection for specific tags in a subset of tests (see [SkipLeakDetection]).
19 |    */
20 |   fun assertNoLeaks(tag: String = NO_TAG) {
21 |     DetectLeaksAssert.delegate.assertNoLeaks(tag)
22 |   }
23 | 
24 |   const val NO_TAG = ""
25 | }
26 | 
27 | 
28 | 
29 | 
30 | 
31 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-instrumentation/src/main/java/leakcanary/internal/friendly/Friendly.kt:
--------------------------------------------------------------------------------
 1 | @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
 2 | @file:JvmName("leakcanary-android-instrumentation_Friendly")
 3 | package leakcanary.internal.friendly
 4 | 
 5 | internal inline fun <reified T : Any> noOpDelegate(): T = leakcanary.internal.noOpDelegate()
 6 | 
 7 | internal inline fun checkNotMainThread() = leakcanary.internal.checkNotMainThread()
 8 | 
 9 | internal inline fun measureDurationMillis(block: () -> Unit) =
10 |   leakcanary.internal.measureDurationMillis(block)
11 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-process/api/leakcanary-android-process.api:
--------------------------------------------------------------------------------
 1 | public final class leakcanary/LeakCanaryProcess {
 2 | 	public static final field INSTANCE Lleakcanary/LeakCanaryProcess;
 3 | 	public final fun isInAnalyzerProcess (Landroid/content/Context;)Z
 4 | }
 5 | 
 6 | public final class leakcanary/internal/RemoteLeakCanaryWorkerService : androidx/work/multiprocess/RemoteWorkerService {
 7 | 	public fun <init> ()V
 8 | 	public fun getApplicationContext ()Landroid/content/Context;
 9 | 	public fun onCreate ()V
10 | }
11 | 
12 | public final class leakcanary/internal/RemoteLeakCanaryWorkerService$FakeAppContextConfigurationProvider : android/content/ContextWrapper, androidx/work/Configuration$Provider {
13 | 	public fun <init> (Landroid/content/Context;)V
14 | 	public synthetic fun getApplicationContext ()Landroid/content/Context;
15 | 	public fun getApplicationContext ()Lleakcanary/internal/RemoteLeakCanaryWorkerService$FakeAppContextConfigurationProvider;
16 | 	public fun getWorkManagerConfiguration ()Landroidx/work/Configuration;
17 | }
18 | 
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-process/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.shark.sharkLog)
 9 |   api(projects.objectWatcher.objectWatcherAndroidCore)
10 | 
11 |   implementation(libs.kotlin.stdlib)
12 |   implementation(libs.androidX.work.multiprocess)
13 | }
14 | 
15 | android {
16 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
17 |   defaultConfig {
18 |     minSdk = libs.versions.androidMinSdk.get().toInt()
19 |   }
20 |   buildFeatures.buildConfig = false
21 |   namespace = "com.squareup.leakcanary"
22 |   lint {
23 |     checkOnly += "Interoperability"
24 |     disable += "GoogleAppIndexingWarning"
25 |     ignore += "InvalidPackage"
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-process/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # A ContentProvider that gets created by Android on :leakcanary process startup
2 | -keep class leakcanary.internal.LeakCanaryProcessAppWatcherInstaller { <init>(); }
3 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-process/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-process
2 | POM_NAME=LeakCanary Android running in a separate process
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-process/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest xmlns:android="http://schemas.android.com/apk/res/android">
18 | 
19 |   <application>
20 |     <service
21 |       android:name="leakcanary.internal.RemoteLeakCanaryWorkerService"
22 |       android:exported="false"
23 |       android:process=":leakcanary" />
24 |   </application>
25 | 
26 | </manifest>
27 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-android-release/consumer-proguard-rules.pro


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-release
2 | POM_NAME=LeakCanary for released Android apps
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest />
3 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/java/leakcanary/ConditionalInterceptor.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import leakcanary.HeapAnalysisInterceptor.Chain
 4 | import leakcanary.HeapAnalysisJob.Result
 5 | 
 6 | /**
 7 |  * An interceptor that runs only when [evaluateCondition] returns true.
 8 |  */
 9 | class ConditionalInterceptor(
10 |   private val delegate: HeapAnalysisInterceptor,
11 |   private val evaluateCondition: (HeapAnalysisJob) -> Boolean
12 | ) : HeapAnalysisInterceptor {
13 |   override fun intercept(chain: Chain): Result {
14 |     if (evaluateCondition(chain.job)) {
15 |       return delegate.intercept(object : Chain {
16 |         override val job = chain.job
17 | 
18 |         override fun proceed(): Result {
19 |           return chain.proceed()
20 |         }
21 |       })
22 |     } else {
23 |       return chain.proceed()
24 |     }
25 |   }
26 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/java/leakcanary/GoodAndroidVersionInterceptor.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.os.Build
 4 | import leakcanary.HeapAnalysisInterceptor.Chain
 5 | 
 6 | class GoodAndroidVersionInterceptor : HeapAnalysisInterceptor {
 7 |   private val errorMessage: String? by lazy {
 8 |     val sdkInt = Build.VERSION.SDK_INT
 9 |     if (// findObjectById() sometimes failing. See #1759
10 |       sdkInt != 23 &&
11 |       // findObjectById() sometimes failing. See #1759
12 |       sdkInt != 25 &&
13 |       // Android 11 seem to sometimes have super slow heap dumps.
14 |       // See https://issuetracker.google.com/issues/168634429
15 |       sdkInt < 30
16 |     ) {
17 |       null
18 |     } else {
19 |       "Build.VERSION.SDK_INT $sdkInt not supported"
20 |     }
21 |   }
22 | 
23 |   override fun intercept(chain: Chain): HeapAnalysisJob.Result {
24 |     errorMessage?.let {
25 |       chain.job.cancel(it)
26 |     }
27 |     return chain.proceed()
28 |   }
29 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/java/leakcanary/HeapAnalysisInterceptor.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | fun interface HeapAnalysisInterceptor {
 4 | 
 5 |   fun intercept(chain: Chain): HeapAnalysisJob.Result
 6 | 
 7 |   interface Chain {
 8 |     val job: HeapAnalysisJob
 9 | 
10 |     fun proceed(): HeapAnalysisJob.Result
11 |   }
12 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/java/leakcanary/MinimumDiskSpaceInterceptor.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.app.Application
 4 | import leakcanary.HeapAnalysisInterceptor.Chain
 5 | import leakcanary.HeapAnalysisJob.Result
 6 | 
 7 | class MinimumDiskSpaceInterceptor(
 8 |   private val application: Application,
 9 |   private val minimumDiskSpaceBytes: Long = 200_000_000,
10 |   private val processInfo: ProcessInfo = ProcessInfo.Real
11 | ) : HeapAnalysisInterceptor {
12 | 
13 |   override fun intercept(chain: Chain): Result {
14 |     val availableDiskSpace = processInfo.availableDiskSpaceBytes(application.filesDir!!)
15 |     if (availableDiskSpace < minimumDiskSpaceBytes) {
16 |       chain.job.cancel("availableDiskSpace $availableDiskSpace < minimumDiskSpaceBytes $minimumDiskSpaceBytes")
17 |     }
18 |     return chain.proceed()
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/java/leakcanary/MinimumElapsedSinceStartInterceptor.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.annotation.SuppressLint
 4 | import leakcanary.HeapAnalysisInterceptor.Chain
 5 | import leakcanary.HeapAnalysisJob.Result
 6 | import java.util.concurrent.TimeUnit
 7 | 
 8 | @SuppressLint("NewApi")
 9 | class MinimumElapsedSinceStartInterceptor(
10 |   private val minimumElapsedSinceStartMillis: Long = TimeUnit.SECONDS.toMillis(30),
11 |   private val processInfo: ProcessInfo = ProcessInfo.Real
12 | ) : HeapAnalysisInterceptor {
13 | 
14 |   override fun intercept(chain: Chain): Result {
15 |     if (processInfo.elapsedMillisSinceStart < minimumElapsedSinceStartMillis) {
16 |       chain.job.cancel("app started less than $minimumElapsedSinceStartMillis ms ago.")
17 |     }
18 |     return chain.proceed()
19 |   }
20 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-release/src/main/java/leakcanary/internal/friendly/Friendly.kt:
--------------------------------------------------------------------------------
 1 | @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "NOTHING_TO_INLINE")
 2 | @file:JvmName("leakcanary-android-release_Friendly")
 3 | 
 4 | package leakcanary.internal.friendly
 5 | 
 6 | internal inline val mainHandler
 7 |   get() = leakcanary.internal.mainHandler
 8 | 
 9 | internal inline fun checkMainThread() = leakcanary.internal.checkMainThread()
10 | 
11 | internal inline fun <reified T : Any> noOpDelegate(): T = leakcanary.internal.noOpDelegate()
12 | 
13 | internal inline fun measureDurationMillis(block: () -> Unit) =
14 |   leakcanary.internal.measureDurationMillis(block)


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-startup/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.leakcanary.leakcanaryAndroidCore)
 9 |   // AppWatcher AndroidX Startup installer
10 |   implementation(projects.objectWatcher.objectWatcherAndroidStartup)
11 |   // Plumber AndroidX Startup installer
12 |   implementation(projects.plumber.plumberAndroidStartup)
13 | }
14 | 
15 | android {
16 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
17 |   defaultConfig {
18 |     minSdk = libs.versions.androidMinSdk.get().toInt()
19 |   }
20 |   buildFeatures.buildConfig = false
21 |   namespace = "com.squareup.leakcanary.startup"
22 |   lint {
23 |     checkOnly += "Interoperability"
24 |     disable += "GoogleAppIndexingWarning"
25 |     ignore += "InvalidPackage"
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-startup/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-startup
2 | POM_NAME=AndroidX Startup config for LeakCanary Android
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-startup/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest />
3 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-test/api/leakcanary-android-test.api:
--------------------------------------------------------------------------------
 1 | public final class leakcanary/RepeatingAndroidInProcessScenarioKt {
 2 | 	public static final fun repeatingAndroidInProcessScenario (Lshark/HeapDiff$Companion;Lshark/ObjectGrowthDetector;Lleakcanary/HeapDumpDirectoryProvider;Lleakcanary/HeapDumper;Lleakcanary/HeapDumpStorageStrategy;)Lshark/RepeatingScenarioObjectGrowthDetector;
 3 | 	public static synthetic fun repeatingAndroidInProcessScenario$default (Lshark/HeapDiff$Companion;Lshark/ObjectGrowthDetector;Lleakcanary/HeapDumpDirectoryProvider;Lleakcanary/HeapDumper;Lleakcanary/HeapDumpStorageStrategy;ILjava/lang/Object;)Lshark/RepeatingScenarioObjectGrowthDetector;
 4 | }
 5 | 
 6 | public final class leakcanary/TargetContextHeapDumpDirectoryProvider : leakcanary/HeapDumpDirectoryProvider {
 7 | 	public fun <init> (Ljava/lang/String;)V
 8 | 	public fun heapDumpDirectory ()Ljava/io/File;
 9 | }
10 | 
11 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-test/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-test
2 | POM_NAME=LeakCanary Android - Test
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-test/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3 | 
4 |   <application
5 |     android:name="androidx.multidex.MultiDexApplication"
6 |     >
7 |   </application>
8 | </manifest>
9 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-test/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest>
18 | </manifest>
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-test/src/main/java/leakcanary/TargetContextHeapDumpDirectoryProvider.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import androidx.test.platform.app.InstrumentationRegistry
 4 | import java.io.File
 5 | 
 6 | class TargetContextHeapDumpDirectoryProvider(
 7 |   private val heapDumpDirectoryName: String
 8 | ) : HeapDumpDirectoryProvider {
 9 |   override fun heapDumpDirectory() = File(
10 |     InstrumentationRegistry.getInstrumentation().targetContext.filesDir,
11 |     heapDumpDirectoryName
12 |   )
13 | }
14 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-uiautomator/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.leakcanary.leakcanaryCore)
 9 |   api(projects.leakcanary.leakcanaryTestCore)
10 |   api(projects.shark.sharkAndroid)
11 |   api(libs.androidX.test.uiautomator)
12 | 
13 |   implementation(libs.androidX.test.monitor)
14 | }
15 | 
16 | android {
17 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
18 |   defaultConfig {
19 |     targetSdk = libs.versions.androidCompileSdk.get().toInt()
20 |     minSdk = 18
21 |   }
22 |   buildFeatures.buildConfig = false
23 |   namespace = "com.squareup.leakcanary.android.uiautomator"
24 | }
25 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-uiautomator/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-uiautomator
2 | POM_NAME=LeakCanary Android - Utilities for UI Automator
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-uiautomator/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android">
 3 | 
 4 |   <!--
 5 |     Performing the heap growth analysis requires more heap. We avoid doing this for
 6 |     in process LeakCanary because apps might not expect it, but that seems more ok
 7 |     for a ui automation app.
 8 |   -->
 9 |   <application
10 |     android:largeHeap="true"/>
11 | 
12 | </manifest>
13 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-uiautomator/src/main/java/leakcanary/AndroidDeviceTempHeapDumpDirectoryProvider.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import java.io.File
 4 | 
 5 | class AndroidDeviceTempHeapDumpDirectoryProvider(
 6 |   private val heapDumpDirectoryName: String
 7 | ) : HeapDumpDirectoryProvider {
 8 |   override fun heapDumpDirectory() = File("/data/local/tmp/", heapDumpDirectoryName)
 9 | }
10 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-uiautomator/src/main/java/leakcanary/UiAutomatorShellFileDeleter.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import androidx.test.platform.app.InstrumentationRegistry
 4 | import androidx.test.uiautomator.UiDevice
 5 | import java.io.File
 6 | 
 7 | object UiAutomatorShellFileDeleter {
 8 |   fun deleteFileUsingShell(file: File) {
 9 |     val instrumentation = InstrumentationRegistry.getInstrumentation()
10 |     val device = UiDevice.getInstance(instrumentation)
11 |     device.executeShellCommand("rm ${file.absolutePath}")
12 |   }
13 | }
14 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/api/leakcanary-android-utils.api:
--------------------------------------------------------------------------------
 1 | public final class leakcanary/AndroidDebugHeapDumper : leakcanary/HeapDumper {
 2 | 	public static final field INSTANCE Lleakcanary/AndroidDebugHeapDumper;
 3 | 	public fun dumpHeap (Ljava/io/File;)V
 4 | }
 5 | 
 6 | public final class leakcanary/AndroidDebugHeapDumperKt {
 7 | 	public static final fun forAndroidInProcess (Lleakcanary/HeapDumper$Companion;)Lleakcanary/AndroidDebugHeapDumper;
 8 | }
 9 | 
10 | public final class leakcanary/LogcatSharkLog : shark/SharkLog$Logger {
11 | 	public static final field Companion Lleakcanary/LogcatSharkLog$Companion;
12 | 	public fun <init> ()V
13 | 	public fun d (Ljava/lang/String;)V
14 | 	public fun d (Ljava/lang/Throwable;Ljava/lang/String;)V
15 | }
16 | 
17 | public final class leakcanary/LogcatSharkLog$Companion {
18 | 	public final fun install ()V
19 | }
20 | 
21 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.leakcanary.leakcanaryCore)
 9 |   api(projects.shark.sharkLog)
10 | 
11 |   implementation(libs.kotlin.stdlib)
12 | }
13 | 
14 | android {
15 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
16 |   defaultConfig {
17 |     minSdk = libs.versions.androidMinSdk.get().toInt()
18 |   }
19 |   buildFeatures.buildConfig = false
20 |   namespace = "com.squareup.leakcanary.utils"
21 |   lint {
22 |     checkOnly += "Interoperability"
23 |     disable += "GoogleAppIndexingWarning"
24 |     error += "ObsoleteSdkInt"
25 |   }
26 | }
27 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>FinalNewline:LogcatSharkLog.kt$leakcanary.LogcatSharkLog.kt</ID>
6 |     <ID>FinalNewline:Objects.kt$leakcanary.internal.Objects.kt</ID>
7 |   </CurrentIssues>
8 | </SmellBaseline>
9 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android-utils
2 | POM_NAME=LeakCanary Android Utils
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest />
3 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/src/main/java/leakcanary/AndroidDebugHeapDumper.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.os.Debug
 4 | import java.io.File
 5 | 
 6 | /**
 7 |  * Dumps the Android heap using [Debug.dumpHprofData].
 8 |  *
 9 |  * Note: despite being part of the Debug class, [Debug.dumpHprofData] can be called from non
10 |  * debuggable non profileable builds.
11 |  */
12 | object AndroidDebugHeapDumper : HeapDumper {
13 |   override fun dumpHeap(heapDumpFile: File) {
14 |     Debug.dumpHprofData(heapDumpFile.absolutePath)
15 |   }
16 | }
17 | 
18 | fun HeapDumper.Companion.forAndroidInProcess() = AndroidDebugHeapDumper
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/src/main/java/leakcanary/LogcatSharkLog.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.util.Log
 4 | import shark.SharkLog
 5 | import shark.SharkLog.Logger
 6 | 
 7 | class LogcatSharkLog : Logger {
 8 | 
 9 |   override fun d(message: String) {
10 |     if (message.length < 4000) {
11 |       Log.d("LeakCanary", message)
12 |     } else {
13 |       message.lines().forEach { line ->
14 |         Log.d("LeakCanary", line)
15 |       }
16 |     }
17 |   }
18 | 
19 |   override fun d(
20 |     throwable: Throwable,
21 |     message: String
22 |   ) {
23 |     d("$message\n${Log.getStackTraceString(throwable)}")
24 |   }
25 | 
26 |   companion object {
27 |     fun install() {
28 |       SharkLog.logger = LogcatSharkLog()
29 |     }
30 |   }
31 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/src/main/java/leakcanary/internal/Handlers.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import android.os.Handler
 4 | import android.os.Looper
 5 | 
 6 | internal val mainHandler by lazy { Handler(Looper.getMainLooper()) }
 7 | 
 8 | internal val isMainThread: Boolean get() = Looper.getMainLooper().thread === Thread.currentThread()
 9 | 
10 | internal fun checkMainThread() {
11 |   check(isMainThread) {
12 |     "Should be called from the main thread, not ${Thread.currentThread()}"
13 |   }
14 | }
15 | 
16 | internal fun checkNotMainThread() {
17 |   check(!isMainThread) {
18 |     "Should not be called from the main thread"
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/src/main/java/leakcanary/internal/Objects.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import java.lang.reflect.InvocationHandler
 4 | import java.lang.reflect.Proxy
 5 | 
 6 | internal inline fun <reified T : Any> noOpDelegate(): T {
 7 |   val javaClass = T::class.java
 8 |   return Proxy.newProxyInstance(
 9 |     javaClass.classLoader, arrayOf(javaClass), NO_OP_HANDLER
10 |   ) as T
11 | }
12 | 
13 | private val NO_OP_HANDLER = InvocationHandler { _, _, _ ->
14 |   // no op
15 | }


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android-utils/src/main/java/leakcanary/internal/Timing.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import android.os.SystemClock
 4 | 
 5 | /**
 6 |  * Executes the given [block] and returns elapsed time in milliseconds using [SystemClock.uptimeMillis]
 7 |  */
 8 | internal inline fun measureDurationMillis(block: () -> Unit): Long {
 9 |   val start = SystemClock.uptimeMillis()
10 |   block()
11 |   return SystemClock.uptimeMillis() - start
12 | }
13 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-android
2 | POM_NAME=LeakCanary Android
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest />
18 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-aidl/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   implementation(libs.kotlin.stdlib)
 9 |   implementation(projects.shark.shark)
10 | }
11 | 
12 | android {
13 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
14 |   defaultConfig {
15 |     minSdk = libs.versions.androidMinSdk.get().toInt()
16 |   }
17 |   buildFeatures {
18 |     aidl = true
19 |   }
20 |   buildFeatures.buildConfig = false
21 |   namespace = "com.squareup.leakcanary.app.aidl"
22 |   lint {
23 |     checkOnly += "Interoperability"
24 |     disable += "GoogleAppIndexingWarning"
25 |     ignore += "InvalidPackage"
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-aidl/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-app-aidl
2 | POM_NAME=Service definitions to communicate with the LeakCanary UI app.
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-aidl/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest />
3 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-aidl/src/main/aidl/org/leakcanary/internal/LeakUiApp.aidl:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.internal;
 2 | 
 3 | import android.net.Uri;
 4 | 
 5 | parcelable ParcelableHeapAnalysis;
 6 | 
 7 | interface LeakUiApp {
 8 |  void sendHeapAnalysis(in ParcelableHeapAnalysis heapAnalysis, in Uri heapDumpUri);
 9 | }
10 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-aidl/src/main/java/org/leakcanary/internal/ParcelableHeapAnalysis.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.internal
 2 | 
 3 | import android.os.Parcel
 4 | import android.os.Parcelable
 5 | import shark.HeapAnalysis
 6 | 
 7 | class ParcelableHeapAnalysis(val wrapped: HeapAnalysis) : Parcelable {
 8 | 
 9 |   private constructor(source: Parcel) : this(source.readSerializable() as HeapAnalysis)
10 | 
11 |   override fun writeToParcel(dest: Parcel, flags: Int) {
12 |     dest.writeSerializable(wrapped)
13 |   }
14 | 
15 |   override fun describeContents() = 0
16 | 
17 |   companion object {
18 |     @Suppress("UNCHECKED_CAST")
19 |     @JvmField val CREATOR = object : Parcelable.Creator<ParcelableHeapAnalysis> {
20 |       override fun createFromParcel(source: Parcel): ParcelableHeapAnalysis {
21 |         return ParcelableHeapAnalysis(source)
22 |       }
23 | 
24 |       override fun newArray(size: Int): Array<ParcelableHeapAnalysis?> {
25 |         return arrayOfNulls(size)
26 |       }
27 |     }
28 | 
29 |     fun HeapAnalysis.asParcelable(): ParcelableHeapAnalysis = ParcelableHeapAnalysis(this)
30 |   }
31 | }
32 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-service/api/leakcanary-app-service.api:
--------------------------------------------------------------------------------
1 | public final class org/leakcanary/internal/LeakUiAppClient {
2 | 	public fun <init> (Landroid/content/Context;)V
3 | 	public final fun sendHeapAnalysis (Lshark/HeapAnalysis;)V
4 | }
5 | 
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-service/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   implementation(libs.kotlin.stdlib)
 9 | }
10 | 
11 | android {
12 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
13 |   defaultConfig {
14 |     minSdk = libs.versions.androidMinSdk.get().toInt()
15 |   }
16 |   buildFeatures.buildConfig = false
17 |   namespace = "com.squareup.leakcanary.app.service"
18 |   lint {
19 |     checkOnly += "Interoperability"
20 |     disable += "GoogleAppIndexingWarning"
21 |     ignore += "InvalidPackage"
22 |   }
23 | }
24 | 
25 | dependencies {
26 |   implementation(projects.leakcanary.leakcanaryAppAidl)
27 |   implementation(projects.leakcanary.leakcanaryAndroidCore)
28 |   implementation(projects.shark.shark)
29 |   implementation(projects.shark.sharkAndroid)
30 | }
31 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-service/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-app-service
2 | POM_NAME=Service that communicates with the LeakCanary UI app.
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app-service/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3 | 
4 |   <queries>
5 |     <package android:name="org.leakcanary" />
6 |   </queries>
7 | 
8 | </manifest>
9 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>FinalNewline:Color.kt$org.leakcanary.ui.theme.Color.kt</ID>
 6 |     <ID>FinalNewline:Theme.kt$org.leakcanary.ui.theme.Theme.kt</ID>
 7 |     <ID>FinalNewline:Type.kt$org.leakcanary.ui.theme.Type.kt</ID>
 8 |     <ID>MaximumLineLength:LeakScreen.kt$LeakViewModel$ </ID>
 9 |     <ID>MultiLineIfElse:LeakTraceWrapper.kt$LeakTraceWrapper$null</ID>
10 |     <ID>NoBlankLineBeforeRbrace:ClientAppAnalysesScreen.kt$ </ID>
11 |     <ID>NoConsecutiveBlankLines:TreeMapScreen.kt$ </ID>
12 |     <ID>ParameterListWrapping:DatabaseModule.kt$DatabaseModule$( app: Application, @WriteAheadLoggingEnabled wolEnabled: Boolean )</ID>
13 |     <ID>SpacingAroundKeyword:HeapRepository.kt$HeapRepository$if</ID>
14 |     <ID>StringTemplate:LeakScreen.kt${leakingStatusReason}</ID>
15 |   </CurrentIssues>
16 | </SmellBaseline>
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/java/org/leakcanary/LeakCanaryApp.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary
 2 | 
 3 | import android.app.Application
 4 | import dagger.hilt.android.HiltAndroidApp
 5 | import org.leakcanary.util.ActivityProviderCallbacks
 6 | 
 7 | @HiltAndroidApp
 8 | class LeakCanaryApp : Application() {
 9 | 
10 |   override fun onCreate() {
11 |     super.onCreate()
12 |     registerActivityLifecycleCallbacks(ActivityProviderCallbacks())
13 |   }
14 | }
15 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/java/org/leakcanary/screens/Destination.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.screens
 2 | 
 3 | import android.os.Parcelable
 4 | import java.io.File
 5 | import kotlinx.parcelize.Parcelize
 6 | 
 7 | sealed class Destination(val title: String) : Parcelable {
 8 | 
 9 |   @Parcelize
10 |   object ClientAppsDestination : Destination("Apps")
11 | 
12 |   // TODO Figure out dynamic titles, this should say "X Heap Analyses"
13 |   // Should also show the app name, icon..
14 |   // Can use content for now.
15 |   @Parcelize
16 |   class ClientAppAnalysesDestination(val packageName: String) : Destination("Heap Analyses")
17 | 
18 |   @Parcelize
19 |   class ClientAppAnalysisDestination(val analysisId: Long) : Destination("Analysis")
20 | 
21 |   @Parcelize
22 |   class TreeMapDestination(val heapDump: File) : Destination("TreeMap")
23 | 
24 |   @Parcelize
25 |   object LeaksDestination : Destination("Leaks")
26 | 
27 |   @Parcelize
28 |   class LeakDestination(
29 |     val leakSignature: String,
30 |     val selectedAnalysisId: Long? = null
31 |   ) : Destination("Leak")
32 | }
33 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/java/org/leakcanary/ui/theme/Color.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.ui.theme
 2 | 
 3 | import androidx.compose.ui.graphics.Color
 4 | 
 5 | val Purple80 = Color(0xFFD0BCFF)
 6 | val PurpleGrey80 = Color(0xFFCCC2DC)
 7 | val Pink80 = Color(0xFFEFB8C8)
 8 | 
 9 | val Purple40 = Color(0xFF6650a4)
10 | val PurpleGrey40 = Color(0xFF625b71)
11 | val Pink40 = Color(0xFF7D5260)


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/java/org/leakcanary/util/Handlers.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.util
 2 | 
 3 | import android.os.Handler
 4 | import android.os.Looper
 5 | 
 6 | val mainHandler by lazy { Handler(Looper.getMainLooper()) }
 7 | 
 8 | val isMainThread: Boolean get() = Looper.getMainLooper().thread === Thread.currentThread()
 9 | 
10 | fun checkMainThread() {
11 |   check(isMainThread) {
12 |     "Should be called from the main thread, not ${Thread.currentThread()}"
13 |   }
14 | }
15 | 
16 | fun checkNotMainThread() {
17 |   check(!isMainThread) {
18 |     "Should not be called from the main thread"
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/java/org/leakcanary/util/Serializables.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.util
 2 | 
 3 | import java.io.ByteArrayInputStream
 4 | import java.io.ByteArrayOutputStream
 5 | import java.io.ObjectInputStream
 6 | import java.io.ObjectOutputStream
 7 | import java.io.Serializable
 8 | import shark.SharkLog
 9 | 
10 | internal fun Serializable.toByteArray(): ByteArray {
11 |   val outputStream = ByteArrayOutputStream()
12 |   ObjectOutputStream(outputStream).writeObject(this)
13 |   return outputStream.toByteArray()
14 | }
15 | 
16 | internal object Serializables {
17 | 
18 |   inline fun <reified T> fromByteArray(byteArray: ByteArray): T? {
19 |     val inputStream = ByteArrayInputStream(byteArray)
20 |     return try {
21 |       ObjectInputStream(inputStream).readObject() as? T
22 |     } catch (ignored: Throwable) {
23 |       SharkLog.d(ignored) { "Could not deserialize bytes, ignoring" }
24 |       null
25 |     }
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/java/org/leakcanary/util/Sharer.kt:
--------------------------------------------------------------------------------
 1 | package org.leakcanary.util
 2 | 
 3 | import android.content.Intent
 4 | import dagger.Binds
 5 | import dagger.Module
 6 | import dagger.hilt.InstallIn
 7 | import dagger.hilt.android.components.ActivityRetainedComponent
 8 | import javax.inject.Inject
 9 | 
10 | interface Sharer {
11 |   fun share(content: String)
12 | }
13 | 
14 | class ActivitySharer @Inject constructor(
15 |   private val activityProvider: CurrentActivityProvider
16 | ) : Sharer {
17 |   override fun share(content: String) {
18 |     val intent = Intent(Intent.ACTION_SEND).apply {
19 |       type = "text/plain"
20 |       putExtra(Intent.EXTRA_TEXT, content)
21 |     }
22 | 
23 |     activityProvider.withActivity {
24 |       startActivity(
25 |         Intent.createChooser(intent, "Share with…")
26 |       )
27 |     }
28 |   }
29 | }
30 | 
31 | @Module
32 | @InstallIn(ActivityRetainedComponent::class)
33 | interface SharerModule {
34 |   @Binds fun bindSharer(sharer: ActivitySharer): Sharer
35 | }
36 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <background android:drawable="@drawable/ic_launcher_background" />
4 |   <foreground android:drawable="@drawable/ic_launcher_foreground" />
5 | </adaptive-icon>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <background android:drawable="@drawable/ic_launcher_background" />
4 |   <foreground android:drawable="@drawable/ic_launcher_foreground" />
5 | </adaptive-icon>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-hdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-hdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-mdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-mdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-xhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-xxhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/leakcanary/leakcanary-app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |   <color name="purple_200">#FFBB86FC</color>
 4 |   <color name="purple_500">#FF6200EE</color>
 5 |   <color name="purple_700">#FF3700B3</color>
 6 |   <color name="teal_200">#FF03DAC5</color>
 7 |   <color name="teal_700">#FF018786</color>
 8 |   <color name="black">#FF000000</color>
 9 |   <color name="white">#FFFFFFFF</color>
10 | </resources>
11 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 | <resources>
2 |   <string name="app_name">My Application</string>
3 | </resources>
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 | 
4 |   <style name="Theme.MyApplication" parent="android:Theme.Material.Light.NoActionBar" />
5 | </resources>
6 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |    Sample backup rules file; uncomment and customize as necessary.
 3 |    See https://developer.android.com/guide/topics/data/autobackup
 4 |    for details.
 5 |    Note: This file is ignored for devices older that API 31
 6 |    See https://developer.android.com/about/versions/12/backup-restore
 7 | -->
 8 | <full-backup-content>
 9 |   <!--
10 |    <include domain="sharedpref" path="."/>
11 |    <exclude domain="sharedpref" path="device.xml"/>
12 | -->
13 | </full-backup-content>
14 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |    Sample data extraction rules file; uncomment and customize as necessary.
 3 |    See https://developer.android.com/about/versions/12/backup-restore#xml-changes
 4 |    for details.
 5 | -->
 6 | <data-extraction-rules>
 7 |   <cloud-backup>
 8 |     <!-- TODO: Use <include> and <exclude> to control what is backed up.
 9 |         <include .../>
10 |         <exclude .../>
11 |         -->
12 |   </cloud-backup>
13 |   <!--
14 |     <device-transfer>
15 |         <include .../>
16 |         <exclude .../>
17 |     </device-transfer>
18 |     -->
19 | </data-extraction-rules>
20 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-app/src/main/sqldelight/dev/leakcanary/sqldelight/App.sq:
--------------------------------------------------------------------------------
 1 | CREATE TABLE app (
 2 |   package_name TEXT NOT NULL PRIMARY KEY,
 3 |   leak_count INTEGER NOT NULL DEFAULT 0
 4 | );
 5 | 
 6 | insertOrIgnore:
 7 | INSERT OR IGNORE INTO app (
 8 | package_name
 9 | )
10 | VALUES (?);
11 | 
12 | selectAll:
13 | SELECT
14 | package_name
15 | , leak_count
16 | FROM app;
17 | 
18 | updateLeakCounts:
19 | UPDATE app
20 | SET leak_count = (
21 | SELECT
22 | COUNT(DISTINCT lt.leak_signature)
23 | FROM leak_trace lt
24 | JOIN heap_analysis h ON lt.heap_analysis_id = h.id
25 | WHERE h.app_package_name=app.package_name
26 | );
27 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-core/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   api(projects.leakcanary.leakcanaryGc)
13 |   api(projects.shark.shark)
14 |   implementation(libs.okio2)
15 | 
16 |   testImplementation(libs.assertjCore)
17 |   testImplementation(libs.junit)
18 |   testImplementation(projects.shark.sharkHprofTest)
19 | }
20 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-core/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>MaximumLineLength:DumpingRepeatingScenarioObjectGrowthDetector.kt$DumpingRepeatingScenarioObjectGrowthDetector$ </ID>
 6 |     <ID>MaximumLineLength:ObjectGrowthWarmupHeapDumperTest.kt$ObjectGrowthWarmupHeapDumperTest$ </ID>
 7 |     <ID>NoConsecutiveBlankLines:DatetimeFormattedHeapDumpFileProvider.kt$ </ID>
 8 |     <ID>NoConsecutiveBlankLines:DumpingRepeatingScenarioObjectGrowthDetector.kt$ </ID>
 9 |     <ID>NoConsecutiveBlankLines:DumpingRepeatingScenarioObjectGrowthDetectorTest.kt$DumpingRepeatingScenarioObjectGrowthDetectorTest$ </ID>
10 |     <ID>NoConsecutiveBlankLines:ObjectGrowthWarmupHeapDumperTest.kt$ObjectGrowthWarmupHeapDumperTest$ </ID>
11 |     <ID>NoUnusedImports:HeapDumpFileProvider.kt$leakcanary.HeapDumpFileProvider.kt</ID>
12 |   </CurrentIssues>
13 | </SmellBaseline>
14 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-core/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-core
2 | POM_NAME=LeakCanary Core
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-core/src/main/java/leakcanary/HeapDumpDirectoryProvider.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import java.io.File
 4 | 
 5 | fun interface HeapDumpDirectoryProvider {
 6 |   /**
 7 |    * Expected to be called only once per [HeapDumpFileProvider] implementation instance.
 8 |    */
 9 |   fun heapDumpDirectory(): File
10 | }
11 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-core/src/main/java/leakcanary/HeapDumpFileProvider.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import java.io.File
 4 | import java.util.Date
 5 | 
 6 | fun interface HeapDumpFileProvider {
 7 | 
 8 |   /**
 9 |    * Returns a [File] that can be passed to a [HeapDumper] to dump the heap.
10 |    */
11 |   fun newHeapDumpFile(): File
12 | }
13 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-core/src/main/java/leakcanary/HeapDumper.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import java.io.File
 4 | 
 5 | fun interface HeapDumper {
 6 | 
 7 |   /**
 8 |    * Dumps the heap. The implementation is expected to be blocking until the heap is dumped
 9 |    * or heap dumping failed.
10 |    *
11 |    * Implementations can throw a runtime exception if heap dumping failed.
12 |    */
13 |   fun dumpHeap(heapDumpFile: File)
14 | 
15 |   /**
16 |    * This allows external modules to add factory methods for implementations of this interface as
17 |    * extension functions of this companion object.
18 |    */
19 |   companion object
20 | }
21 | 
22 | fun HeapDumper.withGc(gcTrigger: GcTrigger = GcTrigger.inProcess()): HeapDumper {
23 |   val delegate = this
24 |   return HeapDumper { file ->
25 |     gcTrigger.runGc()
26 |     delegate.dumpHeap(file)
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-deobfuscation-gradle-plugin/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>NoUnusedImports:LeakCanaryLeakDeobfuscationPlugin.kt$com.squareup.leakcanary.deobfuscation.LeakCanaryLeakDeobfuscationPlugin.kt</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-deobfuscation-gradle-plugin/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-deobfuscation-gradle-plugin
2 | POM_NAME=LeakCanary Deobfuscation Plugin
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-deobfuscation-gradle-plugin/src/test/test-project/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |   ~ Copyright (C) 2015 Square, Inc.
 3 |   ~
 4 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 5 |   ~ you may not use this file except in compliance with the License.
 6 |   ~ You may obtain a copy of the License at
 7 |   ~
 8 |   ~      http://www.apache.org/licenses/LICENSE-2.0
 9 |   ~
10 |   ~ Unless required by applicable law or agreed to in writing, software
11 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
12 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 |   ~ See the License for the specific language governing permissions and
14 |   ~ limitations under the License.
15 |   -->
16 | <manifest package="com.leakcanary.test" />
17 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-deobfuscation-gradle-plugin/src/test/test-project/src/main/java/com/leakcanary/test/TestProjectClass.java:
--------------------------------------------------------------------------------
1 | package com.leakcanary.test;
2 | 
3 | public class TestProjectClass {
4 |   public void foo() {
5 | 
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-gc/api/leakcanary-gc.api:
--------------------------------------------------------------------------------
 1 | public final class leakcanary/FinalizingInProcessGcTrigger : leakcanary/GcTrigger {
 2 | 	public static final field INSTANCE Lleakcanary/FinalizingInProcessGcTrigger;
 3 | 	public fun runGc ()V
 4 | }
 5 | 
 6 | public final class leakcanary/FinalizingInProcessGcTriggerKt {
 7 | 	public static final fun inProcess (Lleakcanary/GcTrigger$Companion;)Lleakcanary/FinalizingInProcessGcTrigger;
 8 | }
 9 | 
10 | public abstract interface class leakcanary/GcTrigger {
11 | 	public static final field Companion Lleakcanary/GcTrigger$Companion;
12 | 	public abstract fun runGc ()V
13 | }
14 | 
15 | public final class leakcanary/GcTrigger$Companion {
16 | 	public final fun getDefault ()Lleakcanary/FinalizingInProcessGcTrigger;
17 | }
18 | 
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-gc/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   implementation(libs.kotlin.stdlib)
13 | }
14 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-gc/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-gc
2 | POM_NAME=LeakCanary - GC Utilities
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-gc/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest>
18 | </manifest>
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-jvm-test/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   api(projects.leakcanary.leakcanaryTestCore)
13 |   api(projects.shark.shark)
14 | 
15 |   testImplementation(libs.assertjCore)
16 |   testImplementation(libs.junit)
17 |   testImplementation(projects.shark.sharkHprofTest)
18 | }
19 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-jvm-test/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>NoConsecutiveBlankLines:HotSpotHeapDumper.kt$ </ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-jvm-test/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-jvm-test
2 | POM_NAME=LeakCanary Jvm Test
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-jvm-test/src/main/java/leakcanary/HotSpotHeapDumper.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import com.sun.management.HotSpotDiagnosticMXBean
 4 | import java.io.File
 5 | import java.lang.management.ManagementFactory
 6 | 
 7 | object HotSpotHeapDumper : HeapDumper {
 8 |   private val hotspotMBean: HotSpotDiagnosticMXBean by lazy {
 9 |     val mBeanServer = ManagementFactory.getPlatformMBeanServer()
10 |     ManagementFactory.newPlatformMXBeanProxy(
11 |       mBeanServer,
12 |       "com.sun.management:type=HotSpotDiagnostic",
13 |       HotSpotDiagnosticMXBean::class.java
14 |     )
15 |   }
16 | 
17 |   override fun dumpHeap(heapDumpFile: File) {
18 |     val live = true
19 |     hotspotMBean.dumpHeap(heapDumpFile.absolutePath, live)
20 |   }
21 | }
22 | 
23 | fun HeapDumper.Companion.forJvmInProcess() = HotSpotHeapDumper
24 | 
25 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-jvm-test/src/main/java/leakcanary/RepositoryRootHeapDumpDirectoryProvider.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import java.io.File
 4 | 
 5 | class RepositoryRootHeapDumpDirectoryProvider(
 6 |   private val heapDumpDirectoryName: String
 7 | ) : HeapDumpDirectoryProvider {
 8 | 
 9 |   override fun heapDumpDirectory() = File(projectRootDirectory(), heapDumpDirectoryName)
10 | 
11 |   private fun projectRootDirectory(): File {
12 |     var currentDirectory = File("./")
13 |     // Going through absolute path string otherwise parentFile returns null.
14 |     currentDirectory = File(currentDirectory.absolutePath)
15 |     while (".git" !in currentDirectory) {
16 |       currentDirectory = currentDirectory.parentFile!!
17 |     }
18 |     return currentDirectory
19 |   }
20 | 
21 |   private operator fun File.contains(filename: String): Boolean {
22 |     return listFiles()?.any { it.name == filename } ?: false
23 |   }
24 | }
25 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-test-core/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   api(projects.leakcanary.leakcanaryCore)
13 |   api(projects.shark.shark)
14 |   api(libs.junit)
15 | 
16 |   testImplementation(libs.assertjCore)
17 | }
18 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-test-core/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>StringTemplate:TestHeapDumpFileProvider.kt$TestHeapDumpFileProvider${classSimpleName}</ID>
6 |     <ID>StringTemplate:TestHeapDumpFileProvider.kt$TestHeapDumpFileProvider${escapedMethodName}</ID>
7 |   </CurrentIssues>
8 | </SmellBaseline>
9 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-test-core/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-test-core
2 | POM_NAME=LeakCanary shared test utils
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/leakcanary/leakcanary-test-core/src/main/java/leakcanary/TestHeapDumpFileProvider.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | class TestHeapDumpFileProvider(
 4 |   heapDumpDirectoryProvider: HeapDumpDirectoryProvider
 5 | ) : HeapDumpFileProvider {
 6 | 
 7 |   private val delegate = DatetimeFormattedHeapDumpFileProvider(
 8 |     heapDumpDirectoryProvider = heapDumpDirectoryProvider,
 9 |     suffixProvider = {
10 |       TestNameProvider.currentTestName()?.run {
11 |         // JVM test method names can have spaces.
12 |         val escapedMethodName = methodName.replace(' ', '-')
13 |         "_${classSimpleName}-${escapedMethodName}"
14 |       } ?: ""
15 |     }
16 |   )
17 | 
18 |   override fun newHeapDumpFile() = delegate.newHeapDumpFile()
19 | }
20 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-androidx/api/object-watcher-android-androidx.api:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/object-watcher/object-watcher-android-androidx/api/object-watcher-android-androidx.api


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-androidx/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.objectWatcher.objectWatcherAndroidCore)
 9 | 
10 |   implementation(libs.kotlin.stdlib)
11 |   // Optional dependency
12 |   compileOnly(libs.androidX.fragment)
13 | }
14 | 
15 | android {
16 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
17 |   defaultConfig {
18 |     minSdk = libs.versions.androidMinSdk.get().toInt()
19 |     consumerProguardFiles("consumer-proguard-rules.pro")
20 |   }
21 |   buildFeatures.buildConfig = false
22 |   namespace = "com.squareup.leakcanary.fragments.androidx"
23 |   lint {
24 |     checkOnly += "Interoperability"
25 |     disable += "GoogleAppIndexingWarning"
26 |     error += "ObsoleteSdkInt"
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-androidx/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # AndroidXFragmentDestroyWatcher is loaded via reflection
2 | -keep class leakcanary.internal.AndroidXFragmentDestroyWatcher { *; }
3 | # ViewModelClearedWatcher reaches into ViewModelStore using reflection.
4 | -keep class androidx.lifecycle.ViewModelStore { *; }
5 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-androidx/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-object-watcher-android-androidx
2 | POM_NAME=LeakCanary Object Watcher for Android extension: Android X fragments support
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-androidx/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest>
3 | </manifest>
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.objectWatcher.objectWatcher)
 9 |   api(projects.leakcanary.leakcanaryAndroidUtils)
10 | 
11 |   implementation(libs.curtains)
12 |   implementation(libs.kotlin.stdlib)
13 | 
14 |   testImplementation(libs.assertjCore)
15 |   testImplementation(libs.junit)
16 |   testImplementation(libs.kotlin.reflect)
17 | }
18 | 
19 | android {
20 |   resourcePrefix = "leak_canary_watcher_"
21 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
22 | 
23 |   defaultConfig {
24 |     minSdk = libs.versions.androidMinSdk.get().toInt()
25 |     consumerProguardFiles("consumer-proguard-rules.pro")
26 |   }
27 | 
28 |   buildFeatures {
29 |     buildConfig = false
30 |   }
31 |   namespace = "com.squareup.leakcanary.objectwatcher.core"
32 |   lint {
33 |     checkOnly += "Interoperability"
34 |     disable += "GoogleAppIndexingWarning"
35 |   }
36 | }
37 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # KeyedWeakReference is looked up in the hprof file
2 | -keep class leakcanary.KeyedWeakReference { *; }
3 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>FinalNewline:Applications.kt$leakcanary.internal.Applications.kt</ID>
 6 |     <ID>FinalNewline:InstallableWatcher.kt$leakcanary.InstallableWatcher.kt</ID>
 7 |     <ID>FinalNewline:LeakCanaryDelegate.kt$leakcanary.internal.LeakCanaryDelegate.kt</ID>
 8 |   </CurrentIssues>
 9 | </SmellBaseline>
10 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-object-watcher-android-core
2 | POM_NAME=LeakCanary Object Watcher for Android - Core
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest>
3 | </manifest>
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/java/leakcanary/InstallableWatcher.kt:
--------------------------------------------------------------------------------
1 | package leakcanary
2 | 
3 | interface InstallableWatcher {
4 | 
5 |   fun install()
6 | 
7 |   fun uninstall()
8 | }


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/java/leakcanary/internal/Applications.kt:
--------------------------------------------------------------------------------
1 | package leakcanary.internal
2 | 
3 | import android.app.Application
4 | import android.content.pm.ApplicationInfo
5 | 
6 | internal val Application.isDebuggableBuild: Boolean
7 |   get() = (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/java/leakcanary/internal/LeakCanaryDelegate.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import android.app.Application
 4 | import leakcanary.OnObjectRetainedListener
 5 | 
 6 | internal object LeakCanaryDelegate {
 7 | 
 8 |   @Suppress("UNCHECKED_CAST")
 9 |   val loadLeakCanary by lazy {
10 |     try {
11 |       val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
12 |       leakCanaryListener.getDeclaredField("INSTANCE")
13 |         .get(null) as (Application) -> Unit
14 |     } catch (ignored: Throwable) {
15 |       NoLeakCanary
16 |     }
17 |   }
18 | 
19 |   object NoLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
20 |     override fun invoke(application: Application) {
21 |     }
22 | 
23 |     override fun onObjectRetained() {
24 |     }
25 |   }
26 | }


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/java/leakcanary/internal/friendly/Friendly.kt:
--------------------------------------------------------------------------------
 1 | @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "NOTHING_TO_INLINE")
 2 | @file:JvmName("leakcanary-object-watcher-android_Friendly")
 3 | 
 4 | package leakcanary.internal.friendly
 5 | 
 6 | internal inline val mainHandler
 7 |   get() = leakcanary.internal.mainHandler
 8 | 
 9 | internal inline fun checkMainThread() = leakcanary.internal.checkMainThread()
10 | 
11 | internal inline fun <reified T : Any> noOpDelegate(): T = leakcanary.internal.noOpDelegate()
12 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/res/values/leak_canary_public.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <public name="leak_canary_watcher_watch_dismissed_dialogs" type="bool"/>
4 | </resources>
5 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/main/res/values/watcher_bools.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <!-- Whether to automatically install in the main process on startup via a custom ContentProvider.
4 |    If false, you need to call AppWatcher.manualInstall().
5 |    -->
6 |   <bool name="leak_canary_watcher_watch_dismissed_dialogs">false</bool>
7 | </resources>
8 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-core/src/test/java/leakcanary/AppWatcherTest.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import org.assertj.core.api.Assertions.assertThat
 4 | import org.junit.Test
 5 | 
 6 | class AppWatcherTest {
 7 | 
 8 |   @Test fun appWatcherLoads_notInstalled() {
 9 |     assertThat(AppWatcher.isInstalled)
10 |       .describedAs("Ensure AppWatcher doesn't crash in JUnit tests")
11 |       .isFalse()
12 |   }
13 | }
14 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-startup/api/object-watcher-android-startup.api:
--------------------------------------------------------------------------------
1 | public final class leakcanary/AppWatcherStartupInitializer : androidx/startup/Initializer {
2 | 	public fun <init> ()V
3 | 	public synthetic fun create (Landroid/content/Context;)Ljava/lang/Object;
4 | 	public fun create (Landroid/content/Context;)Lleakcanary/AppWatcherStartupInitializer;
5 | 	public fun dependencies ()Ljava/util/List;
6 | }
7 | 
8 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-startup/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.objectWatcher.objectWatcherAndroidCore)
 9 | 
10 |   implementation(libs.androidX.startup)
11 | }
12 | 
13 | android {
14 |   resourcePrefix = "leak_canary_watcher_"
15 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
16 |   defaultConfig {
17 |     minSdk = libs.versions.androidMinSdk.get().toInt()
18 |   }
19 |   buildFeatures.buildConfig = false
20 |   namespace = "com.squareup.leakcanary.objectwatcher.startup"
21 |   lint {
22 |     checkOnly += "Interoperability"
23 |     disable += "GoogleAppIndexingWarning"
24 |     error += "ObsoleteSdkInt"
25 |   }
26 | }
27 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-startup/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-object-watcher-android-startup
2 | POM_NAME=AndroidX Startup config for leakcanary-object-watcher-android-core
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-startup/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:tools="http://schemas.android.com/tools">
 4 |   <application>
 5 |     <provider
 6 |       android:name="androidx.startup.InitializationProvider"
 7 |       android:authorities="${applicationId}.androidx-startup"
 8 |       android:exported="false"
 9 |       tools:node="merge">
10 | 
11 |       <meta-data
12 |         android:name="leakcanary.AppWatcherStartupInitializer"
13 |         android:value="androidx.startup"/>
14 |     </provider>
15 | 
16 |   </application>
17 | </manifest>
18 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android-startup/src/main/java/leakcanary/AppWatcherStartupInitializer.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.app.Application
 4 | import android.content.Context
 5 | import androidx.startup.Initializer
 6 | 
 7 | class AppWatcherStartupInitializer : Initializer<AppWatcherStartupInitializer> {
 8 |   override fun create(context: Context) = apply {
 9 |     val application = context.applicationContext as Application
10 |     AppWatcher.manualInstall(application)
11 |   }
12 |   override fun dependencies() = emptyList<Class<out Initializer<*>>>()
13 | }
14 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/api/object-watcher-android.api:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/object-watcher/object-watcher-android/api/object-watcher-android.api


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.objectWatcher.objectWatcherAndroidCore)
 9 | }
10 | 
11 | android {
12 |   resourcePrefix = "leak_canary_watcher_"
13 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
14 | 
15 |   defaultConfig {
16 |     minSdk = libs.versions.androidMinSdk.get().toInt()
17 |     consumerProguardFiles("consumer-proguard-rules.pro")
18 |   }
19 | 
20 |   buildFeatures {
21 |     buildConfig = false
22 |   }
23 |   namespace = "com.squareup.leakcanary.objectwatcher"
24 |   lint {
25 |     checkOnly += "Interoperability"
26 |     disable += "GoogleAppIndexingWarning"
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # A ContentProvider that gets created by Android on startup
2 | -keep class leakcanary.internal.MainProcessAppWatcherInstaller { <init>(); }
3 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>ParameterListWrapping:MainProcessAppWatcherInstaller.kt$MainProcessAppWatcherInstaller$( uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array&lt;out String>? )</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-object-watcher-android
2 | POM_NAME=LeakCanary Object Watcher for Android - Auto installing
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <manifest
 3 |     xmlns:android="http://schemas.android.com/apk/res/android">
 4 | 
 5 |   <application>
 6 |     <provider
 7 |         android:name="leakcanary.internal.MainProcessAppWatcherInstaller"
 8 |         android:authorities="${applicationId}.leakcanary-installer"
 9 |         android:enabled="@bool/leak_canary_watcher_auto_install"
10 |         android:exported="false"/>
11 |   </application>
12 | </manifest>
13 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/src/main/res/values/leak_canary_public.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <public name="leak_canary_watcher_auto_install" type="bool"/>
4 | </resources>
5 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher-android/src/main/res/values/watcher_bools.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <!-- Whether to automatically install in the main process on startup via a custom ContentProvider.
4 |    If false, you need to call AppWatcher.manualInstall().
5 |    -->
6 |   <bool name="leak_canary_watcher_auto_install">true</bool>
7 | </resources>
8 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   implementation(libs.kotlin.stdlib)
13 |   api(projects.shark.sharkLog)
14 |   api(projects.leakcanary.leakcanaryGc)
15 | 
16 |   testImplementation(libs.assertjCore)
17 |   testImplementation(libs.junit)
18 | }
19 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>MultiLineIfElse:DeletableObjectReporter.kt$object : TrackedObjectReachability { override val isStronglyReachable: Boolean get() = false override val isRetained: Boolean get() = false }</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=leakcanary-object-watcher
2 | POM_NAME=LeakCanary Object Watcher
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/src/main/java/leakcanary/Clock.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | /**
 4 |  * An interface to abstract the SystemClock.uptimeMillis() Android API in non Android artifacts.
 5 |  *
 6 |  * This is a functional interface with which you can create a [Clock] from a lambda.
 7 |  */
 8 | @Deprecated("Use UptimeClock instead")
 9 | fun interface Clock {
10 |   /**
11 |    * On Android VMs, this should return android.os.SystemClock.uptimeMillis().
12 |    */
13 |   fun uptimeMillis(): Long
14 | }
15 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/src/main/java/leakcanary/DefaultDelayDeletableObjectReporter.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import kotlin.time.Duration
 4 | 
 5 | class DefaultDelayDeletableObjectReporter(
 6 |   /**
 7 |    * A significant enough delay for the GC to get a chance to run and update reachability status.
 8 |    */
 9 |   private val defaultDelay: Duration,
10 |   private val delayedReporter: DelayedDeletableObjectReporter
11 | ) : DeletableObjectReporter {
12 | 
13 |   override fun expectDeletionFor(
14 |     target: Any,
15 |     reason: String
16 |   ): TrackedObjectReachability {
17 |     return delayedReporter.expectDelayedDeletionFor(target, reason, defaultDelay)
18 |   }
19 | }
20 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/src/main/java/leakcanary/DelayedExecutor.kt:
--------------------------------------------------------------------------------
1 | package leakcanary
2 | 
3 | import kotlin.time.Duration
4 | 
5 | fun interface DelayedExecutor {
6 |   fun executeWithDelay(delayUptime: Duration, runnable: Runnable)
7 | }
8 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/src/main/java/leakcanary/OnObjectRetainedListener.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | /**
 4 |  * Listener used by [ReferenceQueueRetainedObjectTracker] to report retained objects.
 5 |  */
 6 | fun interface OnObjectRetainedListener {
 7 | 
 8 |   /**
 9 |    * A tracked object became retained.
10 |    */
11 |   fun onObjectRetained()
12 | }
13 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/src/main/java/leakcanary/TrackedObjectReachability.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | interface TrackedObjectReachability {
 4 |   /**
 5 |    * true if the tracked object is currently strongly reachable.
 6 |    */
 7 |   val isStronglyReachable: Boolean
 8 | 
 9 |   /**
10 |    * Whether this object is eligible for automatic garbage collection.
11 |    */
12 |   val isDeletable: Boolean
13 |     get() = !isStronglyReachable
14 | 
15 |   /**
16 |    * true if the track object has been marked as retained and is currently strongly reachable.
17 |    */
18 |   val isRetained: Boolean
19 | }
20 | 


--------------------------------------------------------------------------------
/object-watcher/object-watcher/src/main/java/leakcanary/UptimeClock.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import kotlin.time.Duration
 4 | 
 5 | /**
 6 |  * An interface to abstract the clock to get the system uptime.
 7 |  */
 8 | fun interface UptimeClock {
 9 |   /**
10 |    * On JVMs this should return [System.nanoTime] as a [Duration].
11 |    *
12 |    * On Android VMs, this should return either [System.nanoTime] on Android 11 (when the method
13 |    * was annotated with @CriticalNative) or [android.os.SystemClock.uptimeMillis()] before
14 |    * Android 11.
15 |    */
16 |   fun uptime(): Duration
17 | }
18 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.shark.sharkLog)
 9 |   api(projects.leakcanary.leakcanaryAndroidUtils)
10 | 
11 |   implementation(libs.kotlin.stdlib)
12 |   implementation(libs.curtains)
13 |   // Optional dependency
14 |   compileOnly(libs.androidX.fragment)
15 | }
16 | 
17 | android {
18 |   resourcePrefix = "leak_canary_plumber"
19 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
20 |   defaultConfig {
21 |     minSdk = libs.versions.androidMinSdk.get().toInt()
22 |     consumerProguardFiles("consumer-proguard-rules.pro")
23 |   }
24 |   buildFeatures.buildConfig = false
25 |   namespace = "com.squareup.leakcanary.plumber.core"
26 |   lint {
27 |     checkOnly += "Interoperability"
28 |     disable += "GoogleAppIndexingWarning"
29 |     error += "ObsoleteSdkInt"
30 |   }
31 | }
32 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Enum values are referenced reflectively in EnumSet initialization
2 | -keepclassmembers,allowoptimization enum leakcanary.AndroidLeakFixes {
3 |     public static **[] values();
4 | }
5 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>SafeCast:AndroidLeakFixes.kt$AndroidLeakFixes.Companion$if (it is HandlerThread) it else null</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=plumber-android-core
2 | POM_NAME=Plumber for Android - Core
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest />
3 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/src/main/java/leakcanary/internal/FragmentExtensions.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary.internal
 2 | 
 3 | import android.app.Activity
 4 | import androidx.fragment.app.Fragment
 5 | import androidx.fragment.app.FragmentActivity
 6 | import androidx.fragment.app.FragmentManager
 7 | 
 8 | private val hasAndroidXFragmentActivity: Boolean by lazy {
 9 |   try {
10 |     Class.forName("androidx.fragment.app.FragmentActivity")
11 |     true
12 |   } catch (ignored: Throwable) {
13 |     false
14 |   }
15 | }
16 | 
17 | internal fun Activity.onAndroidXFragmentViewDestroyed(block: () -> Unit) {
18 |   if (!hasAndroidXFragmentActivity) {
19 |     return
20 |   }
21 |   if (this is FragmentActivity) {
22 |     supportFragmentManager.registerFragmentLifecycleCallbacks(
23 |       object : FragmentManager.FragmentLifecycleCallbacks() {
24 |         override fun onFragmentViewDestroyed(
25 |           fm: FragmentManager,
26 |           fragment: Fragment
27 |         ) {
28 |           block()
29 |         }
30 |       }, true
31 |     )
32 |   }
33 | }
34 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-core/src/main/java/leakcanary/internal/friendly/Friendly.kt:
--------------------------------------------------------------------------------
 1 | @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "NOTHING_TO_INLINE")
 2 | @file:JvmName("plumber-android_Friendly")
 3 | 
 4 | package leakcanary.internal.friendly
 5 | 
 6 | import android.os.Handler
 7 | 
 8 | internal inline fun checkMainThread() = leakcanary.internal.checkMainThread()
 9 | 
10 | internal inline fun <reified T : Any> noOpDelegate(): T = leakcanary.internal.noOpDelegate()
11 | 
12 | internal inline val mainHandler: Handler
13 |   get() = leakcanary.internal.mainHandler
14 | 
15 | internal inline val isMainThread: Boolean
16 |   get() = leakcanary.internal.isMainThread
17 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-startup/api/plumber-android-startup.api:
--------------------------------------------------------------------------------
1 | public final class leakcanary/PlumberStartupInitializer : androidx/startup/Initializer {
2 | 	public fun <init> ()V
3 | 	public synthetic fun create (Landroid/content/Context;)Ljava/lang/Object;
4 | 	public fun create (Landroid/content/Context;)Lleakcanary/PlumberStartupInitializer;
5 | 	public fun dependencies ()Ljava/util/List;
6 | }
7 | 
8 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-startup/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.plumber.plumberAndroidCore)
 9 | 
10 |   implementation(libs.kotlin.stdlib)
11 |   implementation(libs.androidX.startup)
12 | }
13 | 
14 | android {
15 |   resourcePrefix = "leak_canary_plumber"
16 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
17 |   defaultConfig {
18 |     minSdk = libs.versions.androidMinSdk.get().toInt()
19 |   }
20 |   buildFeatures.buildConfig = false
21 |   namespace = "com.squareup.leakcanary.plumber.startup"
22 |   lint {
23 |     checkOnly += "Interoperability"
24 |     disable += "GoogleAppIndexingWarning"
25 |     error += "ObsoleteSdkInt"
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-startup/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=plumber-android-startup
2 | POM_NAME=AndroidX Startup config for plumber-android-core
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-startup/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:tools="http://schemas.android.com/tools">
 4 |   <application>
 5 |     <provider
 6 |       android:name="androidx.startup.InitializationProvider"
 7 |       android:authorities="${applicationId}.androidx-startup"
 8 |       android:exported="false"
 9 |       tools:node="merge">
10 | 
11 |       <meta-data
12 |         android:name="leakcanary.PlumberStartupInitializer"
13 |         android:value="androidx.startup"/>
14 |     </provider>
15 | 
16 |   </application>
17 | </manifest>
18 | 


--------------------------------------------------------------------------------
/plumber/plumber-android-startup/src/main/java/leakcanary/PlumberStartupInitializer.kt:
--------------------------------------------------------------------------------
 1 | package leakcanary
 2 | 
 3 | import android.app.Application
 4 | import android.content.Context
 5 | import androidx.startup.Initializer
 6 | 
 7 | class PlumberStartupInitializer : Initializer<PlumberStartupInitializer> {
 8 |   override fun create(context: Context) = apply {
 9 |     val application = context.applicationContext as Application
10 |     AndroidLeakFixes.applyFixes(application)
11 |   }
12 |   override fun dependencies() = emptyList<Class<out Initializer<*>>>()
13 | }
14 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/api/plumber-android.api:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/plumber/plumber-android/api/plumber-android.api


--------------------------------------------------------------------------------
/plumber/plumber-android/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("com.android.library")
 3 |   id("org.jetbrains.kotlin.android")
 4 |   id("com.vanniktech.maven.publish")
 5 | }
 6 | 
 7 | dependencies {
 8 |   api(projects.plumber.plumberAndroidCore)
 9 | 
10 |   implementation(libs.kotlin.stdlib)
11 | }
12 | 
13 | android {
14 |   resourcePrefix = "leak_canary_plumber"
15 |   compileSdk = libs.versions.androidCompileSdk.get().toInt()
16 |   defaultConfig {
17 |     minSdk = libs.versions.androidMinSdk.get().toInt()
18 |     consumerProguardFiles("consumer-proguard-rules.pro")
19 |   }
20 |   buildFeatures.buildConfig = false
21 |   namespace = "com.squareup.leakcanary.plumber"
22 |   lint {
23 |     checkOnly += "Interoperability"
24 |     disable += "GoogleAppIndexingWarning"
25 |     error += "ObsoleteSdkInt"
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # A ContentProvider that gets created by Android on startup
2 | -keep class leakcanary.internal.PlumberInstaller { <init>(); }
3 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>ParameterListWrapping:PlumberInstaller.kt$PlumberInstaller$( uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array&lt;out String>? )</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=plumber-android
2 | POM_NAME=Auto installer for plumber-android-core
3 | POM_PACKAGING=aar
4 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android">
 3 |   <application>
 4 |     <provider
 5 |         android:name="leakcanary.internal.PlumberInstaller"
 6 |         android:authorities="${applicationId}.plumber-installer"
 7 |         android:enabled="@bool/leak_canary_plumber_auto_install"
 8 |         android:exported="false" />
 9 |   </application>
10 | </manifest>
11 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/src/main/res/values/plumber_bools.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <bool name="leak_canary_plumber_auto_install">true</bool>
4 | </resources>
5 | 


--------------------------------------------------------------------------------
/plumber/plumber-android/src/main/res/values/plumber_public.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2015 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <resources>
18 | 
19 |   <public name="leak_canary_plumber_auto_install" type="bool"/>
20 | </resources>
21 | 


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>FinalNewline:LeakingService.kt$com.example.leakcanary.LeakingService.kt</ID>
 6 |     <ID>FinalNewline:LeakingSingleton.kt$com.example.leakcanary.LeakingSingleton.kt</ID>
 7 |     <ID>FinalNewline:LeakingThread.kt$com.example.leakcanary.LeakingThread.kt</ID>
 8 |   </CurrentIssues>
 9 | </SmellBaseline>
10 | 


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <!--
 3 |   ~ Copyright (C) 2018 Square, Inc.
 4 |   ~
 5 |   ~ Licensed under the Apache License, Version 2.0 (the "License");
 6 |   ~ you may not use this file except in compliance with the License.
 7 |   ~ You may obtain a copy of the License at
 8 |   ~
 9 |   ~      http://www.apache.org/licenses/LICENSE-2.0
10 |   ~
11 |   ~ Unless required by applicable law or agreed to in writing, software
12 |   ~ distributed under the License is distributed on an "AS IS" BASIS,
13 |   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |   ~ See the License for the specific language governing permissions and
15 |   ~ limitations under the License.
16 |   -->
17 | <manifest>
18 | </manifest>
19 | 


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     xmlns:tools="http://schemas.android.com/tools">
5 |   <application
6 |       tools:replace="android:name"
7 |       android:name=".DebugExampleApplication" />
8 | </manifest>
9 | 


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/debug/java/com/example/leakcanary/DebugExampleApplication.kt:
--------------------------------------------------------------------------------
 1 | package com.example.leakcanary
 2 | 
 3 | import leakcanary.EventListener
 4 | import leakcanary.EventListener.Event.HeapAnalysisDone
 5 | import leakcanary.LeakCanary
 6 | import org.leakcanary.internal.LeakUiAppClient
 7 | 
 8 | class DebugExampleApplication : ExampleApplication() {
 9 | 
10 |   override fun onCreate() {
11 |     super.onCreate()
12 | 
13 |     // TODO We need to decide whether to show the activity icon based on whether
14 |     //  the app library is here (?). Though ideally the embedded activity is also a separate
15 |     //  optional module.
16 |     LeakCanary.config = LeakCanary.config.run {
17 |       copy(eventListeners = eventListeners + EventListener {
18 |         // TODO Move this into an EventListener class, maybe the standard one
19 |         //  TODO Detect if app installed or not and delegate to std leakcanary if not.
20 |         if (it is HeapAnalysisDone<*>) {
21 |           LeakUiAppClient(this@DebugExampleApplication).sendHeapAnalysis(it.heapAnalysis)
22 |         }
23 |       })
24 |     }
25 |   }
26 | }
27 | 


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/java/com/example/leakcanary/LeakingService.kt:
--------------------------------------------------------------------------------
 1 | package com.example.leakcanary
 2 | 
 3 | import android.app.Service
 4 | import android.content.Intent
 5 | import android.os.IBinder
 6 | 
 7 | class LeakingService : Service() {
 8 | 
 9 |   override fun onCreate() {
10 |     super.onCreate()
11 |     (application as ExampleApplication).leakedServices += this
12 |     stopSelf()
13 |   }
14 | 
15 |   override fun onBind(intent: Intent?): IBinder? {
16 |     return null
17 |   }
18 | }


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/java/com/example/leakcanary/LeakingSingleton.kt:
--------------------------------------------------------------------------------
1 | package com.example.leakcanary
2 | 
3 | import android.view.View
4 | 
5 | object LeakingSingleton {
6 |   val leakedViews = mutableListOf<View>()
7 | }


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/java/com/example/leakcanary/LeakingThread.kt:
--------------------------------------------------------------------------------
 1 | package com.example.leakcanary
 2 | 
 3 | import android.view.View
 4 | 
 5 | class LeakingThread : Thread() {
 6 | 
 7 |   val leakedViews = mutableListOf<View>()
 8 | 
 9 |   init {
10 |     name = "Leaking thread"
11 |     start()
12 |   }
13 | 
14 |   override fun run() {
15 |     synchronized(obj) {
16 |       obj.wait()
17 |     }
18 |   }
19 | 
20 |   companion object {
21 |     private val obj = Object()
22 |     val thread = LeakingThread()
23 |   }
24 | }


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/res/drawable/leak_canary_sample_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/samples/leakcanary-android-sample/src/main/res/drawable/leak_canary_sample_icon.png


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/samples/leakcanary-android-sample/src/main/res/mipmap-hdpi/ic_launcher.png


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/samples/leakcanary-android-sample/src/main/res/mipmap-mdpi/ic_launcher.png


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/samples/leakcanary-android-sample/src/main/res/mipmap-xhdpi/ic_launcher.png


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/samples/leakcanary-android-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/samples/leakcanary-android-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png


--------------------------------------------------------------------------------
/samples/leakcanary-android-sample/src/release/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <manifest
3 |     xmlns:android="http://schemas.android.com/apk/res/android"
4 |     xmlns:tools="http://schemas.android.com/tools">
5 |   <application
6 |       tools:replace="android:name"
7 |       android:name=".ReleaseExampleApplication" />
8 | </manifest>
9 | 


--------------------------------------------------------------------------------
/shark-cli.sh:
--------------------------------------------------------------------------------
1 | ./gradlew --quiet --no-configuration-cache :shark:shark-cli:installDist
2 | ./shark/shark-cli/build/install/shark-cli/bin/shark-cli "$@"
3 | 


--------------------------------------------------------------------------------
/shark/shark-android/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   api(projects.shark.shark)
13 | 
14 |   implementation(libs.kotlin.stdlib)
15 | 
16 |   testImplementation(libs.assertjCore)
17 |   testImplementation(libs.junit)
18 |   testImplementation(libs.kotlinStatistics)
19 |   testImplementation(libs.mockito)
20 |   testImplementation(libs.mockitoKotlin)
21 |   testImplementation(libs.okio2)
22 |   testImplementation(projects.shark.sharkTest)
23 |   testImplementation(projects.shark.sharkHprofTest)
24 | }
25 | 


--------------------------------------------------------------------------------
/shark/shark-android/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=shark-android
2 | POM_NAME=Shark for Android heaps
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/shark/shark-android/src/main/java/shark/AndroidObjectGrowthDetector.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | fun ObjectGrowthDetector.Companion.forAndroidHeap(
 4 |   referenceMatchers: List<ReferenceMatcher> = AndroidObjectGrowthReferenceMatchers.defaults
 5 | ): ObjectGrowthDetector {
 6 |   return ObjectGrowthDetector(
 7 |     gcRootProvider = MatchingGcRootProvider(referenceMatchers),
 8 |     referenceReaderFactory = AndroidReferenceReaderFactory(referenceMatchers)
 9 |   )
10 | }
11 | 


--------------------------------------------------------------------------------
/shark/shark-android/src/main/java/shark/AndroidServices.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | object AndroidServices {
 4 |   val HeapGraph.aliveAndroidServiceObjectIds: List<Long>
 5 |     get() {
 6 |       return context.getOrPut(AndroidServices::class.java.name) {
 7 |         val activityThreadClass = findClassByName("android.app.ActivityThread")!!
 8 |         val currentActivityThread = activityThreadClass
 9 |           .readStaticField("sCurrentActivityThread")!!
10 |           .valueAsInstance!!
11 | 
12 |         val mServices = currentActivityThread["android.app.ActivityThread", "mServices"]!!
13 |           .valueAsInstance!!
14 | 
15 |         val servicesArray = mServices["android.util.ArrayMap", "mArray"]!!.valueAsObjectArray!!
16 | 
17 |         servicesArray.readElements()
18 |           .filterIndexed { index, heapValue ->
19 |             // ArrayMap<IBinder, Service>
20 |             // even: key, odd: value
21 |             index % 2 == 1
22 |               && heapValue.isNonNullReference
23 |           }
24 |           .map { it.asNonNullObjectId!! }
25 |           .toList()
26 |       }
27 |     }
28 | }


--------------------------------------------------------------------------------
/shark/shark-android/src/main/java/shark/internal/friendly/Friendly.kt:
--------------------------------------------------------------------------------
 1 | @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
 2 | @file:JvmName("shark-android_Friendly")
 3 | 
 4 | package shark.internal.friendly
 5 | 
 6 | import shark.AndroidNativeSizeMapper
 7 | import shark.HeapGraph
 8 | 
 9 | internal inline fun HeapGraph.mapNativeSizes() =
10 |   AndroidNativeSizeMapper.mapNativeSizes(this)
11 | 


--------------------------------------------------------------------------------
/shark/shark-android/src/main/resources/META-INF/proguard/shark.pro:
--------------------------------------------------------------------------------
1 | # Used during heap analysis to find resource id names
2 | -keep class shark.AndroidResourceIdNames { *; }
3 | 


--------------------------------------------------------------------------------
/shark/shark-android/src/test/java/shark/Resources.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import java.io.File
 4 | 
 5 | fun String.classpathFile(): File {
 6 |   val classLoader = Thread.currentThread()
 7 |     .contextClassLoader
 8 |   val url = classLoader.getResource(this)!!
 9 |   return File(url.path)
10 | }


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/compose_leak.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/compose_leak.hprof


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/gc_root_in_non_primary_heap.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/gc_root_in_non_primary_heap.hprof


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/gcroot_unknown_object.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/gcroot_unknown_object.hprof


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/leak_asynctask_m.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/leak_asynctask_m.hprof


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/leak_asynctask_o.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/leak_asynctask_o.hprof


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/leak_asynctask_pre_m.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/leak_asynctask_pre_m.hprof


--------------------------------------------------------------------------------
/shark/shark-android/src/test/resources/unloaded_classes-stripped.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark-android/src/test/resources/unloaded_classes-stripped.hprof


--------------------------------------------------------------------------------
/shark/shark-cli/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>FinalNewline:DeobfuscateHprofCommand.kt$shark.DeobfuscateHprofCommand.kt</ID>
 6 |     <ID>FinalNewline:StripHprofCommand.kt$shark.StripHprofCommand.kt</ID>
 7 |     <ID>MaximumLineLength:DumpProcessCommand.kt$DumpProcessCommand.Companion$ </ID>
 8 |     <ID>MaximumLineLength:HeapGrowthCommand.kt$HeapGrowthCommand$ </ID>
 9 |     <ID>MaximumLineLength:StripHprofCommand.kt$StripHprofCommand$ </ID>
10 |     <ID>MultiLineIfElse:InteractiveCommand.kt$InteractiveCommand
quot;"</ID>
11 |     <ID>NoConsecutiveBlankLines:Neo4JCommand.kt$ </ID>
12 |     <ID>NoConsecutiveBlankLines:Neo4JCommand.kt$Neo4JCommand.Companion$ </ID>
13 |     <ID>SpacingAroundParens:HeapGrowthCommand.kt$HeapGrowthCommand$(</ID>
14 |     <ID>StringTemplate:InteractiveCommand.kt$InteractiveCommand${instanceCount}</ID>
15 |   </CurrentIssues>
16 | </SmellBaseline>
17 | 


--------------------------------------------------------------------------------
/shark/shark-cli/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=shark-cli
2 | POM_NAME=Shark Command Line Interface
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/shark/shark-cli/src/main/java/shark/DeobfuscateHprofCommand.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import com.github.ajalt.clikt.core.CliktCommand
 4 | import com.github.ajalt.clikt.core.PrintMessage
 5 | import shark.SharkCliCommand.Companion.retrieveHeapDumpFile
 6 | import shark.SharkCliCommand.Companion.sharkCliParams
 7 | 
 8 | class DeobfuscateHprofCommand : CliktCommand(
 9 |   name = "deobfuscate-hprof",
10 |   help = "Deobfuscate the provided heap dump and generate a new \"-deobfuscated.hprof\" file."
11 | ) {
12 | 
13 |   override fun run() {
14 |     val params = context.sharkCliParams
15 |     val obfuscationMappingFile = params.obfuscationMappingPath
16 |       ?: throw PrintMessage("Error: Missing obfuscation mapping file")
17 |     val heapDumpFile = retrieveHeapDumpFile(params)
18 |     SharkLog.d { "Deobfuscating heap dump $heapDumpFile" }
19 |     val proguardMapping =
20 |       ProguardMappingReader(obfuscationMappingFile.inputStream()).readProguardMapping()
21 |     val deobfuscator = HprofDeobfuscator()
22 |     val outputFile = deobfuscator.deobfuscate(proguardMapping, heapDumpFile)
23 |     echo("Created deobfuscated hprof to $outputFile")
24 |   }
25 | }


--------------------------------------------------------------------------------
/shark/shark-cli/src/main/java/shark/Main.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import com.github.ajalt.clikt.core.subcommands
 4 | 
 5 | fun main(args: Array<String>) =
 6 |   SharkCliCommand().subcommands(
 7 |     InteractiveCommand(),
 8 |     AnalyzeCommand(),
 9 |     Neo4JCommand(),
10 |     DumpProcessCommand(),
11 |     StripHprofCommand(),
12 |     DeobfuscateHprofCommand(),
13 |     HeapGrowthCommand()
14 |   ).main(args)
15 | 


--------------------------------------------------------------------------------
/shark/shark-cli/src/main/java/shark/StripHprofCommand.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import com.github.ajalt.clikt.core.CliktCommand
 4 | import shark.SharkCliCommand.Companion.retrieveHeapDumpFile
 5 | import shark.SharkCliCommand.Companion.sharkCliParams
 6 | 
 7 | class StripHprofCommand : CliktCommand(
 8 |   name = "strip-hprof",
 9 |   help = "Replace all primitive arrays from the provided heap dump with arrays of zeroes and generate a new \"-stripped.hprof\" file."
10 | ) {
11 | 
12 |   override fun run() {
13 |     val heapDumpFile = retrieveHeapDumpFile(context.sharkCliParams)
14 |     SharkLog.d { "Stripping primitive arrays in heap dump $heapDumpFile" }
15 |     val stripper = HprofPrimitiveArrayStripper()
16 |     val outputFile = stripper.stripPrimitiveArrays(heapDumpFile)
17 |     echo("Created hprof with stripped primitive arrays to $outputFile")
18 |   }
19 | }


--------------------------------------------------------------------------------
/shark/shark-graph/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   api(projects.shark.sharkHprof)
13 |   api(libs.androidX.collections)
14 | 
15 |   implementation(libs.kotlin.stdlib)
16 |   implementation(libs.okio2)
17 | 
18 |   testImplementation(libs.assertjCore)
19 |   testImplementation(libs.junit)
20 |   testImplementation(projects.shark.sharkTest)
21 |   testImplementation(projects.shark.sharkHprofTest)
22 | }
23 | 


--------------------------------------------------------------------------------
/shark/shark-graph/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=shark-graph
2 | POM_NAME=Shark Graph
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/shark/shark-graph/src/main/java/shark/CloseableHeapGraph.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | import java.io.Closeable
4 | 
5 | /**
6 |  * A [HeapGraph] that should be closed after being used.
7 |  */
8 | interface CloseableHeapGraph : HeapGraph, Closeable


--------------------------------------------------------------------------------
/shark/shark-graph/src/main/java/shark/internal/aosp/ByteArrayComparator.kt:
--------------------------------------------------------------------------------
 1 | package shark.internal.aosp
 2 | 
 3 | internal fun interface ByteArrayComparator {
 4 | 
 5 |   /**
 6 |    * Indexes are divided by entrySize
 7 |    */
 8 |   fun compare(
 9 |     entrySize: Int,
10 |     o1Array: ByteArray,
11 |     o1Index: Int,
12 |     o2Array: ByteArray,
13 |     o2Index: Int
14 |   ): Int
15 | }
16 | 


--------------------------------------------------------------------------------
/shark/shark-graph/src/main/java/shark/internal/hppc/Tuples.kt:
--------------------------------------------------------------------------------
 1 | package shark.internal.hppc
 2 | 
 3 | /** Alternative to Pair<Long, Object> that doesn't box long.*/
 4 | internal data class LongObjectPair<out B>(
 5 |   val first: Long,
 6 |   val second: B
 7 | )
 8 | 
 9 | /** Alternative to Pair<Int, Object> that doesn't box int.*/
10 | internal data class IntObjectPair<out B>(
11 |   val first: Int,
12 |   val second: B
13 | )
14 | 
15 | /** Alternative to Pair<Long, Long> that doesn't box longs. */
16 | internal data class LongLongPair(
17 |   val first: Long,
18 |   val second: Long
19 | )
20 | 
21 | internal infix fun <B> Long.to(that: B): LongObjectPair<B> = LongObjectPair(this, that)
22 | 
23 | internal infix fun <B> Int.to(that: B): IntObjectPair<B> = IntObjectPair(this, that)
24 | 
25 | internal infix fun Long.to(that: Long): LongLongPair = LongLongPair(this, that)
26 | 


--------------------------------------------------------------------------------
/shark/shark-hprof-test/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 | }
 4 | 
 5 | java {
 6 |   sourceCompatibility = JavaVersion.VERSION_1_8
 7 |   targetCompatibility = JavaVersion.VERSION_1_8
 8 | }
 9 | 
10 | dependencies {
11 |     implementation(libs.kotlin.stdlib)
12 |     implementation(libs.junit)
13 |     implementation(libs.okio2)
14 | 
15 |     implementation(projects.shark.sharkHprof)
16 | }
17 | 


--------------------------------------------------------------------------------
/shark/shark-hprof-test/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>FinalNewline:ProguardMappingHelper.kt$shark.ProguardMappingHelper.kt</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/shark/shark-hprof-test/src/main/kotlin/shark/ProguardMappingHelper.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | class ProguardMappingHelper(
 4 |   private val proguardMapping: ProguardMapping
 5 | ) {
 6 |   fun clazz(
 7 |     className: Pair<String, String>,
 8 |     fieldsBlock: Class.() -> Unit = {}
 9 |   ) {
10 |     val clazz = Class(className)
11 |     fieldsBlock(clazz)
12 |     proguardMapping.addMapping(clazz.nameMapping.second, clazz.nameMapping.first)
13 |     clazz.fieldMappings.forEach { field ->
14 |       proguardMapping.addMapping("${clazz.nameMapping.second}.${field.second}", field.first)
15 |     }
16 |   }
17 | 
18 |   inner class Class(val nameMapping: Pair<String, String>) {
19 |     val fieldMappings = mutableSetOf<Pair<String, String>>()
20 |   }
21 | 
22 |   fun Class.field(block: () -> Pair<String, String>) {
23 |     fieldMappings.add(block())
24 |   }
25 | }
26 | 
27 | fun ProguardMapping.create(block: ProguardMappingHelper.() -> Unit): ProguardMapping {
28 |   block(ProguardMappingHelper(this))
29 |   return this
30 | }


--------------------------------------------------------------------------------
/shark/shark-hprof/detekt-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version='1.0' encoding='UTF-8'?>
 2 | <SmellBaseline>
 3 |   <ManuallySuppressedIssues/>
 4 |   <CurrentIssues>
 5 |     <ID>FinalNewline:ConstantMemoryMetricsDualSourceProvider.kt$shark.ConstantMemoryMetricsDualSourceProvider.kt</ID>
 6 |     <ID>FinalNewline:GcRoot.kt$shark.GcRoot.kt</ID>
 7 |     <ID>FinalNewline:ProguardMappingReader.kt$shark.ProguardMappingReader.kt</ID>
 8 |     <ID>FinalNewline:ProguardMappingTest.kt$shark.ProguardMappingTest.kt</ID>
 9 |     <ID>FinalNewline:RandomAccessHprofReader.kt$shark.RandomAccessHprofReader.kt</ID>
10 |     <ID>FinalNewline:ValueHolder.kt$shark.ValueHolder.kt</ID>
11 |     <ID>NoConsecutiveBlankLines:ConstantMemoryMetricsDualSourceProvider.kt$ConstantMemoryMetricsDualSourceProvider$ </ID>
12 |     <ID>NoConsecutiveBlankLines:FileSourceProvider.kt$ </ID>
13 |     <ID>NoMultipleSpaces:HprofReaderPrimitiveArrayTest.kt$HprofReaderPrimitiveArrayTest$ </ID>
14 |     <ID>NoUnusedImports:ThrowingCancelableFileSourceProvider.kt$shark.ThrowingCancelableFileSourceProvider.kt</ID>
15 |   </CurrentIssues>
16 | </SmellBaseline>
17 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=shark-hprof
2 | POM_NAME=Shark Hprof
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/ByteArraySourceProvider.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import java.io.IOException
 4 | import okio.Buffer
 5 | import okio.BufferedSource
 6 | 
 7 | class ByteArraySourceProvider(private val byteArray: ByteArray) : DualSourceProvider {
 8 |   override fun openStreamingSource(): BufferedSource = Buffer().apply { write(byteArray) }
 9 | 
10 |   override fun openRandomAccessSource(): RandomAccessSource {
11 |     return object : RandomAccessSource {
12 | 
13 |       var closed = false
14 | 
15 |       override fun read(
16 |         sink: Buffer,
17 |         position: Long,
18 |         byteCount: Long
19 |       ): Long {
20 |         if (closed) {
21 |           throw IOException("Source closed")
22 |         }
23 |         val maxByteCount = byteCount.coerceAtMost(byteArray.size - position)
24 |         sink.write(byteArray, position.toInt(), maxByteCount.toInt())
25 |         return maxByteCount
26 |       }
27 | 
28 |       override fun close() {
29 |         closed = true
30 |       }
31 |     }
32 |   }
33 | }
34 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/DualSourceProvider.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | /**
4 |  * Both a [StreamingSourceProvider] and a [RandomAccessSourceProvider]
5 |  */
6 | interface DualSourceProvider : StreamingSourceProvider, RandomAccessSourceProvider
7 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/HprofVersion.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Supported hprof versions
 5 |  */
 6 | enum class HprofVersion(val versionString: String) {
 7 |   JDK1_2_BETA3("JAVA PROFILE 1.0"),
 8 |   JDK1_2_BETA4("JAVA PROFILE 1.0.1"),
 9 |   JDK_6("JAVA PROFILE 1.0.2"),
10 |   ANDROID("JAVA PROFILE 1.0.3")
11 | }
12 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/OnHprofRecordListener.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Listener passed in to [StreamingRecordReaderAdapter.readRecords], gets notified for each [HprofRecord]
 5 |  * found in the heap dump which types is in the set of the recordTypes parameter passed to
 6 |  * [StreamingRecordReaderAdapter.readRecords].
 7 |  */
 8 | fun interface OnHprofRecordListener {
 9 |   fun onHprofRecord(
10 |     /**
11 |      * The position of the record in the underlying hprof file.
12 |      */
13 |     position: Long,
14 |     record: HprofRecord
15 |   )
16 | }
17 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/OnHprofRecordTagListener.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Listener passed in to [StreamingHprofReader.readRecords], gets notified for each
 5 |  * [HprofRecordTag] found in the heap dump.
 6 |  *
 7 |  * Listener implementations are expected to read all bytes corresponding to a given tag from the
 8 |  * provided reader before returning.
 9 |  */
10 | fun interface OnHprofRecordTagListener {
11 |   fun onHprofRecord(
12 |     tag: HprofRecordTag,
13 |     /**
14 |      * Length of the record or -1 if there is the length is not known
15 |      */
16 |     length: Long,
17 |     reader: HprofRecordReader
18 |   )
19 | }
20 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/PrimitiveType.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * A primitive type in the prof.
 5 |  */
 6 | enum class PrimitiveType(
 7 |   /**
 8 |    * The hprof defined "basic type".
 9 |    */
10 |   val hprofType: Int,
11 |   /**
12 |    * The size in bytes for each value of that type.
13 |    */
14 |   val byteSize: Int
15 | ) {
16 |   BOOLEAN(4, 1),
17 |   CHAR(5, 2),
18 |   FLOAT(6, 4),
19 |   DOUBLE(7, 8),
20 |   BYTE(8, 1),
21 |   SHORT(9, 2),
22 |   INT(10, 4),
23 |   LONG(11, 8);
24 | 
25 |   companion object {
26 |     /**
27 |      * The hprof defined "basic type" for references.
28 |      */
29 |     const val REFERENCE_HPROF_TYPE = 2
30 | 
31 |     val byteSizeByHprofType = values().associate { it.hprofType to it.byteSize }
32 | 
33 |     val primitiveTypeByHprofType = values().associateBy { it.hprofType }
34 |   }
35 | }
36 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/RandomAccessSourceProvider.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | /**
4 |  * Can open [RandomAccessSource] instances.
5 |  */
6 | fun interface RandomAccessSourceProvider {
7 |   fun openRandomAccessSource(): RandomAccessSource
8 | }
9 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/StreamingSourceProvider.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import okio.BufferedSource
 4 | import okio.Source
 5 | 
 6 | /**
 7 |  * Can open [Source] instances.
 8 |  */
 9 | fun interface StreamingSourceProvider {
10 |   fun openStreamingSource(): BufferedSource
11 | }
12 | 


--------------------------------------------------------------------------------
/shark/shark-hprof/src/main/java/shark/ValueHolder.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import shark.ValueHolder.ReferenceHolder
 4 | 
 5 | /**
 6 |  * A value in the heap dump, which can be a [ReferenceHolder] or
 7 |  * a primitive type.
 8 |  */
 9 | sealed class ValueHolder {
10 |   data class ReferenceHolder(val value: Long) : ValueHolder() {
11 |     val isNull
12 |       get() = value == NULL_REFERENCE
13 |   }
14 | 
15 |   data class BooleanHolder(val value: Boolean) : ValueHolder()
16 |   data class CharHolder(val value: Char) : ValueHolder()
17 |   data class FloatHolder(val value: Float) : ValueHolder()
18 |   data class DoubleHolder(val value: Double) : ValueHolder()
19 |   data class ByteHolder(val value: Byte) : ValueHolder()
20 |   data class ShortHolder(val value: Short) : ValueHolder()
21 |   data class IntHolder(val value: Int) : ValueHolder()
22 |   data class LongHolder(val value: Long) : ValueHolder()
23 | 
24 |   companion object {
25 |     const val NULL_REFERENCE = 0L
26 |   }
27 | }


--------------------------------------------------------------------------------
/shark/shark-log/api/shark-log.api:
--------------------------------------------------------------------------------
 1 | public final class shark/SharkLog {
 2 | 	public static final field INSTANCE Lshark/SharkLog;
 3 | 	public final fun d (Ljava/lang/Throwable;Lkotlin/jvm/functions/Function0;)V
 4 | 	public final fun d (Lkotlin/jvm/functions/Function0;)V
 5 | 	public final fun getLogger ()Lshark/SharkLog$Logger;
 6 | 	public final fun setLogger (Lshark/SharkLog$Logger;)V
 7 | }
 8 | 
 9 | public abstract interface class shark/SharkLog$Logger {
10 | 	public abstract fun d (Ljava/lang/String;)V
11 | 	public abstract fun d (Ljava/lang/Throwable;Ljava/lang/String;)V
12 | }
13 | 
14 | 


--------------------------------------------------------------------------------
/shark/shark-log/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   implementation(libs.kotlin.stdlib)
13 | 
14 |   testImplementation(libs.assertjCore)
15 |   testImplementation(libs.junit)
16 | }
17 | 


--------------------------------------------------------------------------------
/shark/shark-log/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>FinalNewline:SharkLogTest.kt$shark.SharkLogTest.kt</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/shark/shark-log/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=shark-log
2 | POM_NAME=Shark Log
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/shark/shark-test/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 | }
 4 | 
 5 | java {
 6 |   sourceCompatibility = JavaVersion.VERSION_1_8
 7 |   targetCompatibility = JavaVersion.VERSION_1_8
 8 | }
 9 | 
10 | dependencies {
11 |     implementation(libs.kotlin.stdlib)
12 |     implementation(libs.assertjCore)
13 |     implementation(libs.junit)
14 | }
15 | 
16 | 


--------------------------------------------------------------------------------
/shark/shark-test/detekt-baseline.xml:
--------------------------------------------------------------------------------
1 | <?xml version='1.0' encoding='UTF-8'?>
2 | <SmellBaseline>
3 |   <ManuallySuppressedIssues/>
4 |   <CurrentIssues>
5 |     <ID>FinalNewline:JvmTestHeapDumper.kt$shark.JvmTestHeapDumper.kt</ID>
6 |   </CurrentIssues>
7 | </SmellBaseline>
8 | 


--------------------------------------------------------------------------------
/shark/shark-test/src/main/kotlin/shark/HeapDumpRule.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import org.junit.rules.ExternalResource
 4 | import org.junit.rules.TemporaryFolder
 5 | import java.io.File
 6 | import java.io.IOException
 7 | import java.util.UUID
 8 | 
 9 | class HeapDumpRule : ExternalResource() {
10 |   private val temporaryFolder = TemporaryFolder()
11 | 
12 |   @Throws(Throwable::class)
13 |   override fun before() {
14 |     temporaryFolder.create()
15 |   }
16 | 
17 |   override fun after() {
18 |     temporaryFolder.delete()
19 |   }
20 | 
21 |   @Throws(IOException::class)
22 |   fun dumpHeap(): File {
23 |     val hprof = File(temporaryFolder.root, "heapDump" + UUID.randomUUID() + ".hprof")
24 |     JvmTestHeapDumper.dumpHeap(hprof.absolutePath)
25 |     return hprof
26 |   }
27 | }
28 | 


--------------------------------------------------------------------------------
/shark/shark-test/src/main/kotlin/shark/JvmTestHeapDumper.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import com.sun.management.HotSpotDiagnosticMXBean
 4 | import java.lang.management.ManagementFactory
 5 | 
 6 | object JvmTestHeapDumper {
 7 |   private val hotspotMBean: HotSpotDiagnosticMXBean by lazy {
 8 |     val mBeanServer = ManagementFactory.getPlatformMBeanServer()
 9 |     ManagementFactory.newPlatformMXBeanProxy(
10 |       mBeanServer,
11 |       "com.sun.management:type=HotSpotDiagnostic",
12 |       HotSpotDiagnosticMXBean::class.java
13 |     )
14 |   }
15 | 
16 |   fun dumpHeap(
17 |     fileName: String
18 |   ) {
19 |     val live = true
20 |     hotspotMBean.dumpHeap(fileName, live)
21 |   }
22 | }


--------------------------------------------------------------------------------
/shark/shark/build.gradle.kts:
--------------------------------------------------------------------------------
 1 | plugins {
 2 |   id("org.jetbrains.kotlin.jvm")
 3 |   id("com.vanniktech.maven.publish")
 4 | }
 5 | 
 6 | java {
 7 |   sourceCompatibility = JavaVersion.VERSION_1_8
 8 |   targetCompatibility = JavaVersion.VERSION_1_8
 9 | }
10 | 
11 | dependencies {
12 |   api(projects.shark.sharkGraph)
13 | 
14 |   implementation(libs.coroutines.core)
15 |   implementation(libs.kotlin.stdlib)
16 |   implementation(libs.okio2)
17 | 
18 |   testImplementation(libs.assertjCore)
19 |   testImplementation(libs.junit)
20 |   testImplementation(projects.shark.sharkTest)
21 |   testImplementation(projects.shark.sharkHprofTest)
22 | }
23 | 


--------------------------------------------------------------------------------
/shark/shark/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=shark
2 | POM_NAME=Shark
3 | POM_PACKAGING=jar
4 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/ActualMatchingReferenceReaderFactory.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Creates [ReferenceReader] instances that will follow references from all [HeapObject]s,
 5 |  * applying matching rules provided by [referenceMatchers], and not creating any virtual reference.
 6 |  */
 7 | class ActualMatchingReferenceReaderFactory(
 8 |   private val referenceMatchers: List<ReferenceMatcher>
 9 | ) : ReferenceReader.Factory<HeapObject> {
10 |   override fun createFor(heapGraph: HeapGraph): ReferenceReader<HeapObject> {
11 |     return DelegatingObjectReferenceReader(
12 |       classReferenceReader = ClassReferenceReader(heapGraph, referenceMatchers),
13 |       instanceReferenceReader = ChainingInstanceReferenceReader(
14 |         virtualRefReaders = listOf(JavaLocalReferenceReader(heapGraph, referenceMatchers)),
15 |         flatteningInstanceReader = null,
16 |         fieldRefReader = FieldInstanceReferenceReader(heapGraph, referenceMatchers)
17 |       ), objectArrayReferenceReader = ObjectArrayReferenceReader()
18 |     )
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/AndroidObjectSizeCalculator.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import shark.DominatorTree.ObjectSizeCalculator
 4 | import shark.internal.ShallowSizeCalculator
 5 | 
 6 | class AndroidObjectSizeCalculator(graph: HeapGraph) : ObjectSizeCalculator {
 7 | 
 8 |   private val nativeSizes = AndroidNativeSizeMapper(graph).mapNativeSizes()
 9 |   private val shallowSizeCalculator = ShallowSizeCalculator(graph)
10 | 
11 |   override fun computeSize(objectId: Long): Int {
12 |     val nativeSize = nativeSizes[objectId] ?: 0
13 |     val shallowSize = shallowSizeCalculator.computeShallowSize(objectId)
14 |     return nativeSize + shallowSize
15 |   }
16 | }
17 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/AppSingletonInspector.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import shark.HeapObject.HeapInstance
 4 | 
 5 | /**
 6 |  * Inspector that automatically marks instances of the provided class names as not leaking
 7 |  * because they're app wide singletons.
 8 |  */
 9 | class AppSingletonInspector(private vararg val singletonClasses: String) : ObjectInspector {
10 |   override fun inspect(
11 |     reporter: ObjectReporter
12 |   ) {
13 |     if (reporter.heapObject is HeapInstance) {
14 |       reporter.heapObject.instanceClass
15 |         .classHierarchy
16 |         .forEach { heapClass ->
17 |           if (heapClass.name in singletonClasses) {
18 |             reporter.notLeakingReasons += "${heapClass.name} is an app singleton"
19 |           }
20 |         }
21 |     }
22 |   }
23 | }


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/DelegatingObjectReferenceReader.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import shark.HeapObject.HeapClass
 4 | import shark.HeapObject.HeapInstance
 5 | import shark.HeapObject.HeapObjectArray
 6 | import shark.HeapObject.HeapPrimitiveArray
 7 | 
 8 | internal class DelegatingObjectReferenceReader(
 9 |   private val classReferenceReader: ReferenceReader<HeapClass>,
10 |   private val instanceReferenceReader: ReferenceReader<HeapInstance>,
11 |   private val objectArrayReferenceReader: ReferenceReader<HeapObjectArray>,
12 | ) : ReferenceReader<HeapObject> {
13 |   override fun read(source: HeapObject): Sequence<Reference> {
14 |     return when(source) {
15 |       is HeapClass -> classReferenceReader.read(source)
16 |       is HeapInstance -> instanceReferenceReader.read(source)
17 |       is HeapObjectArray -> objectArrayReferenceReader.read(source)
18 |       is HeapPrimitiveArray -> emptySequence()
19 |     }
20 |   }
21 | }
22 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/Dominators.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | import java.io.Serializable
4 | import shark.ObjectDominators.DominatorNode
5 | 
6 | class Dominators(val dominatorNodes: Map<Long, DominatorNode>) : Serializable
7 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/FilteringLeakingObjectFinder.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Finds the objects that are leaking by scanning all objects in the heap dump
 5 |  * and delegating the decision to a list of [FilteringLeakingObjectFinder.LeakingObjectFilter]
 6 |  */
 7 | class FilteringLeakingObjectFinder(private val filters: List<LeakingObjectFilter>) :
 8 |   LeakingObjectFinder {
 9 | 
10 |   /**
11 |    * Filter to be passed to the [FilteringLeakingObjectFinder] constructor.
12 |    */
13 |   fun interface LeakingObjectFilter {
14 |     /**
15 |      * Returns whether the passed in [heapObject] is leaking. This should only return true
16 |      * when we're 100% sure the passed in [heapObject] should not be in memory anymore.
17 |      */
18 |     fun isLeakingObject(heapObject: HeapObject): Boolean
19 |   }
20 | 
21 |   override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> {
22 |     return graph.objects
23 |       .filter { heapObject ->
24 |         filters.any { filter ->
25 |           filter.isLeakingObject(heapObject)
26 |         }
27 |       }
28 |       .map { it.objectId }
29 |       .toSet()
30 |   }
31 | }
32 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/GcRootProvider.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | fun interface GcRootProvider {
4 |   /**
5 |    * Provides a sequence of GC Roots to traverse the graph from, ideally in a stable order.
6 |    */
7 |   fun provideGcRoots(graph: HeapGraph): Sequence<GcRootReference>
8 | }
9 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/GcRootReference.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | // TODO Revisit this API. It's more like a GC Root + some priority / tagging.
4 | class GcRootReference(
5 |   val gcRoot: GcRoot,
6 |   val isLowPriority: Boolean,
7 |   val matchedLibraryLeak: LibraryLeakReferenceMatcher?,
8 | )
9 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/HeapAnalysisException.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import java.io.PrintWriter
 4 | import java.io.StringWriter
 5 | 
 6 | class HeapAnalysisException(cause: Throwable) : RuntimeException(cause) {
 7 | 
 8 |   override fun toString(): String {
 9 |     val stringWriter = StringWriter()
10 |     cause!!.printStackTrace(PrintWriter(stringWriter))
11 |     return stringWriter.toString()
12 |   }
13 | 
14 |   companion object {
15 |     private const val serialVersionUID: Long = -2522323377375290608
16 |   }
17 | }


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/JvmObjectGrowthDetector.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | fun ObjectGrowthDetector.Companion.forJvmHeap(
 4 |   referenceMatchers: List<ReferenceMatcher> = JvmObjectGrowthReferenceMatchers.defaults
 5 | ): ObjectGrowthDetector {
 6 |   return ObjectGrowthDetector(
 7 |     gcRootProvider = MatchingGcRootProvider(referenceMatchers),
 8 |     referenceReaderFactory = OpenJdkReferenceReaderFactory(referenceMatchers)
 9 |   )
10 | }
11 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/LeakNodeStatus.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * This class is kept to support backward compatible deserialization.
 5 |  */
 6 | internal enum class LeakNodeStatus {
 7 |   NOT_LEAKING,
 8 |   LEAKING,
 9 |   UNKNOWN;
10 | }


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/LeakTracer.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | fun interface LeakTracer {
 4 | 
 5 |   // TODO What should we do about exceptions here? union error or exception?
 6 |   fun traceObjects(objectIds: Set<Long>): LeaksAndUnreachableObjects
 7 | 
 8 |   fun interface Factory {
 9 |     fun createFor(heapGraph: HeapGraph): LeakTracer
10 |   }
11 | }
12 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/LeakingObjectFinder.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Finds the objects that are leaking, for which Shark will compute
 5 |  * leak traces.
 6 |  */
 7 | fun interface LeakingObjectFinder {
 8 | 
 9 |   /**
10 |    * For a given heap graph, returns a set of object ids for the objects that are leaking.
11 |    */
12 |   fun findLeakingObjectIds(graph: HeapGraph): Set<Long>
13 | }
14 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/LeaksAndUnreachableObjects.kt:
--------------------------------------------------------------------------------
1 | package shark
2 | 
3 | // TODO Name?
4 | data class LeaksAndUnreachableObjects(
5 |   val applicationLeaks: List<ApplicationLeak>,
6 |   val libraryLeaks: List<LibraryLeak>,
7 |   val unreachableObjects: List<LeakTraceObject>
8 | )
9 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/MetadataExtractor.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Extracts metadata from a hprof to be reported in [HeapAnalysisSuccess.metadata].
 5 |  */
 6 | fun interface MetadataExtractor {
 7 |   fun extractMetadata(graph: HeapGraph): Map<String, String>
 8 | 
 9 |   companion object {
10 | 
11 |     /**
12 |      * A no-op [MetadataExtractor]
13 |      */
14 |     val NO_OP = MetadataExtractor { emptyMap() }
15 |   }
16 | }
17 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/ObjectInspector.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * Provides LeakCanary with insights about objects (classes, instances and arrays) found in the
 5 |  * heap. [inspect] will be called for each object that LeakCanary wants to know more about.
 6 |  * The implementation can then use the provided [ObjectReporter] to provide insights for that
 7 |  * object.
 8 |  */
 9 | fun interface ObjectInspector {
10 | 
11 |   /**
12 |    * @see [ObjectInspector]
13 |    */
14 |   fun inspect(reporter: ObjectReporter)
15 | }
16 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/OpenJdkReferenceReaderFactory.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | class OpenJdkReferenceReaderFactory(
 4 |   private val referenceMatchers: List<ReferenceMatcher>
 5 | ) : ReferenceReader.Factory<HeapObject> {
 6 | 
 7 |   private val virtualizingFactory = VirtualizingMatchingReferenceReaderFactory(
 8 |     referenceMatchers = referenceMatchers,
 9 |     virtualRefReadersFactory = { graph ->
10 |       listOf(
11 |         JavaLocalReferenceReader(graph, referenceMatchers),
12 |       ) +
13 |         OpenJdkInstanceRefReaders.values().mapNotNull { it.create(graph) } +
14 |         ApacheHarmonyInstanceRefReaders.values().mapNotNull { it.create(graph) }
15 |     }
16 |   )
17 | 
18 |   override fun createFor(heapGraph: HeapGraph): ReferenceReader<HeapObject> {
19 |     return virtualizingFactory.createFor(heapGraph)
20 |   }
21 | }
22 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/PathFindingResults.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import shark.internal.ReferencePathNode
 4 | 
 5 | // TODO Class name
 6 | class PathFindingResults(
 7 |   val pathsToLeakingObjects: List<ReferencePathNode>,
 8 |   val dominatorTree: DominatorTree?
 9 | )
10 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/ReferenceLocationType.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | /**
 4 |  * TODO This is quite similar to the leaktrace equivalent
 5 |  */
 6 | enum class ReferenceLocationType {
 7 |   INSTANCE_FIELD,
 8 |   STATIC_FIELD,
 9 |   LOCAL,
10 |   ARRAY_ENTRY
11 | }
12 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/ReferenceReader.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | // TODO Reevaluate name. Maybe not "Reader"? Something about navigating?
 4 | fun interface ReferenceReader<T : HeapObject> {
 5 | 
 6 |   /**
 7 |    * Returns the sequences of non null outgoing references from [source]. Outgoing refs
 8 |    * can be actual JVM references or they can be virtual references when simplifying known data
 9 |    * structures.
10 |    *
11 |    * Whenever possible, the returned sequence should be sorted in a way that ensures consistent
12 |    * graph traversal across heap dumps.
13 |    *
14 |    * The returned sequence may contain several [Reference] with an identical
15 |    * [Reference.valueObjectId].
16 |    */
17 |   fun read(source: T): Sequence<Reference>
18 | 
19 |   fun interface Factory<T : HeapObject> {
20 |     fun createFor(heapGraph: HeapGraph): ReferenceReader<T>
21 |   }
22 | }
23 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/ShortestPathFinder.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | // TODO Mention that this can also compute the dominator tree?
 4 | //  Ideally this would be split out, e.g. ObjectDominators uses this without
 5 | //  any target just to navigate the whole graph. But we do want to be able traverse the
 6 | //  whole thing in one go, and both find leaking objects + compute dominators.
 7 | //  Maybe there's a new "heap traversal" class that can navigate the whole heap starting from
 8 | //  gc roots and following references, and we plug in 2 things on it: the one for leaks
 9 | //  and the one for dominators. And both can say when to stop (dominators: never).
10 | fun interface ShortestPathFinder {
11 |   fun findShortestPathsFromGcRoots(
12 |     leakingObjectIds: Set<Long>
13 |   ): PathFindingResults
14 | 
15 |   fun interface Factory {
16 |     fun createFor(heapGraph: HeapGraph): ShortestPathFinder
17 |   }
18 | }
19 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/internal/ByteStringCompat.java:
--------------------------------------------------------------------------------
 1 | package shark.internal;
 2 | 
 3 | import okio.ByteString;
 4 | 
 5 | class ByteStringCompat {
 6 | 
 7 |   /**
 8 |    * This is deprecated (error) to invoke from Kotlin but invoking the Kotlin extension function
 9 |    * leads to improper bytecode that goes through the companion class.
10 |    */
11 |   static ByteString encodeUtf8(String string) {
12 |     return ByteString.encodeUtf8(string);
13 |   }
14 | }
15 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/internal/IntIntPairUtils.kt:
--------------------------------------------------------------------------------
 1 | package shark.internal
 2 | 
 3 | @PublishedApi
 4 | internal inline infix fun Int.packedWith(that: Int) =
 5 |   ((toLong()) shl 32) or (that.toLong() and 0xffffffffL)
 6 | 
 7 | @PublishedApi
 8 | internal inline val Long.unpackAsFirstInt: Int
 9 |   get() = (this shr 32).toInt()
10 | 
11 | @PublishedApi
12 | internal inline val Long.unpackAsSecondInt: Int
13 |   get() = (this and 0xFFFFFFFF).toInt()
14 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/internal/JavaFrames.kt:
--------------------------------------------------------------------------------
 1 | package shark.internal
 2 | 
 3 | import shark.GcRoot.JavaFrame
 4 | import shark.HeapGraph
 5 | 
 6 | internal object JavaFrames {
 7 | 
 8 |   private fun getJavaFramesByThreadSerialNumber(graph: HeapGraph) =
 9 |     graph.context.getOrPut(JavaFrames::class.java.name) {
10 |       graph.gcRoots.asSequence().filterIsInstance<JavaFrame>().groupBy { javaFrame ->
11 |         javaFrame.threadSerialNumber
12 |       }
13 |     }
14 | 
15 |   fun getByThreadObjectId(graph: HeapGraph, threadObjectId: Long): List<JavaFrame>? {
16 |     val threadObject = ThreadObjects.getByThreadObjectId(graph, threadObjectId) ?: return null
17 |     val javaFrameByThreadSerial = getJavaFramesByThreadSerialNumber(graph)
18 |     return javaFrameByThreadSerial[threadObject.threadSerialNumber]
19 |   }
20 | }
21 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/internal/Strings.kt:
--------------------------------------------------------------------------------
1 | package shark.internal
2 | 
3 | internal fun String.lastSegment(segmentingChar: Char): String {
4 |   val separator = lastIndexOf(segmentingChar)
5 |   return if (separator == -1) this else this.substring(separator + 1)
6 | }
7 | 
8 | internal fun String.createSHA1Hash() = ByteStringCompat.encodeUtf8(this).sha1().hex()
9 | 


--------------------------------------------------------------------------------
/shark/shark/src/main/java/shark/internal/ThreadObjects.kt:
--------------------------------------------------------------------------------
 1 | package shark.internal
 2 | 
 3 | import shark.GcRoot.ThreadObject
 4 | import shark.HeapGraph
 5 | 
 6 | internal object ThreadObjects {
 7 | 
 8 |   private fun getThreadObjectsByIdMap(graph: HeapGraph) = graph.context.getOrPut(ThreadObjects::class.java.name) {
 9 |     graph.gcRoots.asSequence().filterIsInstance<ThreadObject>().associateBy { it.id }
10 |   }
11 | 
12 |   fun getThreadObjects(graph: HeapGraph) = getThreadObjectsByIdMap(graph).values
13 | 
14 |   fun getByThreadObjectId(graph: HeapGraph, objectId: Long): ThreadObject? {
15 |     val threadObjectsById = getThreadObjectsByIdMap(graph)
16 |     return threadObjectsById[objectId]
17 |   }
18 | }
19 | 


--------------------------------------------------------------------------------
/shark/shark/src/test/java/shark/UnreachableObjectRenderingTest.kt:
--------------------------------------------------------------------------------
 1 | package shark
 2 | 
 3 | import org.assertj.core.api.Assertions.assertThat
 4 | import org.junit.Test
 5 | 
 6 | class UnreachableObjectRenderingTest {
 7 | 
 8 |   @Test fun `renders unreachable object`() {
 9 |     val heapDump = dump {
10 |       "com.example.SomeClass" watchedInstance {
11 |       }
12 |     }
13 | 
14 |     val analysis = heapDump.checkForLeaks<HeapAnalysisSuccess>()
15 | 
16 |     analysis renders """
17 |     com.example.SomeClass instance
18 |     _  Leaking: YES (ObjectWatcher was watching this because its lifecycle has ended)
19 |     _  key = 39efcc1a-67bf-2040-e7ab-3fc9f94731dc
20 |     _  watchDurationMillis = 25000
21 |     _  retainedDurationMillis = 10000
22 |         """
23 |   }
24 | 
25 |   private infix fun HeapAnalysisSuccess.renders(expectedString: String) {
26 |     assertThat(unreachableObjects[0].toString()).isEqualTo(
27 |       expectedString.trimIndent().replace('_', LeakTrace.ZERO_WIDTH_SPACE)
28 |     )
29 |   }
30 | 
31 | }


--------------------------------------------------------------------------------
/shark/shark/src/test/resources/hashmap_api_25.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark/src/test/resources/hashmap_api_25.hprof


--------------------------------------------------------------------------------
/shark/shark/src/test/resources/safe_iterable_map.hprof:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/square/leakcanary/22bef70ba5abdba5f65935c1a37227d01be598d3/shark/shark/src/test/resources/safe_iterable_map.hprof


--------------------------------------------------------------------------------