Add framework event infra
Summary: Added infra for collecting events from UI frameworks. 1. Framework event metadata captures all the static metadata around the event. This allows to us to not send the same metadata in every event as well as populate the monitoring drop down immediately. This is sent in init since this information is static 2. Framework event itself is quite bare at the moment. It will have thread and more attributes in the future The UIdebugger litho support ulitity has been simplified now there are 3 extension points. Context renamed to UIDContext since it is referenced in app initialisers where the android context is also imported and it create a naming collision Reviewed By: lblasa Differential Revision: D42606933 fbshipit-source-id: a419f3fd424c533d586813004c40b68feafd9a2e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
39b14fc428
commit
914b32c383
@@ -7,13 +7,10 @@
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.litho
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
|
||||
// this is not used internally
|
||||
object UIDebuggerLithoSupport {
|
||||
|
||||
fun addDescriptors(register: DescriptorRegister) {}
|
||||
|
||||
fun addObserver(observerFactory: TreeObserverFactory) {}
|
||||
fun enable(context: UIDContext) {}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin.SharedPreferencesDescriptor;
|
||||
import com.facebook.flipper.plugins.uidebugger.UIDebuggerFlipperPlugin;
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext;
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister;
|
||||
import com.facebook.flipper.plugins.uidebugger.litho.UIDebuggerLithoSupport;
|
||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory;
|
||||
@@ -62,12 +63,10 @@ public final class FlipperInitializer {
|
||||
|
||||
DescriptorRegister descriptorRegister = DescriptorRegister.Companion.withDefaults();
|
||||
TreeObserverFactory treeObserverFactory = TreeObserverFactory.Companion.withDefaults();
|
||||
UIDebuggerLithoSupport.INSTANCE.addDescriptors(descriptorRegister);
|
||||
UIDebuggerLithoSupport.INSTANCE.addObserver(treeObserverFactory);
|
||||
UIDContext uidContext = UIDContext.Companion.create((Application) context);
|
||||
UIDebuggerLithoSupport.INSTANCE.enable(uidContext);
|
||||
|
||||
client.addPlugin(
|
||||
new UIDebuggerFlipperPlugin(
|
||||
(Application) context, descriptorRegister, treeObserverFactory));
|
||||
client.addPlugin(new UIDebuggerFlipperPlugin(uidContext));
|
||||
client.start();
|
||||
|
||||
final OkHttpClient okHttpClient =
|
||||
|
||||
@@ -7,33 +7,19 @@
|
||||
|
||||
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.*
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.ApplicationRefDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.InitEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataUpdateEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
const val LogTag = "ui-debugger"
|
||||
|
||||
class UIDebuggerFlipperPlugin(
|
||||
val application: Application,
|
||||
descriptorRegister: DescriptorRegister?,
|
||||
observerFactory: TreeObserverFactory?
|
||||
) : FlipperPlugin {
|
||||
|
||||
private val context: Context =
|
||||
Context(
|
||||
ApplicationRef(application),
|
||||
ConnectionRef(null),
|
||||
descriptorRegister = descriptorRegister ?: DescriptorRegister.withDefaults(),
|
||||
observerFactory = observerFactory ?: TreeObserverFactory.withDefaults())
|
||||
class UIDebuggerFlipperPlugin(val context: UIDContext) : FlipperPlugin {
|
||||
|
||||
init {
|
||||
Log.i(LogTag, "Initializing ui-debugger")
|
||||
@@ -53,7 +39,9 @@ class UIDebuggerFlipperPlugin(
|
||||
InitEvent.name,
|
||||
Json.encodeToString(
|
||||
InitEvent.serializer(),
|
||||
InitEvent(ApplicationRefDescriptor.getId(context.applicationRef))))
|
||||
InitEvent(
|
||||
ApplicationRefDescriptor.getId(context.applicationRef),
|
||||
context.frameworkEventMetadata)))
|
||||
|
||||
connection.send(
|
||||
MetadataUpdateEvent.name,
|
||||
|
||||
@@ -11,10 +11,10 @@ import com.facebook.flipper.core.FlipperObject
|
||||
import com.facebook.flipper.core.FlipperReceiver
|
||||
import com.facebook.flipper.core.FlipperResponder
|
||||
import com.facebook.flipper.plugins.common.MainThreadFlipperReceiver
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
|
||||
/** An interface for extensions to the UIDebugger plugin */
|
||||
abstract class Command(val context: Context) {
|
||||
abstract class Command(val context: UIDContext) {
|
||||
/** The command identifier to respond to */
|
||||
abstract fun identifier(): String
|
||||
/** Execute the command */
|
||||
|
||||
@@ -7,19 +7,22 @@
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.core
|
||||
|
||||
import android.app.Application
|
||||
import com.facebook.flipper.core.FlipperConnection
|
||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEventMetadata
|
||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverManager
|
||||
import com.facebook.flipper.plugins.uidebugger.scheduler.SharedThrottle
|
||||
import com.facebook.flipper.plugins.uidebugger.traversal.PartialLayoutTraversal
|
||||
|
||||
data class Context(
|
||||
data class UIDContext(
|
||||
val applicationRef: ApplicationRef,
|
||||
val connectionRef: ConnectionRef,
|
||||
val descriptorRegister: DescriptorRegister,
|
||||
val observerFactory: TreeObserverFactory,
|
||||
val frameworkEventMetadata: MutableList<FrameworkEventMetadata>
|
||||
) {
|
||||
val layoutTraversal: PartialLayoutTraversal =
|
||||
PartialLayoutTraversal(descriptorRegister, observerFactory)
|
||||
@@ -27,6 +30,17 @@ data class Context(
|
||||
val treeObserverManager = TreeObserverManager(this)
|
||||
val sharedThrottle: SharedThrottle = SharedThrottle()
|
||||
val bitmapPool = BitmapPool()
|
||||
|
||||
companion object {
|
||||
fun create(application: Application): UIDContext {
|
||||
return UIDContext(
|
||||
ApplicationRef(application),
|
||||
ConnectionRef(null),
|
||||
descriptorRegister = DescriptorRegister.withDefaults(),
|
||||
observerFactory = TreeObserverFactory.withDefaults(),
|
||||
frameworkEventMetadata = mutableListOf())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ConnectionRef(var connection: FlipperConnection?)
|
||||
@@ -10,9 +10,7 @@ package com.facebook.flipper.plugins.uidebugger.model
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
data class InitEvent(
|
||||
val rootId: Id,
|
||||
) {
|
||||
data class InitEvent(val rootId: Id, val frameworkEventMetadata: List<FrameworkEventMetadata>) {
|
||||
companion object {
|
||||
const val name = "init"
|
||||
}
|
||||
@@ -31,7 +29,8 @@ data class SubtreeUpdateEvent(
|
||||
val observerType: String,
|
||||
val rootId: Id,
|
||||
val nodes: List<Node>,
|
||||
val snapshot: String? = null
|
||||
val snapshot: String?,
|
||||
val frameworkEvents: List<FrameworkEvent>?
|
||||
) {
|
||||
companion object {
|
||||
const val name = "subtreeUpdate"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.model
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
data class FrameworkEventMetadata(
|
||||
val type: String,
|
||||
val documentation: String,
|
||||
)
|
||||
|
||||
@kotlinx.serialization.Serializable
|
||||
data class FrameworkEvent(
|
||||
val nodeId: Id,
|
||||
val type: String,
|
||||
val timestamp: Long,
|
||||
)
|
||||
@@ -11,15 +11,15 @@ import android.util.Log
|
||||
import android.view.View
|
||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||
|
||||
/**
|
||||
* Responsible for observing the activity stack and managing the subscription to the top most
|
||||
* content view (decor view)
|
||||
*/
|
||||
class ApplicationTreeObserver(val context: Context) : TreeObserver<ApplicationRef>() {
|
||||
class ApplicationTreeObserver(val context: UIDContext) : TreeObserver<ApplicationRef>() {
|
||||
|
||||
override val type = "Application"
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
typealias DecorView = View
|
||||
|
||||
/** Responsible for subscribing to updates to the content view of an activity */
|
||||
class DecorViewObserver(val context: Context) : TreeObserver<DecorView>() {
|
||||
class DecorViewObserver(val context: UIDContext) : TreeObserver<DecorView>() {
|
||||
|
||||
private var nodeRef: WeakReference<View>? = null
|
||||
private var preDrawListener: ViewTreeObserver.OnPreDrawListener? = null
|
||||
@@ -78,7 +78,7 @@ object DecorViewTreeObserverBuilder : TreeObserverBuilder<DecorView> {
|
||||
return node.javaClass.simpleName.contains("DecorView")
|
||||
}
|
||||
|
||||
override fun build(context: Context): TreeObserver<DecorView> {
|
||||
override fun build(context: UIDContext): TreeObserver<DecorView> {
|
||||
Log.i(LogTag, "Building DecorView observer")
|
||||
return DecorViewObserver(context)
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ package com.facebook.flipper.plugins.uidebugger.observers
|
||||
import android.util.Log
|
||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||
|
||||
/*
|
||||
@@ -40,9 +41,10 @@ abstract class TreeObserver<T> {
|
||||
|
||||
/** Traverses the layout hierarchy while managing any encountered child observers. */
|
||||
fun traverseAndSend(
|
||||
context: Context,
|
||||
context: UIDContext,
|
||||
root: Any,
|
||||
snapshotBitmap: BitmapPool.ReusableBitmap? = null
|
||||
snapshotBitmap: BitmapPool.ReusableBitmap? = null,
|
||||
frameworkEvents: List<FrameworkEvent>? = null
|
||||
) {
|
||||
val startTimestamp = System.currentTimeMillis()
|
||||
val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root)
|
||||
@@ -97,6 +99,7 @@ abstract class TreeObserver<T> {
|
||||
startTimestamp,
|
||||
traversalCompleteTime,
|
||||
snapshotCompleteTime,
|
||||
frameworkEvents,
|
||||
snapshotBitmap))
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
package com.facebook.flipper.plugins.uidebugger.observers
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
|
||||
interface TreeObserverBuilder<T> {
|
||||
fun canBuildFor(node: Any): Boolean
|
||||
fun build(context: Context): TreeObserver<T>
|
||||
fun build(context: UIDContext): TreeObserver<T>
|
||||
}
|
||||
|
||||
class TreeObserverFactory {
|
||||
@@ -28,7 +28,7 @@ class TreeObserverFactory {
|
||||
}
|
||||
|
||||
// TODO: Not very efficient, need to cache this. Builders cannot be removed.
|
||||
fun createObserver(node: Any, context: Context): TreeObserver<*>? {
|
||||
fun createObserver(node: Any, context: UIDContext): TreeObserver<*>? {
|
||||
return builders.find { it.canBuildFor(node) }?.build(context)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ import android.util.Log
|
||||
import android.view.Choreographer
|
||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||
import com.facebook.flipper.plugins.uidebugger.core.Context
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.MetadataRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.model.MetadataUpdateEvent
|
||||
import com.facebook.flipper.plugins.uidebugger.model.Node
|
||||
import com.facebook.flipper.plugins.uidebugger.model.PerfStatsEvent
|
||||
@@ -37,13 +38,14 @@ data class SubtreeUpdate(
|
||||
val startTime: Long,
|
||||
val traversalCompleteTime: Long,
|
||||
val snapshotComplete: Long,
|
||||
val frameworkEvents: List<FrameworkEvent>?,
|
||||
val snapshot: BitmapPool.ReusableBitmap?
|
||||
)
|
||||
|
||||
data class BatchedUpdate(val updates: List<SubtreeUpdate>, val frameTimeMs: Long)
|
||||
|
||||
/** Holds the root observer and manages sending updates to desktop */
|
||||
class TreeObserverManager(val context: Context) {
|
||||
class TreeObserverManager(val context: UIDContext) {
|
||||
|
||||
private val rootObserver = ApplicationTreeObserver(context)
|
||||
private lateinit var batchedUpdates: Channel<BatchedUpdate>
|
||||
@@ -104,6 +106,7 @@ class TreeObserverManager(val context: Context) {
|
||||
val onWorkerThread = System.currentTimeMillis()
|
||||
|
||||
val nodes = batchedUpdate.updates.flatMap { it.deferredNodes.map { it.value() } }
|
||||
val frameworkEvents = batchedUpdate.updates.flatMap { it.frameworkEvents ?: listOf() }
|
||||
val snapshotUpdate = batchedUpdate.updates.find { it.snapshot != null }
|
||||
val deferredComptationComplete = System.currentTimeMillis()
|
||||
|
||||
@@ -116,13 +119,20 @@ class TreeObserverManager(val context: Context) {
|
||||
snapshotUpdate.snapshot.readyForReuse()
|
||||
}
|
||||
|
||||
// it is important this comes after deferred processing since the deferred processing can create
|
||||
// metadata
|
||||
sendMetadata()
|
||||
|
||||
val serialized =
|
||||
Json.encodeToString(
|
||||
SubtreeUpdateEvent.serializer(),
|
||||
SubtreeUpdateEvent(
|
||||
batchedUpdate.frameTimeMs, "batched", snapshotUpdate?.rootId ?: 1, nodes, snapshot))
|
||||
batchedUpdate.frameTimeMs,
|
||||
"batched",
|
||||
snapshotUpdate?.rootId ?: 1,
|
||||
nodes,
|
||||
snapshot,
|
||||
frameworkEvents))
|
||||
|
||||
val serializationEnd = System.currentTimeMillis()
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
package com.facebook.flipper.plugins.uidebugger
|
||||
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister
|
||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -32,11 +31,7 @@ class UIDebuggerFlipperPluginTest {
|
||||
@Throws(Exception::class)
|
||||
@Test
|
||||
fun emptyTest() {
|
||||
var plugin =
|
||||
UIDebuggerFlipperPlugin(
|
||||
app,
|
||||
DescriptorRegister.Companion.withDefaults(),
|
||||
TreeObserverFactory.Companion.withDefaults())
|
||||
var plugin = UIDebuggerFlipperPlugin(UIDContext.create(app))
|
||||
Assert.assertNotNull(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user