Native UI scan
Summary: Added scheduler to scan the Native UI every 500 ms to test, Also added instrumentation in a separate event with the timings of each stage visualised in a Data table on desktop which can be accessed with ctrl+I. Currently this instrumentation event is sent every time but it could be a config option controlled from the desktop in the future Reviewed By: lblasa Differential Revision: D39205313 fbshipit-source-id: ca034171db6b062396b4ef28028aaa663c4d852a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a5da6923eb
commit
41068d1c90
@@ -8,22 +8,23 @@
|
||||
package com.facebook.flipper.plugins.uidebugger
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import com.facebook.flipper.core.FlipperConnection
|
||||
import com.facebook.flipper.core.FlipperPlugin
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationInspector
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ConnectionRef
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.NativeScanScheduler
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InitEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.model.NativeScanEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.scheduler.Scheduler
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
val LogTag = "FlipperUIDebugger"
|
||||
|
||||
class UIDebuggerFlipperPlugin(val application: Application) : FlipperPlugin {
|
||||
|
||||
private val context: Context = Context(ApplicationRef(application))
|
||||
private var connection: FlipperConnection? = null
|
||||
private val context: Context = Context(ApplicationRef(application), ConnectionRef(null))
|
||||
|
||||
private val nativeScanScheduler = Scheduler(NativeScanScheduler(context))
|
||||
|
||||
override fun getId(): String {
|
||||
return "ui-debugger"
|
||||
@@ -31,33 +32,26 @@ class UIDebuggerFlipperPlugin(val application: Application) : FlipperPlugin {
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun onConnect(connection: FlipperConnection) {
|
||||
this.connection = connection
|
||||
// temp solution, get from descriptor
|
||||
val inspector = ApplicationInspector(context)
|
||||
this.context.connectionRef.connection = connection
|
||||
|
||||
val rootDescriptor =
|
||||
inspector.descriptorRegister.descriptorForClassUnsafe(context.applicationRef.javaClass)
|
||||
context.descriptorRegister.descriptorForClassUnsafe(context.applicationRef.javaClass)
|
||||
|
||||
connection.send(
|
||||
InitEvent.name,
|
||||
Json.encodeToString(
|
||||
InitEvent.serializer(), InitEvent(rootDescriptor.getId(context.applicationRef))))
|
||||
|
||||
try {
|
||||
val nodes = inspector.traversal.traverse()
|
||||
connection.send(
|
||||
NativeScanEvent.name,
|
||||
Json.encodeToString(NativeScanEvent.serializer(), NativeScanEvent(nodes)))
|
||||
} catch (e: java.lang.Exception) {
|
||||
Log.e(LogTag, e.message.toString(), e)
|
||||
}
|
||||
nativeScanScheduler.start()
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun onDisconnect() {
|
||||
this.connection = null
|
||||
this.context.connectionRef.connection = null
|
||||
this.nativeScanScheduler.stop()
|
||||
}
|
||||
|
||||
override fun runInBackground(): Boolean {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,13 @@
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.core
|
||||
|
||||
class Context(val applicationRef: ApplicationRef) {}
|
||||
import com.facebook.flipper.core.FlipperConnection
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
|
||||
data class Context(
|
||||
val applicationRef: ApplicationRef,
|
||||
val connectionRef: ConnectionRef,
|
||||
val descriptorRegister: DescriptorRegister = DescriptorRegister.withDefaults()
|
||||
)
|
||||
|
||||
data class ConnectionRef(var connection: FlipperConnection?)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.core
|
||||
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import com.facebook.flipper.plugins.uidebugger.model.NativeScanEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Node
|
||||
import com.facebook.flipper.plugins.uidebugger.model.PerfStatsEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.scheduler.Scheduler
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
data class ScanResult(
|
||||
val txId: Long,
|
||||
val scanStart: Long,
|
||||
val scanEnd: Long,
|
||||
val nodes: List<Node>
|
||||
)
|
||||
|
||||
class NativeScanScheduler(val context: Context) : Scheduler.Task<ScanResult> {
|
||||
val traversal = LayoutTraversal(context.descriptorRegister, context.applicationRef)
|
||||
var txId = 0L
|
||||
override fun execute(): ScanResult {
|
||||
|
||||
val start = System.currentTimeMillis()
|
||||
val nodes = traversal.traverse()
|
||||
val scanEnd = System.currentTimeMillis()
|
||||
|
||||
Log.d(
|
||||
"LAYOUT_SCHEDULER",
|
||||
Thread.currentThread().name +
|
||||
Looper.myLooper() +
|
||||
", produced: " +
|
||||
{
|
||||
nodes.count()
|
||||
} +
|
||||
" nodes")
|
||||
|
||||
return ScanResult(txId++, start, scanEnd, nodes)
|
||||
}
|
||||
|
||||
override fun process(result: ScanResult) {
|
||||
|
||||
val serialized =
|
||||
Json.encodeToString(
|
||||
NativeScanEvent.serializer(), NativeScanEvent(result.txId, result.nodes))
|
||||
val serializationEnd = System.currentTimeMillis()
|
||||
context.connectionRef.connection?.send(
|
||||
NativeScanEvent.name,
|
||||
serialized,
|
||||
)
|
||||
|
||||
val socketEnd = System.currentTimeMillis()
|
||||
|
||||
context.connectionRef.connection?.send(
|
||||
PerfStatsEvent.name,
|
||||
Json.encodeToString(
|
||||
PerfStatsEvent.serializer(),
|
||||
PerfStatsEvent(
|
||||
result.txId,
|
||||
result.scanStart,
|
||||
result.scanEnd,
|
||||
serializationEnd,
|
||||
socketEnd,
|
||||
result.nodes.size)))
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,23 @@ data class InitEvent(val rootId: String) {
|
||||
}
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
data class NativeScanEvent(val nodes: List<Node>) {
|
||||
data class NativeScanEvent(val txId: Long, val nodes: List<Node>) {
|
||||
companion object {
|
||||
const val name = "nativeScan"
|
||||
}
|
||||
}
|
||||
|
||||
/** Separate optional performance statistics event */
|
||||
@kotlinx.serialization.Serializable
|
||||
data class PerfStatsEvent(
|
||||
val txId: Long,
|
||||
val start: Long,
|
||||
val scanComplete: Long,
|
||||
val serializationComplete: Long,
|
||||
val socketComplete: Long,
|
||||
val nodesCount: Int
|
||||
) {
|
||||
companion object {
|
||||
const val name = "perfStats"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user