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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
da903b8bc5
commit
ee7f12ef85
@@ -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.descriptors.DescriptorRegister
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent
|
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEvent
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.FrameworkEventMetadata
|
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.TreeObserverFactory
|
||||||
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverManager
|
import com.facebook.flipper.plugins.uidebugger.observers.TreeObserverManager
|
||||||
import com.facebook.flipper.plugins.uidebugger.scheduler.SharedThrottle
|
import com.facebook.flipper.plugins.uidebugger.scheduler.SharedThrottle
|
||||||
import com.facebook.flipper.plugins.uidebugger.traversal.PartialLayoutTraversal
|
import com.facebook.flipper.plugins.uidebugger.traversal.PartialLayoutTraversal
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
interface ConnectionListener {
|
interface ConnectionListener {
|
||||||
fun onConnect()
|
fun onConnect()
|
||||||
@@ -34,8 +36,7 @@ class UIDContext(
|
|||||||
private val pendingFrameworkEvents: MutableList<FrameworkEvent>
|
private val pendingFrameworkEvents: MutableList<FrameworkEvent>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val layoutTraversal: PartialLayoutTraversal =
|
val layoutTraversal: PartialLayoutTraversal = PartialLayoutTraversal(this)
|
||||||
PartialLayoutTraversal(descriptorRegister, observerFactory)
|
|
||||||
|
|
||||||
val treeObserverManager = TreeObserverManager(this)
|
val treeObserverManager = TreeObserverManager(this)
|
||||||
val sharedThrottle: SharedThrottle = SharedThrottle()
|
val sharedThrottle: SharedThrottle = SharedThrottle()
|
||||||
@@ -45,6 +46,11 @@ class UIDContext(
|
|||||||
synchronized(pendingFrameworkEvents) { pendingFrameworkEvents.add(frameworkEvent) }
|
synchronized(pendingFrameworkEvents) { pendingFrameworkEvents.add(frameworkEvent) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onError(traversalError: TraversalError) {
|
||||||
|
connectionRef.connection?.send(
|
||||||
|
TraversalError.name, Json.encodeToString(TraversalError.serializer(), traversalError))
|
||||||
|
}
|
||||||
|
|
||||||
fun extractPendingFrameworkEvents(): List<FrameworkEvent> {
|
fun extractPendingFrameworkEvents(): List<FrameworkEvent> {
|
||||||
synchronized(pendingFrameworkEvents) {
|
synchronized(pendingFrameworkEvents) {
|
||||||
val copy = pendingFrameworkEvents.toList()
|
val copy = pendingFrameworkEvents.toList()
|
||||||
|
|||||||
@@ -10,21 +10,21 @@ package com.facebook.flipper.plugins.uidebugger.model
|
|||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class InitEvent(val rootId: Id, val frameworkEventMetadata: List<FrameworkEventMetadata>) {
|
class InitEvent(val rootId: Id, val frameworkEventMetadata: List<FrameworkEventMetadata>) {
|
||||||
companion object {
|
companion object {
|
||||||
const val name = "init"
|
const val name = "init"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class MetadataUpdateEvent(val attributeMetadata: Map<MetadataId, Metadata> = emptyMap()) {
|
class MetadataUpdateEvent(val attributeMetadata: Map<MetadataId, Metadata> = emptyMap()) {
|
||||||
companion object {
|
companion object {
|
||||||
const val name = "metadataUpdate"
|
const val name = "metadataUpdate"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class FrameScanEvent(
|
class FrameScanEvent(
|
||||||
val frameTime: Long,
|
val frameTime: Long,
|
||||||
val nodes: List<Node>,
|
val nodes: List<Node>,
|
||||||
val snapshot: Snapshot?,
|
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 */
|
/** Separate optional performance statistics event */
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class PerfStatsEvent(
|
class PerfStatsEvent(
|
||||||
val txId: Long,
|
val txId: Long,
|
||||||
val observerType: String,
|
val observerType: String,
|
||||||
val nodesCount: Int,
|
val nodesCount: Int,
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ package com.facebook.flipper.plugins.uidebugger.model
|
|||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class FrameworkEventMetadata(
|
class FrameworkEventMetadata(
|
||||||
val type: String,
|
val type: String,
|
||||||
val documentation: String,
|
val documentation: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class FrameworkEvent(
|
class FrameworkEvent(
|
||||||
val treeId: Id,
|
val treeId: Id,
|
||||||
val nodeId: Id,
|
val nodeId: Id,
|
||||||
val type: String,
|
val type: String,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ typealias MetadataId = Int
|
|||||||
* identity, attributes, layout, documentation, or a custom type.
|
* identity, attributes, layout, documentation, or a custom type.
|
||||||
*/
|
*/
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class Metadata(
|
class Metadata(
|
||||||
val id: MetadataId,
|
val id: MetadataId,
|
||||||
val type: String,
|
val type: String,
|
||||||
val namespace: String,
|
val namespace: String,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ data class Bounds(val x: Int, val y: Int, val width: Int, val height: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@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 {
|
companion object {
|
||||||
fun fromRect(rect: Rect): SpaceBox {
|
fun fromRect(rect: Rect): SpaceBox {
|
||||||
return SpaceBox(rect.top, rect.right, rect.bottom, rect.left)
|
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
|
@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 {
|
companion object {
|
||||||
fun fromColor(color: Int): Color {
|
fun fromColor(color: Int): Color {
|
||||||
val alpha: Int = (color shr 24) and 0xFF / 255
|
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
|
@kotlinx.serialization.Serializable
|
||||||
data class Coordinate(
|
class Coordinate(
|
||||||
@Serializable(with = NumberSerializer::class) val x: Number,
|
@Serializable(with = NumberSerializer::class) val x: Number,
|
||||||
@Serializable(with = NumberSerializer::class) val y: Number
|
@Serializable(with = NumberSerializer::class) val y: Number
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class Coordinate3D(
|
class Coordinate3D(
|
||||||
@Serializable(with = NumberSerializer::class) val x: Number,
|
@Serializable(with = NumberSerializer::class) val x: Number,
|
||||||
@Serializable(with = NumberSerializer::class) val y: Number,
|
@Serializable(with = NumberSerializer::class) val y: Number,
|
||||||
@Serializable(with = NumberSerializer::class) val z: Number
|
@Serializable(with = NumberSerializer::class) val z: Number
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@kotlinx.serialization.Serializable
|
@kotlinx.serialization.Serializable
|
||||||
data class Size(
|
class Size(
|
||||||
@Serializable(with = NumberSerializer::class) val width: Number,
|
@Serializable(with = NumberSerializer::class) val width: Number,
|
||||||
@Serializable(with = NumberSerializer::class) val height: Number
|
@Serializable(with = NumberSerializer::class) val height: Number
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@@ -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.Node
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.PerfStatsEvent
|
import com.facebook.flipper.plugins.uidebugger.model.PerfStatsEvent
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Snapshot
|
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 com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
@@ -107,7 +108,19 @@ class TreeObserverManager(val context: UIDContext) {
|
|||||||
|
|
||||||
val workerThreadStartTimestamp = System.currentTimeMillis()
|
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 frameworkEvents = context.extractPendingFrameworkEvents()
|
||||||
val snapshotUpdate = batchedUpdate.updates.find { it.snapshot != null }
|
val snapshotUpdate = batchedUpdate.updates.find { it.snapshot != null }
|
||||||
val deferredComputationEndTimestamp = System.currentTimeMillis()
|
val deferredComputationEndTimestamp = System.currentTimeMillis()
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ package com.facebook.flipper.plugins.uidebugger.traversal
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
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.Id
|
||||||
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
import com.facebook.flipper.plugins.uidebugger.descriptors.NodeDescriptor
|
||||||
import com.facebook.flipper.plugins.uidebugger.model.Node
|
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.Immediate
|
||||||
import com.facebook.flipper.plugins.uidebugger.util.MaybeDeferred
|
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.
|
* - The second item are any observable roots discovered.
|
||||||
*/
|
*/
|
||||||
class PartialLayoutTraversal(
|
class PartialLayoutTraversal(
|
||||||
private val descriptorRegister: DescriptorRegister,
|
private val context: UIDContext,
|
||||||
private val treeObserverFactory: TreeObserverFactory,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
internal fun NodeDescriptor<*>.asAny(): NodeDescriptor<Any> = this as NodeDescriptor<Any>
|
private fun NodeDescriptor<*>.asAny(): NodeDescriptor<Any> = this as NodeDescriptor<Any>
|
||||||
|
|
||||||
fun traverse(root: Any, parentId: Id?): Pair<List<MaybeDeferred<Node>>, List<Pair<Any, Id?>>> {
|
fun traverse(root: Any, parentId: Id?): Pair<List<MaybeDeferred<Node>>, List<Pair<Any, Id?>>> {
|
||||||
|
|
||||||
@@ -47,12 +46,13 @@ class PartialLayoutTraversal(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// If we encounter a node that has it own observer, don't traverse
|
// 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))
|
observableRoots.add((node to parentId))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val descriptor = descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny()
|
val descriptor =
|
||||||
|
context.descriptorRegister.descriptorForClassUnsafe(node::class.java).asAny()
|
||||||
|
|
||||||
val curId = descriptor.getId(node)
|
val curId = descriptor.getId(node)
|
||||||
if (shallow.contains(node)) {
|
if (shallow.contains(node)) {
|
||||||
@@ -82,13 +82,13 @@ class PartialLayoutTraversal(
|
|||||||
var activeChildId: Id? = null
|
var activeChildId: Id? = null
|
||||||
if (activeChild != null) {
|
if (activeChild != null) {
|
||||||
val activeChildDescriptor =
|
val activeChildDescriptor =
|
||||||
descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass)
|
context.descriptorRegister.descriptorForClassUnsafe(activeChild.javaClass)
|
||||||
activeChildId = activeChildDescriptor.getId(activeChild)
|
activeChildId = activeChildDescriptor.getId(activeChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
val childrenIds = mutableListOf<Id>()
|
val childrenIds = mutableListOf<Id>()
|
||||||
children.forEach { child ->
|
children.forEach { child ->
|
||||||
val childDescriptor = descriptorRegister.descriptorForClassUnsafe(child.javaClass)
|
val childDescriptor = context.descriptorRegister.descriptorForClassUnsafe(child.javaClass)
|
||||||
childrenIds.add(childDescriptor.getId(child))
|
childrenIds.add(childDescriptor.getId(child))
|
||||||
stack.add(Pair(child, curId))
|
stack.add(Pair(child, curId))
|
||||||
// If there is an active child then don't traverse it
|
// If there is an active child then don't traverse it
|
||||||
@@ -117,6 +117,12 @@ class PartialLayoutTraversal(
|
|||||||
})
|
})
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(LogTag, "Error while processing node ${node.javaClass.name} $node", 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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user