Skip to content

Commit

Permalink
fix thread's name not show in flipper
Browse files Browse the repository at this point in the history
  • Loading branch information
s1rius committed Dec 15, 2021
1 parent a7ed764 commit 299c46d
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("unused")

package wtf.s1.android.thread.bhook

import android.annotation.SuppressLint
Expand All @@ -14,22 +16,26 @@ object S1ThreadHooker {

const val HOOK_ALL = 0
const val HOOK_APP = 1
private const val DEBUG = false
private const val TAG = "thread_hook"

val stackCache = ConcurrentHashMap<Int, String>()
val idMap = ConcurrentHashMap<Int, Int>()
val nameMap = ConcurrentHashMap<Int, String>()
//ugly fixme
private val c2stack = ConcurrentHashMap<Int, String>()
private val c2t = ConcurrentHashMap<Int, Int>()
private val t2c = ConcurrentHashMap<Int, Int>()
private val t2name = ConcurrentHashMap<Int, String>()

init {
System.loadLibrary("s1threadhook")
}

@SuppressLint("DefaultLocale")
@JvmStatic
fun threadCreate(cid: Int, nativeStack: String?): String {
fun threadCreate(cid: Int, nativeStack: ByteArray?) {
val sb: StringBuilder = StringBuilder()
if (nativeStack != null) {
sb.append(nativeStack)
val stackTrace: Array<StackTraceElement> = Thread.currentThread().getStackTrace()
sb.append(String(nativeStack))
val stackTrace: Array<StackTraceElement> = Thread.currentThread().stackTrace
for (s: StackTraceElement in stackTrace) {
if (!filterStacktrace(s)) {
sb.append("\t at ")
Expand All @@ -38,36 +44,35 @@ object S1ThreadHooker {
}
}

stackCache[cid] = sb.toString();
if (idMap.contains(cid)) {
idMap.get(cid)?.let {tid->
c2stack[cid] = sb.toString()
if (c2t.contains(cid)) {
c2t[cid]?.let { tid->
updateThread(cid, tid)
}
}
if (DEBUG) Log.i(TAG, "catch stacktrace cid = $cid stack = ${stackTrace.size}")
}
return sb.toString()
}

@JvmStatic
fun threadStart(tid: Int, cid: Int) {
idMap[cid] = tid;
c2t[cid] = tid
t2c[tid] = cid
updateThread(cid, tid)
}

@Suppress("ConvertTwoComparisonsToRangeCheck")
private fun updateThread(cid: Int, tid: Int) {

var s1thread = ThreadInspector.getThread(tid);
var s1thread = ThreadInspector.getThread(tid)

if (s1thread == null) {
s1thread = S1Thread(cid.toLong(), tid.toLong())
val name: String? = nameMap.remove(tid)
s1thread.name = name
ThreadInspector.threadCreate(s1thread)
}

var needUpdate = false
if (stackCache.containsKey(cid)) {
val stackString: String? = stackCache.remove(cid)
if (c2stack.containsKey(cid)) {
val stackString: String? = c2stack.remove(cid)
if (!TextUtils.isEmpty(stackString)) {
needUpdate = true
s1thread.stackTraces = stackString?.split("\n")
Expand All @@ -82,32 +87,34 @@ object S1ThreadHooker {
}
}
}
val name: String? = nameMap.remove(tid)
val name: String? = t2name.remove(tid)
if (!TextUtils.isEmpty(name)) {
needUpdate = true
s1thread.name = name
}

if (needUpdate) {
ThreadInspector.threadUpdate(s1thread)
} else {
ThreadInspector.threadCreate(s1thread)
}
if (DEBUG) Log.i(TAG, "$s1thread")
}

@JvmStatic
fun threadSetName(tid: Int, name: String) {
val s1Thread = ThreadInspector.getThread(tid)
if (s1Thread == null) {
nameMap[tid] = name
} else {
s1Thread.name = name;
ThreadInspector.threadUpdate(s1Thread)
fun threadSetName(tid: Int, name: ByteArray?) {
if (name == null) return
t2name[tid] = String(name)
t2c[tid]?.let {
updateThread(it, tid)
}
if (DEBUG) Log.i(TAG, "catch name tid = $tid name = ${String(name)}")
}

private fun filterStacktrace(s: StackTraceElement): Boolean {
return (TextUtils.equals(s.getClassName(), S1ThreadHooker::class.java.getName())
|| s.getMethodName().contains("getStackTrace")
|| s.getMethodName().contains("getThreadStackTrace")
return (TextUtils.equals(s.className, S1ThreadHooker::class.java.name)
|| s.methodName.contains("getStackTrace")
|| s.methodName.contains("getThreadStackTrace")
|| TextUtils.isEmpty(s.toString()))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,25 @@ data class S1Thread constructor(
)


fun update(thread: Thread) {
fun update(thread: Thread): S1Thread {
this.state = thread.state.ordinal.threadState()
this.isInterrupted = thread.isInterrupted
this.isAlive = thread.isAlive
return this
}

fun update(thread: S1Thread): S1Thread {
thread.name?.let { n->
if (n.isNotEmpty() && "null" != n) {
this.name = n
}
}
thread.stackTraces?.let { stackTraces->
if (stackTraces.isNotEmpty()) {
this.stackTraces = stackTraces
}
}
return this
}

override fun equals(other: Any?): Boolean {
Expand All @@ -63,13 +78,14 @@ data class S1Thread constructor(
}

override fun toString(): String {
return "S1Thread(id=$id, name='$name', " +
return "S1Thread(id=$id, cid=$cid name='$name', " +
"group=$group, " +
"state='$state', " +
"priority=$priority, " +
"isDaemon=$isDaemon, " +
"isInterrupted=$isInterrupted, " +
"createTime=$createTime)"
"createTime=$createTime), " +
"stacktrace=${stackTraces?.size?:0}"
}
}

Expand Down
12 changes: 7 additions & 5 deletions thread-core/src/main/java/wtf/s1/android/thread/ThreadLogImp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ class ThreadLogImp: ThreadLog {
private val listeners = CopyOnWriteArrayList<OnThreadCreateListener>()

override fun getThread(tid: Long): S1Thread? {
return threadMap.get(tid)
return threadMap[tid]
}

override fun onThreadNew(t: S1Thread) {
threadMap[t.id] = t
val newT = threadMap[t.id]?.update(t) ?: t
threadMap[newT.id] = newT
listeners.forEach {
it.onThreadCreate(t)
it.onThreadCreate(newT)
}
}

override fun onThreadUpdate(t: S1Thread) {
threadMap[t.id] = t
val newT = threadMap[t.id]?.update(t) ?: t
threadMap[t.id] = newT
listeners.forEach {
it.onThreadUpdate(t)
it.onThreadUpdate(newT)
}
}

Expand Down

0 comments on commit 299c46d

Please sign in to comment.