Skip to content

Commit

Permalink
Merge pull request #189 from KwaiAppTeam/xqs/support-leakcanary-custo…
Browse files Browse the repository at this point in the history
…m-dumper

Support leakcanary custom dumper
  • Loading branch information
alhah authored May 17, 2022
2 parents a602237 + 8b42ec3 commit 4fdb067
Show file tree
Hide file tree
Showing 85 changed files with 1,021 additions and 500 deletions.
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
# v2.2.0
New Features
- Support leakcanary custom dumper.
- Add two flavors StaticCpp and SharedCpp.

# v2.1.0
Enhancement
- Support Android S.
- AndroidGradlePlugin update to 7.1.0.
- NDK update to 23.1.7779620.

# v2.0.0
New Features
- Add Native Leak Monitor
- Add Thread Leak Monitor
- Add Native Leak Monitor.
- Add Thread Leak Monitor.

# v1.1.0
Enhancement
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,38 @@ The app freezes for a long time during the dump. For details, please refer to [h
- The `koom-thread-leak` module is used for Thread leak monitoring: it hooks the life cycle
function of the thread, and periodically reports the leaked thread information. For details, please refer to [here](./koom-thread-leak/README.md)

## STL Support
All Native modules support two access modes, c++_shared and c++_static. For details, please
refer to [cpp-support](https://developer.android.com/ndk/guides/cpp-support).
- Add dependency to the project build.gradle (take koom-fast-dump as an example):
```groovy
dependencies {
// In shared mode, multiple modules share the same libc++_shared.so (STL), and the package
// size is small, but when multiple modules depend on different STL versions, the final
// compilation will conflict.
implementation "com.kuaishou.koom:koom-fast-dump:${latest_version}"
// Or in static mode, each module has its own STL, the package size is large, and there are no
// compilation and runtime problems.
implementation "com.kuaishou.koom:koom-fast-dump-static:${latest_version}"
}
```
- Introduce a way to resolve the conflict of shared mode, add `pickFirst` in the project root
directory build.gradle:
```groovy
packagingOptions {
// Select the first libc++_shared.so when packaging apk, it may encounter unpredictable bugs
// at runtime, use it with caution!
pickFirst 'lib/*/libc++_shared.so'
}
```

## minSdk
- The minSdk of all modules is 18. If the minSdk of your app is lower than that, it needs to be
compatible with overrideLibrary in the manifest.
```xml
<uses-sdk tools:overrideLibrary="com.kwai.koom.fastdump, com.kwai.android.base, com.kwai.koom.base" />
```

## License
KOOM is under the Apache license 2.0. For details check out the [LICENSE](./LICENSE).

Expand Down
34 changes: 30 additions & 4 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,37 @@ KOOM(Kwai OOM, Kill OOM)是快手性能优化团队在处理移动端OOM问题
## KOOM 功能
### Java Heap 泄漏监控
- `koom-java-leak` 模块用于 Java Heap 泄漏监控:它利用 Copy-on-write 机制 fork 子进程 dump Java Heap,解决了
dump 过程中 app 长时间冻结的问题,详情参考[这里](./koom-java-leak/README.zh-CN.md)
dump 过程中 app 长时间冻结的问题,详情参考 [这里](./koom-java-leak/README.zh-CN.md)
### Native Heap 泄漏监控
- `koom-native-leak` 模块用于 Native Heap 泄漏监控:它利用 [Tracing garbage collection](https://en.wikipedia.org/wiki/Tracing_garbage_collection) 机制分析整个 Native Heap,直接输出泄漏内存信息「大小、分配堆栈等』;极大的降低了业务同学分析、解决内存泄漏的成本。详情可以参考[这里](./koom-native-leak/README.zh-CN.md)
- `koom-native-leak` 模块用于 Native Heap 泄漏监控:它利用 [Tracing garbage collection](https://en.wikipedia.org/wiki/Tracing_garbage_collection)
机制分析整个 Native Heap,直接输出泄漏内存信息「大小、分配堆栈等』;极大的降低了业务同学分析、解决内存泄漏的成本。详情可以参考 [这里](./koom-native-leak/README.zh-CN.md)
### Thread 泄漏监控
- `koom-thread-leak` 模块用于 Thread 泄漏监控:它会 hook 线程的生命周期函数,周期性的上报泄漏线程信息。详情参考[这里](./koom-thread-leak/README.zh-CN.md)
- `koom-thread-leak` 模块用于 Thread 泄漏监控:它会 hook 线程的生命周期函数,周期性的上报泄漏线程信息。详情参考 [这里](./koom-thread-leak/README.zh-CN.md)

## STL 支持
所有Native模块均支持c++_shared和c++_static两种接入模式,详情参考 [cpp-support](https://developer.android.com/ndk/guides/cpp-support)
- 项目 build.gradle 中增加依赖(以koom-fast-dump为例):
```groovy
dependencies {
// shared模式,多个模块共享同一个libc++_shared.so,包体较小,但当多个模块依赖的STL版本不同时,最终编译会发生冲突。
implementation "com.kuaishou.koom:koom-fast-dump:${latest_version}"
// or static模式,包体较大,无编译和运行时问题。
implementation "com.kuaishou.koom:koom-fast-dump-static:${latest_version}"
}
```
- 介绍一种解决shared模式冲突的办法,项目根目录 build.gradle 中增加pickFirst:
```groovy
packagingOptions {
// apk打包时选择第一个libc++_shared.so,运行时可能遇到不可预知的bug,慎用!
pickFirst 'lib/*/libc++_shared.so'
}
```

## minSdk
- 所有模块编译时的minSdk为18,如果接入方的minSdk低于此值,需要在manifest中通过overrideLibrary兼容:
```xml
<uses-sdk tools:overrideLibrary="com.kwai.koom.fastdump, com.kwai.android.base, com.kwai.koom.base" />
```

## License

Expand All @@ -40,5 +66,5 @@ KOOM 以 Apache-2.0 证书开源,详情参见 [LICENSE](./LICENSE)。
[lbtrace(王连宝)](https://github.com/lbtrace) <br>
[shenvsv(沈冠初)](https://github.com/shenvsv) <br>

**微信讨论群**
**微信讨论群** <br>
<img src=./doc/images/wechat.jpg/>。
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ buildscript {
ext.versions = [
'compileSdkVersion': 31,
'buildToolsVersion': '31.0.0',
'minSdkVersion' : 21,
'minSdkVersion' : 18,
'targetSdkVersion' : 26,
'kotlin' : '1.3.72',
'kotlin_compiler' : '1.4.21',
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ android.useAndroidX=true
android.enableJetifier=true

GROUP=com.kuaishou.koom
VERSION_NAME=2.1.0
VERSION_NAME=2.2.0

POM_URL=https://github.com/KwaiAppTeam/KOOM
POM_SCM_URL=https://github.com/KwaiAppTeam/KOOM/tree/master
Expand Down
173 changes: 173 additions & 0 deletions gradle/mavenCentral-android-publish.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'

task androidSourcesJar(type: Jar) {
if (project.hasProperty("android")) {
from android.sourceSets.main.java.srcDirs
} else {
from sourceSets.main.allSource
}
classifier 'sources'
}

task javadocJar(type: Jar) {
archiveClassifier.set("javadoc")
classifier "javadoc"
}

tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
options.addStringOption('encoding', 'UTF-8')
options.addStringOption('charSet', 'UTF-8')
}

ext {
PUBLISH_ARTIFACT_ID = "${project.getName()}" //project name
}

ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.secretKeyRingFile"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''

File secretPropsFile = project.rootProject.file('.gradle/gradle.properties')
if (secretPropsFile.exists()) {
println "Found secret props file, loading props"
Properties p = new Properties()
p.load(new FileInputStream(secretPropsFile))
p.each { name, value ->
ext[name] = value
}
} else {
println "No props file, loading env vars"
}

afterEvaluate {
def curArtifactId
android.libraryVariants.all { variant ->
// Skipped debug variants
if (variant.buildType.name == "debug") {
return
}
def hasFlavors = !variant.flavorName.isEmpty()

def artifactIdSuffix = hasFlavors ? variant.flavorName.replace('_', '-').capitalize() : ''
variant.productFlavors.each { flavor ->
def flavorArtifactIdSuffix = flavor.ext.has('artifactIdSuffix') ? flavor.ext.artifactIdSuffix : flavor.name
if (!flavorArtifactIdSuffix.isEmpty()) {
artifactIdSuffix = artifactIdSuffix.replace(flavor.name.capitalize(), "-${flavorArtifactIdSuffix}")
} else {
artifactIdSuffix = artifactIdSuffix.replace(flavor.name.capitalize(), "")
}
}
if (!artifactIdSuffix.isEmpty() && !artifactIdSuffix.startsWith('-')) {
artifactIdSuffix = '-' + artifactIdSuffix
}

curArtifactId = "${project.getName()}${artifactIdSuffix}"

def publicationName = "android${variant.name.capitalize()}"
publishing.publications {
"$publicationName"(MavenPublication) {
// The coordinates of the library, being set from variables that
// we'll set up in a moment
groupId GROUP
artifactId curArtifactId
version VERSION_NAME

// Two artifacts, the `aar` and the sources
if (project.hasProperty("android")) {
if (hasFlavors) {
variant.productFlavors.each { flavor ->
artifact("build/outputs/aar/${project.getName()}-${flavor.name}-release.aar")
}
} else {
artifact("build/outputs/aar/${project.getName()}-release.aar")
}
artifact androidSourcesJar
} else {
artifact("$buildDir/libs/${project.getName()}.jar")
artifact androidSourcesJar
artifact javadocJar
}
pom {
name = "${project.getName()}"
description = rootProject.name
// If your project has a dedicated site, use its URL here
url = POM_URL
licenses {
license {
name = POM_LICENCE_NAME
url = POM_LICENCE_URL
}
}
developers {
developer {
id = POM_DEVELOPER_ID
name = POM_DEVELOPER_NAME
}
}
// Version control info, if you're using GitHub, follow the format as seen here
scm {

connection = POM_SCM_CONNECTION
developerConnection = POM_SCM_DEV_CONNECTION
//branch address:
url = POM_SCM_URL
}
// A slightly hacky fix so that your POM will include any transitive dependencies
// that your library builds upon
withXml {
def dependenciesNode = asNode().appendNode('dependencies')
project.configurations.implementation.allDependencies.each {
if (it.group != null) {
def dependencyNode = dependenciesNode.appendNode('dependency')
if ((it.group).contains(rootProject.name)) {
dependencyNode.appendNode('groupId', GROUP)
// Consider a java project like "shark"
if (it.dependencyProject.hasProperty("android")) {
dependencyNode.appendNode('artifactId', "$it.name${artifactIdSuffix}")
} else {
dependencyNode.appendNode('artifactId', it.name)
}
dependencyNode.appendNode('version', VERSION_NAME)
} else {
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}
}
}
}
}
}
}

publishing.repositories {
// The repository to publish to, Sonatype/MavenCentral
maven {
// This is an arbitrary name, you may also use "mavencentral" or
// any other name that's descriptive for you
name = rootProject.name
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
// You only need this if you want to publish snapshots, otherwise just set the URL
// to the release repo directly
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl

// The username and password we've fetched earlier
credentials {
username ossrhUsername
password ossrhPassword
}
}
}
signing {
sign publishing.publications
}
}



Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'signing'

task androidSourcesJar(type: Jar) {
if (project.hasProperty("android")) {
from android.sourceSets.main.java.sourceFiles
from android.sourceSets.main.java.srcDirs
} else {
from sourceSets.main.allSource
}
Expand Down Expand Up @@ -46,7 +46,7 @@ if (secretPropsFile.exists()) {
afterEvaluate {
publishing {
publications {
mavenAndroid(MavenPublication) {
java(MavenPublication) {
// The coordinates of the library, being set from variables that
// we'll set up in a moment
groupId GROUP
Expand Down Expand Up @@ -132,7 +132,4 @@ afterEvaluate {
signing {
sign publishing.publications
}
}



}
36 changes: 28 additions & 8 deletions koom-common/kwai-android-base/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
id 'kotlin-android'
}
apply from: rootProject.file('gradle/common.gradle')
apply from: rootProject.file('gradle/mavenCentral-publish.gradle')
apply from: rootProject.file('gradle/mavenCentral-android-publish.gradle')

android {
defaultConfig {
Expand All @@ -13,29 +13,49 @@ android {
externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_shared", "-DCMAKE_VERBOSE_MAKEFILE=ON"
cppFlags "-std=c++17", "-Wl,--gc-sections", "-fno-exceptions", "-fno-rtti", "-fvisibility=hidden", "-flto"
cppFlags '-std=c++17', '-fno-exceptions', '-fno-rtti'
}
}
}

buildTypes {
release {
minifyEnabled false
externalNativeBuild {
cmake {
cppFlags '-Wl,--gc-sections', '-fvisibility=hidden', '-flto'
}
}
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.18.1"
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
// jniLibs.srcDir('src/main/libs')
// jni.srcDirs = []

flavorDimensions "stl_mode"
productFlavors {
StaticCpp {
dimension "stl_mode"
ext.artifactIdSuffix = 'static'
externalNativeBuild {
cmake {
arguments = ["-DANDROID_STL=c++_static"]
}
}
}
SharedCpp {
dimension "stl_mode"
ext.artifactIdSuffix = ''
externalNativeBuild {
cmake {
arguments = ["-DANDROID_STL=c++_shared"]
}
}
}
}
}
Expand Down
Loading

0 comments on commit 4fdb067

Please sign in to comment.