From ee7f12ef8557cd2fbc10db965f6170e0de6dff91 Mon Sep 17 00:00:00 2001 From: Luke De Feo Date: Thu, 19 Oct 2023 03:33:42 -0700 Subject: [PATCH] Add message when traversal has error Summary: By sending a message to the desktop we can report to log view and inform the user what happened Reviewed By: lblasa Differential Revision: D50369853 fbshipit-source-id: b4852d736232477261bfdf6f94c9395ce29cceaf --- .../plugins/uidebugger/core/UIDContext.kt | 10 ++++++-- .../plugins/uidebugger/model/Events.kt | 22 +++++++++++++---- .../uidebugger/model/FrameworkEvents.kt | 4 ++-- .../plugins/uidebugger/model/Metadata.kt | 2 +- .../flipper/plugins/uidebugger/model/Types.kt | 10 ++++---- .../observers/TreeObserverManager.kt | 15 +++++++++++- .../traversal/PartialLayoutTraversal.kt | 24 ++++++++++++------- 7 files changed, 62 insertions(+), 25 deletions(-) diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt index 83ed3f111..bd2a275d3 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/core/UIDContext.kt @@ -13,10 +13,12 @@ import com.facebook.flipper.plugins.uidebugger.common.BitmapPool import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent import com.facebook.flipper.plugins.uidebugger.model.FrameworkEventMetadata +import com.facebook.flipper.plugins.uidebugger.model.TraversalError 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 +import kotlinx.serialization.json.Json interface ConnectionListener { fun onConnect() @@ -34,8 +36,7 @@ class UIDContext( private val pendingFrameworkEvents: MutableList ) { - val layoutTraversal: PartialLayoutTraversal = - PartialLayoutTraversal(descriptorRegister, observerFactory) + val layoutTraversal: PartialLayoutTraversal = PartialLayoutTraversal(this) val treeObserverManager = TreeObserverManager(this) val sharedThrottle: SharedThrottle = SharedThrottle() @@ -45,6 +46,11 @@ class UIDContext( synchronized(pendingFrameworkEvents) { pendingFrameworkEvents.add(frameworkEvent) } } + fun onError(traversalError: TraversalError) { + connectionRef.connection?.send( + TraversalError.name, Json.encodeToString(TraversalError.serializer(), traversalError)) + } + fun extractPendingFrameworkEvents(): List { synchronized(pendingFrameworkEvents) { val copy = pendingFrameworkEvents.toList() diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt index 69624989f..def4febe7 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Events.kt @@ -10,21 +10,21 @@ package com.facebook.flipper.plugins.uidebugger.model import com.facebook.flipper.plugins.uidebugger.descriptors.Id @kotlinx.serialization.Serializable -data class InitEvent(val rootId: Id, val frameworkEventMetadata: List) { +class InitEvent(val rootId: Id, val frameworkEventMetadata: List) { companion object { const val name = "init" } } @kotlinx.serialization.Serializable -data class MetadataUpdateEvent(val attributeMetadata: Map = emptyMap()) { +class MetadataUpdateEvent(val attributeMetadata: Map = emptyMap()) { companion object { const val name = "metadataUpdate" } } @kotlinx.serialization.Serializable -data class FrameScanEvent( +class FrameScanEvent( val frameTime: Long, val nodes: List, val snapshot: Snapshot?, @@ -35,11 +35,23 @@ data class FrameScanEvent( } } -@kotlinx.serialization.Serializable data class Snapshot(val nodeId: Id, val data: String) +@kotlinx.serialization.Serializable +class TraversalError( + val nodeName: String, + val errorType: String, + val errorMessage: String, + val stack: String +) { + companion object { + const val name = "traversalError" + } +} + +@kotlinx.serialization.Serializable class Snapshot(val nodeId: Id, val data: String) /** Separate optional performance statistics event */ @kotlinx.serialization.Serializable -data class PerfStatsEvent( +class PerfStatsEvent( val txId: Long, val observerType: String, val nodesCount: Int, diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt index a5cd7f77d..28751660d 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/FrameworkEvents.kt @@ -10,13 +10,13 @@ package com.facebook.flipper.plugins.uidebugger.model import com.facebook.flipper.plugins.uidebugger.descriptors.Id @kotlinx.serialization.Serializable -data class FrameworkEventMetadata( +class FrameworkEventMetadata( val type: String, val documentation: String, ) @kotlinx.serialization.Serializable -data class FrameworkEvent( +class FrameworkEvent( val treeId: Id, val nodeId: Id, val type: String, diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Metadata.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Metadata.kt index 0ad0915b7..56a148d85 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Metadata.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Metadata.kt @@ -17,7 +17,7 @@ typealias MetadataId = Int * identity, attributes, layout, documentation, or a custom type. */ @kotlinx.serialization.Serializable -data class Metadata( +class Metadata( val id: MetadataId, val type: String, val namespace: String, diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Types.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Types.kt index 47e99e777..9cbe5585f 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Types.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/model/Types.kt @@ -22,7 +22,7 @@ data class Bounds(val x: Int, val y: Int, val width: Int, val height: Int) { } @kotlinx.serialization.Serializable -data class SpaceBox(val top: Int, val right: Int, val bottom: Int, val left: Int) { +class SpaceBox(val top: Int, val right: Int, val bottom: Int, val left: Int) { companion object { fun fromRect(rect: Rect): SpaceBox { return SpaceBox(rect.top, rect.right, rect.bottom, rect.left) @@ -31,7 +31,7 @@ data class SpaceBox(val top: Int, val right: Int, val bottom: Int, val left: Int } @kotlinx.serialization.Serializable -data class Color(val r: Int, val g: Int, val b: Int, val a: Int) { +class Color(val r: Int, val g: Int, val b: Int, val a: Int) { companion object { fun fromColor(color: Int): Color { val alpha: Int = (color shr 24) and 0xFF / 255 @@ -48,20 +48,20 @@ data class Color(val r: Int, val g: Int, val b: Int, val a: Int) { } @kotlinx.serialization.Serializable -data class Coordinate( +class Coordinate( @Serializable(with = NumberSerializer::class) val x: Number, @Serializable(with = NumberSerializer::class) val y: Number ) {} @kotlinx.serialization.Serializable -data class Coordinate3D( +class Coordinate3D( @Serializable(with = NumberSerializer::class) val x: Number, @Serializable(with = NumberSerializer::class) val y: Number, @Serializable(with = NumberSerializer::class) val z: Number ) {} @kotlinx.serialization.Serializable -data class Size( +class Size( @Serializable(with = NumberSerializer::class) val width: Number, @Serializable(with = NumberSerializer::class) val height: Number ) {} diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt index 141adbb36..7abd8db7b 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/observers/TreeObserverManager.kt @@ -25,6 +25,7 @@ import com.facebook.flipper.plugins.uidebugger.model.MetadataUpdateEvent import com.facebook.flipper.plugins.uidebugger.model.Node import com.facebook.flipper.plugins.uidebugger.model.PerfStatsEvent import com.facebook.flipper.plugins.uidebugger.model.Snapshot +import com.facebook.flipper.plugins.uidebugger.model.TraversalError import com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred import java.io.ByteArrayOutputStream import java.util.concurrent.atomic.AtomicInteger @@ -107,7 +108,19 @@ class TreeObserverManager(val context: UIDContext) { val workerThreadStartTimestamp = System.currentTimeMillis() - val nodes = batchedUpdate.updates.flatMap { it.deferredNodes.map { it.value() } } + val nodes = + try { + batchedUpdate.updates.flatMap { it.deferredNodes.map { it.value() } } + } catch (exception: Exception) { + context.onError( + TraversalError( + "DeferredProcessing", + exception.javaClass.simpleName, + exception.message ?: "", + exception.stackTraceToString())) + return + } + val frameworkEvents = context.extractPendingFrameworkEvents() val snapshotUpdate = batchedUpdate.updates.find { it.snapshot != null } val deferredComputationEndTimestamp = System.currentTimeMillis() diff --git a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt index 110019734..fd724ee57 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt +++ b/android/src/main/java/com/facebook/flipper/plugins/uidebugger/traversal/PartialLayoutTraversal.kt @@ -9,11 +9,11 @@ package com.facebook.flipper.plugins.uidebugger.traversal import android.util.Log import com.facebook.flipper.plugins.uidebugger.LogTag -import com.facebook.flipper.plugins.uidebugger.descriptors.DescriptorRegister +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.Node -import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverFactory +import com.facebook.flipper.plugins.uidebugger.model.TraversalError import com.facebook.flipper.plugins.uidebugger.util.Immediate import com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred @@ -24,12 +24,11 @@ import com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred * - The second item are any observable roots discovered. */ class PartialLayoutTraversal( - private val descriptorRegister: DescriptorRegister, - private val treeObserverFactory: TreeObserverFactory, + private val context: UIDContext, ) { @Suppress("unchecked_cast") - internal fun NodeDescriptor<*>.asAny(): NodeDescriptor = this as NodeDescriptor + private fun NodeDescriptor<*>.asAny(): NodeDescriptor = this as NodeDescriptor fun traverse(root: Any, parentId: Id?): Pair>, List>> { @@ -47,12 +46,13 @@ class PartialLayoutTraversal( try { // If we encounter a node that has it own observer, don't traverse - if (node != root && treeObserverFactory.hasObserverFor(node)) { + if (node != root && context.observerFactory.hasObserverFor(node)) { observableRoots.add((node to parentId)) continue } - val descriptor = descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny() + val descriptor = + context.descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny() val curId = descriptor.getId(node) if (shallow.contains(node)) { @@ -82,13 +82,13 @@ class PartialLayoutTraversal( var activeChildId: Id? = null if (activeChild != null) { val activeChildDescriptor = - descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass) + context.descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass) activeChildId = activeChildDescriptor.getId(activeChild) } val childrenIds = mutableListOf() children.forEach { child -> - val childDescriptor = descriptorRegister.descriptorForClassUnsafe(child.javaClass) + val childDescriptor = context.descriptorRegister.descriptorForClassUnsafe(child.javaClass) childrenIds.add(childDescriptor.getId(child)) stack.add(Pair(child, curId)) // If there is an active child then don't traverse it @@ -117,6 +117,12 @@ class PartialLayoutTraversal( }) } catch (exception: Exception) { Log.e(LogTag, "Error while processing node ${node.javaClass.name} $node", exception) + context.onError( + TraversalError( + node.javaClass.simpleName, + exception.javaClass.simpleName, + exception.message ?: "", + exception.stackTraceToString())) } }