Skip to content
This repository has been archived by the owner on Nov 22, 2024. It is now read-only.

Commit

Permalink
Add framework event infra
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Luke De Feo authored and facebook-github-bot committed Mar 1, 2023
1 parent 39b14fc commit 914b32c
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
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;
Expand Down Expand Up @@ -62,12 +63,10 @@ public static InitializationResult initFlipperPlugins(Context context, FlipperCl

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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,40 @@

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)

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?)
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand All @@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
)
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

/*
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -97,6 +99,7 @@ abstract class TreeObserver<T> {
startTimestamp,
traversalCompleteTime,
snapshotCompleteTime,
frameworkEvents,
snapshotBitmap))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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>
Expand Down Expand Up @@ -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()

Expand All @@ -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()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
}
}

0 comments on commit 914b32c

Please sign in to comment.