Skip to content

Commit

Permalink
支持根据正则表达式配置是否需要进行 trace 插桩
Browse files Browse the repository at this point in the history
  • Loading branch information
b7woreo committed Dec 31, 2023
1 parent a9d75c2 commit 5b27b4a
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 128 deletions.
6 changes: 5 additions & 1 deletion example/application/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ android {
matchingFallbacks = ['release']
signingConfig debug.signingConfig
tracex {
enable = true
enabled = true

include(
"com.example.**"
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ class MainActivity : ComponentActivity() {
viewBinding.btnInc.setOnClickListener {
viewModel.inc()
}

viewBinding.btnDec.setOnClickListener {
viewModel.dec()
}
}

}
36 changes: 22 additions & 14 deletions example/application/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">

<TextView
android:id="@+id/tv_count"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center" />

<TextView
android:id="@+id/tv_count"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center" />
<Button
android:id="@+id/btn_inc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="INC" />

<Button
android:id="@+id/btn_inc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<Button
android:id="@+id/btn_dec"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="DEC" />
</LinearLayout>
2 changes: 1 addition & 1 deletion example/application/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Example</string>
<string name="app_name">TraceX Example</string>
</resources>
1 change: 1 addition & 0 deletions example/library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ android {

dependencies {
implementation(libraries.androidx.lifecycle.viewmodel)
implementation(libraries.kotlinx.coroutine.android)
}
16 changes: 13 additions & 3 deletions example/library/src/main/java/com/example/library/MainViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.example.library

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.launch

class MainViewModel : ViewModel() {

Expand All @@ -15,14 +17,22 @@ class MainViewModel : ViewModel() {
runCatching { incInternal() }
}

fun dec() {
viewModelScope.launch {
decInternal()
}
}

private fun incInternal() {
val currentCount = mutableCount.getAndUpdate { it + 1 }
Thread.sleep(500)
if (currentCount % 2 == 0) {
Thread.sleep(500)
throw RuntimeException()
} else {
return
}
}

private fun decInternal() {
mutableCount.getAndUpdate { it - 1 }
}

}
1 change: 1 addition & 0 deletions gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ gradlePlugin {
dependencies {
implementation libraries.android.gradle.api
implementation libraries.asm
testImplementation libraries.kotlin.test
}
51 changes: 25 additions & 26 deletions gradle-plugin/src/main/java/tracex/JarsIdentity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,35 @@ import org.gradle.work.InputChanges
import java.io.File

class JarsIdentity(
private val inputJars: ConfigurableFileCollection,
private val inputChanges: InputChanges,
private val inputJars: ConfigurableFileCollection,
private val inputChanges: InputChanges,
) {

fun compute(): JarChanges {
val (changed, addedOrRemoved) = inputChanges
.getFileChanges(inputJars)
.partition { it.changeType == ChangeType.MODIFIED }
fun compute(): JarChanges {
val (changed, addedOrRemoved) = inputChanges.getFileChanges(inputJars)
.partition { it.changeType == ChangeType.MODIFIED }

val reprocessAll = !inputChanges.isIncremental || addedOrRemoved.isNotEmpty()
val changedFiles = changed.map { it.file }.toSet()
val hasChanged = { file: File -> reprocessAll || (file in changedFiles) }
val jarsInfo = inputJars.files.mapIndexedNotNull { index: Int, file: File ->
if (!hasChanged(file)) null
else FileInfo(
identity = index.toString(),
file = file,
)
}
val reprocessAll = !inputChanges.isIncremental || addedOrRemoved.isNotEmpty()
val changedFiles = changed.map { it.file }.toSet()
val hasChanged = { file: File -> reprocessAll || (file in changedFiles) }
val jarsInfo = inputJars.files.mapIndexedNotNull { index: Int, file: File ->
if (!hasChanged(file)) null
else FileInfo(
identity = index.toString(),
file = file,
)
}

return JarChanges(jarsInfo, reprocessAll)
}
return JarChanges(jarsInfo, reprocessAll)
}

data class JarChanges(
val jarsInfo: List<FileInfo>,
val reprocessAll: Boolean,
)
data class JarChanges(
val jarsInfo: List<FileInfo>,
val reprocessAll: Boolean,
)

data class FileInfo(
val identity: String,
val file: File,
)
data class FileInfo(
val identity: String,
val file: File,
)
}
12 changes: 9 additions & 3 deletions gradle-plugin/src/main/java/tracex/TraceClassVisitor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.commons.AdviceAdapter

class TraceClassVisitor(
private val filter: (String) -> Boolean,
api: Int,
next: ClassVisitor,
) : ClassVisitor(api, next) {
Expand All @@ -31,15 +32,20 @@ class TraceClassVisitor(
exceptions: Array<out String>?
): MethodVisitor {
val mv = super.visitMethod(access, name, descriptor, signature, exceptions)
return TraceMethodVisitor(api, mv, access, name, descriptor)
val traceTag = "$className#$name"
if (!filter(traceTag)) {
return mv
}
return TraceMethodVisitor(traceTag, api, mv, access, name, descriptor)
}

private inner class TraceMethodVisitor(
private val traceTag: String,
api: Int,
methodVisitor: MethodVisitor?,
access: Int,
name: String?,
descriptor: String?
descriptor: String?,
) : AdviceAdapter(
api,
methodVisitor,
Expand All @@ -49,7 +55,7 @@ class TraceClassVisitor(
) {

override fun onMethodEnter() {
mv.visitLdcInsn("$className#$name")
mv.visitLdcInsn(traceTag)
mv.visitMethodInsn(
INVOKESTATIC,
"android/os/Trace",
Expand Down
33 changes: 25 additions & 8 deletions gradle-plugin/src/main/java/tracex/TraceExtension.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
package tracex

import TraceSpec
import com.android.build.api.dsl.ApplicationBuildType
import org.gradle.api.provider.Property

interface TraceExtension {
val enable: Property<Boolean>
abstract class TraceExtension : TraceSpec {

internal val includes = mutableListOf<String>()
internal val excludes = mutableListOf<String>()

override var enabled: Boolean = false

override fun include(vararg regex: String) {
includes.addAll(regex)
}

override fun exclude(vararg regex: String) {
excludes.addAll(regex)
}

companion object {

internal const val EXTENSION_NAME = "tracex"

internal fun ApplicationBuildType.createTraceExtension() {
extensions.create(TraceSpec::class.java, EXTENSION_NAME, TraceExtension::class.java)
}

companion object {
internal fun create(buildType: ApplicationBuildType) {
buildType.extensions.create("tracex", TraceExtension::class.java)
}
}
}


}
40 changes: 16 additions & 24 deletions gradle-plugin/src/main/java/tracex/TracePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,45 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.configurationcache.extensions.capitalized
import tracex
import tracex.TraceExtension.Companion.createTraceExtension

abstract class TracePlugin : Plugin<Project> {

override fun apply(project: Project) {
project.plugins.findPlugin("com.android.application")
?: throw RuntimeException("apply plugin: com.android.application first")

val androidExtension = project.extensions
.getByType(ApplicationExtension::class.java)
val androidExtension = project.extensions.getByType(ApplicationExtension::class.java)

androidExtension.buildTypes.configureEach { buildType ->
TraceExtension.create(buildType)
buildType.createTraceExtension()
}

val componentsExtension = project.extensions
.getByType(ApplicationAndroidComponentsExtension::class.java)
val componentsExtension = project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)

componentsExtension.onVariants { variant ->
val buildTypeName = variant.buildType ?: return@onVariants

val traceExtension = androidExtension
.buildTypes
.getByName(buildTypeName)
.tracex()
val traceExtension = androidExtension.buildTypes.getByName(buildTypeName).tracex() as TraceExtension

if (!traceExtension.enable.getOrElse(false)) {
if (!traceExtension.enabled) {
return@onVariants
}

val traceTransformTask = project.tasks.register(
"transform${variant.name.capitalized()}WithTraceX",
TraceTransformTask::class.java
"transform${variant.name.capitalized()}WithTraceX", TraceTransformTask::class.java
) {
it.intermediate.set(
project.layout.buildDirectory.dir("intermediates/tracex/${variant.name}")
)
it.includes.set(traceExtension.includes)
it.excludes.set(traceExtension.excludes)
it.intermediate.set(project.layout.buildDirectory.dir("intermediates/tracex/${variant.name}"))
}

variant.artifacts
.forScope(ScopedArtifacts.Scope.ALL)
.use(traceTransformTask)
.toTransform(
ScopedArtifact.CLASSES,
TraceTransformTask::allJars,
TraceTransformTask::allDirectories,
TraceTransformTask::outputJar
)
variant.artifacts.forScope(ScopedArtifacts.Scope.ALL).use(traceTransformTask).toTransform(
ScopedArtifact.CLASSES,
TraceTransformTask::allJars,
TraceTransformTask::allDirectories,
TraceTransformTask::outputJar
)
}
}

Expand Down
18 changes: 18 additions & 0 deletions gradle-plugin/src/main/java/tracex/TraceTagMatcher.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package tracex

class TraceTagMatcher(
includes: List<String>,
excludes: List<String>,
) {

private val includes = includes.map { it.toRegex() }
private val excludes = excludes.map { it.toRegex() }

fun isMatch(traceTag: String): Boolean {
return when {
excludes.any { traceTag.matches(it) } -> false
includes.any { traceTag.matches(it) } -> true
else -> includes.isEmpty()
}
}
}
Loading

0 comments on commit 5b27b4a

Please sign in to comment.