Support new transactions trace

Keep previous implementation as "transactions (legacy)"

The proxy is not yet able to generate traces because no
adb command is available at the moment.

Known issues:
- Enum fields are not translated into values in Winscope
  (only IntDef support)

Prepare the codebase for the new SF transaction tracing
Bug: 167521734
Test: run winscope and collect a transactions trace

Change-Id: Ie489ee1a63056377c1699e14df8de975c2978085
This commit is contained in:
Nataniel Borges
2021-11-08 13:01:09 +01:00
parent 9cc1353195
commit 60e704c1de
17 changed files with 539 additions and 338 deletions

View File

@@ -132,7 +132,6 @@ class TraceTarget:
self.trace_start = trace_start
self.trace_stop = trace_stop
# Order of files matters as they will be expected in that order and decoded in that order
TRACE_TARGETS = {
"window_trace": TraceTarget(
@@ -155,9 +154,14 @@ TRACE_TARGETS = {
f'screenrecord --bit-rate 8M /data/local/tmp/screen.mp4 >/dev/null 2>&1 &\necho "ScreenRecorder started."',
'pkill -l SIGINT screenrecord >/dev/null 2>&1'
),
"transaction": TraceTarget(
"transactions": TraceTarget(
WinscopeFileMatcher(WINSCOPE_DIR, "transactions_trace", "transactions"),
'su root service call SurfaceFlinger 1041 i32 1\necho "SF transactions recording started."',
'su root service call SurfaceFlinger 1041 i32 0 >/dev/null 2>&1'
),
"transactions_legacy": TraceTarget(
[
WinscopeFileMatcher(WINSCOPE_DIR, "transaction_trace", "transactions"),
WinscopeFileMatcher(WINSCOPE_DIR, "transaction_trace", "transactions_legacy"),
FileMatcher(WINSCOPE_DIR, f'transaction_merges_*', "transaction_merges"),
],
'su root service call SurfaceFlinger 1020 i32 1\necho "SF transactions recording started."',

View File

@@ -1,7 +1,7 @@
import { Buffer, RectF, Transform, Matrix, Color, Rect, Region } from '../../src/flickerlib/common.js';
import { ActiveBuffer, RectF, Transform, Matrix33, Color, Rect, Region } from '../../src/flickerlib/common.js';
import { VISIBLE_CHIP } from '../../src/flickerlib/treeview/Chips';
const standardTransform = new Transform(0, new Matrix(1, 0, 0, 0, 1, 0));
const standardTransform = new Transform(0, new Matrix33(1, 0, 0, 0, 1, 0));
const standardRect = new Rect(0, 0, 0, 0);
const standardColor = new Color(0, 0, 0, 1);
const standardCrop = new Rect(0, 0, -1, -1);
@@ -23,13 +23,13 @@ const expectedEmptyRegionLayer = {
z: -1,
zOrderRelativeOf: null,
parentId: 579,
activeBuffer: new Buffer(1440, 2614, 1472, 1),
activeBuffer: new ActiveBuffer(1440, 2614, 1472, 1),
bufferTransform: standardTransform,
color: new Color(0, 0, 0, 0.0069580078125),
crop: standardCrop,
hwcFrame: standardRect,
screenBounds: new RectF(37, 43, 146, 152),
transform: new Transform(0, new Matrix(1, 0, 37.37078094482422, 0, 1, -3.5995326042175293)),
transform: new Transform(0, new Matrix33(1, 0, 37.37078094482422, 0, 1, -3.5995326042175293)),
visibleRegion: new Region([new Rect(37, 43, 146, 152)]),
};
const emptyRegionProto = {
@@ -114,7 +114,7 @@ const expectedInvalidLayerVisibilityLayer = {
zOrderRelativeOf: null,
parentId: 1535,
stableId: "BufferLayer 1536 com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#2",
activeBuffer: new Buffer(1440, 2880, 1472, 1),
activeBuffer: new ActiveBuffer(1440, 2880, 1472, 1),
bufferTransform: standardTransform,
color: new Color(-1, -1, -1, 0),
hwcFrame: standardRect,
@@ -202,13 +202,13 @@ const expectedOrphanLayersLayer = {
zOrderRelativeOf: null,
parentId: 1011,
stableId: "BufferLayer 1012 SurfaceView - com.android.chrome/com.google.android.apps.chrome.Main#0",
activeBuffer: new Buffer(1440, 2614, 1472, 1),
activeBuffer: new ActiveBuffer(1440, 2614, 1472, 1),
bufferTransform: standardTransform,
color: standardColor,
crop: standardCrop,
hwcFrame: standardRect,
screenBounds: new RectF(0, 98, 1440, 2712),
transform: new Transform(0, new Matrix(1, 0, 0, 0, 1, 98)),
transform: new Transform(0, new Matrix33(1, 0, 0, 0, 1, 98)),
visibleRegion: new Region([new Rect(0, 98, 1440, 2712)]),
};
const expectedOrphanLayersProto = {
@@ -294,7 +294,7 @@ const expectedRootLayer = {
zOrderRelativeOf: null,
parentId: 12541,
stableId: "BufferQueueLayer 12545 com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.SimpleActivity#0",
activeBuffer: new Buffer(1440, 2960, 1472, 1),
activeBuffer: new ActiveBuffer(1440, 2960, 1472, 1),
chips: [VISIBLE_CHIP],
bufferTransform: standardTransform,
color: standardColor,
@@ -398,7 +398,7 @@ const expectedRootAospLayer = {
z: 0,
zOrderRelativeOf: null,
parentId: 41,
activeBuffer: new Buffer(1440, 2880, 1472, 1),
activeBuffer: new ActiveBuffer(1440, 2880, 1472, 1),
bufferTransform: standardTransform,
chips: [VISIBLE_CHIP],
color: standardColor,

View File

@@ -188,8 +188,8 @@ const TRACES = {
'layers_trace': {
name: 'Surface Flinger',
},
'transaction': {
name: 'Transactions',
'transactions': {
name: 'Transaction',
},
'proto_log': {
name: 'ProtoLog',
@@ -269,6 +269,7 @@ const proxyFileTypeAdapter = {
'wl_dump': FILE_TYPES.WAYLAND_DUMP,
'screen_recording': FILE_TYPES.SCREEN_RECORDING,
'transactions': FILE_TYPES.TRANSACTIONS_TRACE,
'transactions_legacy': FILE_TYPES.TRANSACTIONS_TRACE_LEGACY,
'proto_log': FILE_TYPES.PROTO_LOG,
'system_ui_trace': FILE_TYPES.SYSTEM_UI,
'launcher_trace': FILE_TYPES.LAUNCHER,

View File

@@ -57,8 +57,8 @@
:presentErrors="presentErrors"
ref="view"
/>
<transactionsview
v-else-if="isTransactions(file) && isShowFileType(file.type)"
<transactionsviewlegacy
v-else-if="isTransactionsLegacy(file) && isShowFileType(file.type)"
:trace="file"
ref="view"
/>
@@ -87,7 +87,7 @@ import TraceView from '@/TraceView.vue';
import AccessibilityTraceView from '@/AccessibilityTraceView.vue';
import WindowManagerTraceView from '@/WindowManagerTraceView.vue';
import SurfaceFlingerTraceView from '@/SurfaceFlingerTraceView.vue';
import TransactionsView from '@/TransactionsView.vue';
import TransactionsViewLegacy from '@/TransactionsViewLegacy.vue';
import LogView from '@/LogView.vue';
import FileType from '@/mixins/FileType.js';
import FlatCard from '@/components/FlatCard.vue';
@@ -181,7 +181,7 @@ export default {
mixins: [FileType],
components: {
'traceview': TraceView,
'transactionsview': TransactionsView,
'transactionsviewlegacy': TransactionsViewLegacy,
'logview': LogView,
'flat-card': FlatCard,
AccessibilityTraceView,

View File

@@ -69,7 +69,7 @@
import { shortenName } from './flickerlib/mixin'
export default {
name: 'transaction-entry',
name: 'transaction-entry-legacy',
props: {
index: {
type: Number,

View File

@@ -152,14 +152,17 @@
<script>
import TreeView from './TreeView.vue';
import VirtualList from '../libs/virtualList/VirtualList';
import TransactionEntry from './TransactionEntry.vue';
import TransactionEntryLegacy from './TransactionEntryLegacy.vue';
import FlatCard from './components/FlatCard.vue';
import {ObjectTransformer} from './transform.js';
import {expandTransactionId} from '@/traces/Transactions.ts';
import {expandTransactionId} from '@/traces/TransactionsLegacy.ts';
/**
* @deprecated This trace has been replaced by the new transactions trace
*/
export default {
name: 'transactionsview',
name: 'transactionsviewlegacy',
props: ['trace'],
data() {
const transactionTypes = new Set();
@@ -201,7 +204,7 @@ export default {
filters: [],
selectedProperties: [],
selectedTransaction: null,
transactionEntryComponent: TransactionEntry,
transactionEntryComponent: TransactionEntryLegacy,
transactionsTrace,
expandTransactionId,
};

View File

@@ -21,7 +21,8 @@ import jsonProtoDefsAccessibility from 'frameworks/base/core/proto/android/serve
import jsonProtoDefsWm from 'frameworks/base/core/proto/android/server/windowmanagertrace.proto';
import jsonProtoDefsProtoLog from 'frameworks/base/core/proto/android/internal/protolog.proto';
import jsonProtoDefsSf from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto';
import jsonProtoDefsTransaction from 'frameworks/native/cmds/surfacereplayer/proto/src/trace.proto';
import jsonProtoDefsTransaction from 'frameworks/native/services/surfaceflinger/layerproto/transactions.proto';
import jsonProtoDefsTransactionLegacy from 'frameworks/native/cmds/surfacereplayer/proto/src/trace.proto';
import jsonProtoDefsWl from 'WaylandSafePath/waylandtrace.proto';
import jsonProtoDefsSysUi from 'frameworks/base/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto';
import jsonProtoDefsLauncher from 'packages/apps/Launcher3/protos/launcher_trace_file.proto';
@@ -31,6 +32,7 @@ import jsonProtoDefsErrors from 'platform_testing/libraries/flicker/src/com/andr
import protobuf from 'protobufjs';
import {transform_accessibility_trace} from './transform_accessibility.js';
import {transform_transaction_trace} from './transform_transaction.js';
import {transform_transaction_trace_legacy} from './transform_transaction_legacy.js';
import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js';
import {transformProtolog} from './transform_protolog.js';
import {transform_sysui_trace} from './transform_sys_ui.js';
@@ -42,6 +44,7 @@ import AccessibilityTrace from '@/traces/Accessibility.ts';
import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.ts';
import WindowManagerTrace from '@/traces/WindowManager.ts';
import TransactionsTrace from '@/traces/Transactions.ts';
import TransactionsTraceLegacy from '@/traces/TransactionsLegacy.ts';
import ScreenRecordingTrace from '@/traces/ScreenRecording.ts';
import WaylandTrace from '@/traces/Wayland.ts';
import ProtoLogTrace from '@/traces/ProtoLog.ts';
@@ -63,7 +66,8 @@ const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.Windo
const WmDumpMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerServiceDumpProto');
const SfTraceMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersTraceFileProto');
const SfDumpMessage = lookup_type(jsonProtoDefsSf, 'android.surfaceflinger.LayersProto');
const SfTransactionTraceMessage = lookup_type(jsonProtoDefsTransaction, 'Trace');
const SfTransactionTraceMessage = lookup_type(jsonProtoDefsTransaction, 'TransactionTraceFile');
const SfTransactionTraceMessageLegacy = lookup_type(jsonProtoDefsTransactionLegacy, 'Trace');
const WaylandTraceMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.wayland_composer.TraceFileProto');
const WaylandDumpMessage = lookup_type(jsonProtoDefsWl, 'org.chromium.arc.wayland_composer.OutputStateProto');
const ProtoLogMessage = lookup_type(jsonProtoDefsProtoLog, 'com.android.internal.protolog.ProtoLogFileProto');
@@ -77,6 +81,7 @@ const ErrorTraceMessage = lookup_type(jsonProtoDefsErrors, 'com.android.server.w
const ACCESSIBILITY_MAGIC_NUMBER = [0x09, 0x41, 0x31, 0x31, 0x59, 0x54, 0x52, 0x41, 0x43]; // .A11YTRAC
const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE
const TRANSACTIONS_TRACE_MAGIC_NUMBER = [0x09, 0x54, 0x4e, 0x58, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TNXTRACE
const WINDOW_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WINTRACE
const MPEG4_MAGIC_NMBER = [0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x6d, 0x70, 0x34, 0x32]; // ....ftypmp42
const WAYLAND_TRACE_MAGIC_NUMBER = [0x09, 0x57, 0x59, 0x4c, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WYLTRACE
@@ -97,6 +102,7 @@ const FILE_TYPES = Object.freeze({
SURFACE_FLINGER_DUMP: 'SurfaceFlingerDump',
SCREEN_RECORDING: 'ScreenRecording',
TRANSACTIONS_TRACE: 'TransactionsTrace',
TRANSACTIONS_TRACE_LEGACY: 'TransactionsTraceLegacy',
WAYLAND_TRACE: 'WaylandTrace',
WAYLAND_DUMP: 'WaylandDump',
PROTO_LOG: 'ProtoLog',
@@ -130,6 +136,7 @@ const FILE_ICONS = {
[FILE_TYPES.SURFACE_FLINGER_DUMP]: SURFACE_FLINGER_ICON,
[FILE_TYPES.SCREEN_RECORDING]: SCREEN_RECORDING_ICON,
[FILE_TYPES.TRANSACTIONS_TRACE]: TRANSACTION_ICON,
[FILE_TYPES.TRANSACTIONS_TRACE_LEGACY]: TRANSACTION_ICON,
[FILE_TYPES.WAYLAND_TRACE]: WAYLAND_ICON,
[FILE_TYPES.WAYLAND_DUMP]: WAYLAND_ICON,
[FILE_TYPES.PROTO_LOG]: PROTO_LOG_ICON,
@@ -152,6 +159,7 @@ const TRACE_TYPES = Object.freeze({
SURFACE_FLINGER: 'SurfaceFlingerTrace',
SCREEN_RECORDING: 'ScreenRecording',
TRANSACTION: 'Transaction',
TRANSACTION_LEGACY: 'Transaction (Legacy)',
WAYLAND: 'Wayland',
PROTO_LOG: 'ProtoLog',
SYSTEM_UI: 'SystemUI',
@@ -196,6 +204,14 @@ const TRACE_INFO = {
],
constructor: TransactionsTrace,
},
[TRACE_TYPES.TRANSACTION_LEGACY]: {
name: 'Transactions (Legacy)',
icon: TRANSACTION_ICON,
files: [
oneOf(FILE_TYPES.TRANSACTIONS_TRACE_LEGACY),
],
constructor: TransactionsTraceLegacy,
},
[TRACE_TYPES.WAYLAND]: {
name: 'Wayland',
icon: WAYLAND_ICON,
@@ -284,6 +300,7 @@ export const TRACE_ICONS = {
[TRACE_TYPES.SURFACE_FLINGER]: SURFACE_FLINGER_ICON,
[TRACE_TYPES.SCREEN_RECORDING]: SCREEN_RECORDING_ICON,
[TRACE_TYPES.TRANSACTION]: TRANSACTION_ICON,
[TRACE_TYPES.TRANSACTION_LEGACY]: TRANSACTION_ICON,
[TRACE_TYPES.WAYLAND]: WAYLAND_ICON,
[TRACE_TYPES.PROTO_LOG]: PROTO_LOG_ICON,
[TRACE_TYPES.SYSTEM_UI]: SYSTEM_UI_ICON,
@@ -396,6 +413,17 @@ const FILE_DECODERS = {
timeline: true,
},
},
[FILE_TYPES.TRANSACTIONS_TRACE_LEGACY]: {
name: 'Transactions (Legacy)',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.TRANSACTIONS_TRACE_LEGACY,
mime: 'application/octet-stream',
objTypeProto: SfTransactionTraceMessageLegacy,
transform: transform_transaction_trace_legacy,
timeline: true,
},
},
[FILE_TYPES.PROTO_LOG]: {
name: 'ProtoLog',
decoder: protoDecoder,
@@ -643,6 +671,9 @@ function detectAndDecode(buffer, fileName, store) {
if (arrayStartsWith(buffer, MPEG4_MAGIC_NMBER)) {
return decodedFile(FILE_TYPES.SCREEN_RECORDING, buffer, fileName, store);
}
if (arrayStartsWith(buffer, TRANSACTIONS_TRACE_MAGIC_NUMBER)) {
return decodedFile(FILE_TYPES.TRANSACTIONS_TRACE, buffer, fileName, store);
}
if (arrayStartsWith(buffer, WAYLAND_TRACE_MAGIC_NUMBER)) {
return decodedFile(FILE_TYPES.WAYLAND_TRACE, buffer, fileName, store);
}
@@ -673,10 +704,10 @@ function detectAndDecode(buffer, fileName, store) {
// TODO(b/169305853): Add magic number at beginning of file for better auto detection
for (const [filetype, condition] of [
[FILE_TYPES.TRANSACTIONS_TRACE, (file) => file.data.length > 0],
[FILE_TYPES.TRANSACTIONS_TRACE_LEGACY, (file) => file.data.length > 0],
[FILE_TYPES.WAYLAND_DUMP, (file) => (file.data.length > 0 && file.data.children[0] > 0) || file.data.length > 1],
[FILE_TYPES.WINDOW_MANAGER_DUMP],
[FILE_TYPES.SURFACE_FLINGER_DUMP],
[FILE_TYPES.SURFACE_FLINGER_DUMP]
]) {
try {
const [, fileData] = decodedFile(filetype, buffer, fileName, store);

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
import {toSize, toBuffer, toColor, toPoint, toRect,
toRectF, toRegion, toTransform} from './common';
import {toSize, toActiveBuffer, toColor, toColor3, toPoint, toRect,
toRectF, toRegion, toMatrix22, toTransform} from './common';
import intDefMapping from
'../../../../../prebuilts/misc/common/winscope/intDefMapping.json';
import config from '../config/Configuration.json'
@@ -99,7 +99,7 @@ export default class ObjectFormatter {
if (value === null || value === undefined) {
if (this.displayDefaults) {
result[key] = value
result[key] = value;
}
return
}
@@ -112,31 +112,35 @@ export default class ObjectFormatter {
} else if (value.prettyPrint) {
const isEmpty = value.isEmpty === true;
if (!isEmpty || this.displayDefaults) {
result[key] = value.prettyPrint()
result[key] = value.prettyPrint();
}
} else {
// converted proto to flicker
const translatedObject = this.translateObject(value)
const translatedObject = this.translateObject(value);
if (translatedObject) {
result[key] = translatedObject.prettyPrint()
if (translatedObject.prettyPrint) {
result[key] = translatedObject.prettyPrint();
}
else {
result[key] = translatedObject;
}
// objects - recursive call
} else if (value && typeof(value) == `object`) {
const childObj = this.format(value) as any
const isEmpty = Object.entries(childObj).length == 0 || childObj.isEmpty
const childObj = this.format(value) as any;
const isEmpty = Object.entries(childObj).length == 0 || childObj.isEmpty;
if (!isEmpty || this.displayDefaults) {
result[key] = childObj
result[key] = childObj;
}
} else {
// values
result[key] = this.translateIntDef(obj, key, value)
result[key] = this.translateIntDef(obj, key, value);
}
}
}
})
// return Object.freeze(result)
return result
return result;
}
/**
@@ -147,23 +151,25 @@ export default class ObjectFormatter {
* @param obj Object to translate
*/
private static translateObject(obj) {
const type = obj?.$type?.name
const type = obj?.$type?.name;
switch(type) {
case `SizeProto`: return toSize(obj)
case `ActiveBufferProto`: return toBuffer(obj)
case `ColorProto`: return toColor(obj)
case `PointProto`: return toPoint(obj)
case `RectProto`: return toRect(obj)
case `FloatRectProto`: return toRectF(obj)
case `RegionProto`: return toRegion(obj)
case `TransformProto`: return toTransform(obj)
case `SizeProto`: return toSize(obj);
case `ActiveBufferProto`: return toActiveBuffer(obj);
case `Color3`: return toColor3(obj);
case `ColorProto`: return toColor(obj);
case `PointProto`: return toPoint(obj);
case `RectProto`: return toRect(obj);
case `Matrix22`: return toMatrix22(obj);
case `FloatRectProto`: return toRectF(obj);
case `RegionProto`: return toRegion(obj);
case `TransformProto`: return toTransform(obj);
case 'ColorTransformProto': {
const formatted = this.formatColorTransform(obj.val);
return `${formatted}`;
}
}
return null
return null;
}
private static formatColorTransform(vals) {
@@ -184,17 +190,17 @@ export default class ObjectFormatter {
* @param propertyName Property to search
*/
private static getTypeDefSpec(obj: any, propertyName: string): string {
const fields = obj?.$type?.fields
const fields = obj?.$type?.fields;
if (!fields) {
return null
return null;
}
const options = fields[propertyName]?.options
const options = fields[propertyName]?.options;
if (!options) {
return null
return null;
}
return options["(.android.typedef)"]
return options["(.android.typedef)"];
}
/**
@@ -207,23 +213,23 @@ export default class ObjectFormatter {
* @param value Property value
*/
private static translateIntDef(parentObj: any, propertyName: string, value: any): string {
const parentClassName = parentObj.constructor.name
const propertyPath = `${parentClassName}.${propertyName}`
const parentClassName = parentObj.constructor.name;
const propertyPath = `${parentClassName}.${propertyName}`;
let translatedValue = value
let translatedValue = value;
// Parse Flicker objects (no intdef annotation supported)
if (this.FLICKER_INTDEF_MAP.has(propertyPath)) {
translatedValue = this.getIntFlagsAsStrings(value,
this.FLICKER_INTDEF_MAP.get(propertyPath))
this.FLICKER_INTDEF_MAP.get(propertyPath));
} else {
// If it's a proto, search on the proto definition for the intdef type
const typeDefSpec = this.getTypeDefSpec(parentObj, propertyName)
const typeDefSpec = this.getTypeDefSpec(parentObj, propertyName);
if (typeDefSpec) {
translatedValue = this.getIntFlagsAsStrings(value, typeDefSpec)
translatedValue = this.getIntFlagsAsStrings(value, typeDefSpec);
}
}
return translatedValue
return translatedValue;
}
/**

View File

@@ -62,8 +62,10 @@ const LayerTraceEntryBuilder = require('flicker').com.android.server.wm.traces.
common.layers.LayerTraceEntryBuilder;
const LayersTrace = require('flicker').com.android.server.wm.traces.common.
layers.LayersTrace;
const Matrix = require('flicker').com.android.server.wm.traces.common.layers.
Transform.Matrix;
const Matrix22 = require('flicker').com.android.server.wm.traces.common
.Matrix22;
const Matrix33 = require('flicker').com.android.server.wm.traces.common
.Matrix33;
const Transform = require('flicker').com.android.server.wm.traces.common.
layers.Transform;
const Display = require('flicker').com.android.server.wm.traces.common.
@@ -71,7 +73,9 @@ const Display = require('flicker').com.android.server.wm.traces.common.
// Common
const Size = require('flicker').com.android.server.wm.traces.common.Size;
const Buffer = require('flicker').com.android.server.wm.traces.common.Buffer;
const ActiveBuffer = require('flicker').com.android.server.wm.traces.common
.ActiveBuffer;
const Color3 = require('flicker').com.android.server.wm.traces.common.Color3;
const Color = require('flicker').com.android.server.wm.traces.common.Color;
const Point = require('flicker').com.android.server.wm.traces.common.Point;
const Rect = require('flicker').com.android.server.wm.traces.common.Rect;
@@ -91,13 +95,15 @@ const ErrorTrace = require('flicker').com.android.server.wm.traces.common.errors
// Service
const TaggingEngine = require('flicker').com.android.server.wm.traces.common.service.TaggingEngine;
const EMPTY_BUFFER = new Buffer(0, 0, 0, 0);
const EMPTY_BUFFER = new ActiveBuffer(0, 0, 0, 0);
const EMPTY_COLOR3 = new Color3(-1, -1, -1);
const EMPTY_COLOR = new Color(-1, -1, -1, 0);
const EMPTY_RECT = new Rect(0, 0, 0, 0);
const EMPTY_RECTF = new RectF(0, 0, 0, 0);
const EMPTY_POINT = new Point(0, 0);
const EMPTY_MATRIX = new Matrix(0, 0, 0, 0, 0, 0);
const EMPTY_TRANSFORM = new Transform(0, EMPTY_MATRIX);
const EMPTY_MATRIX22 = new Matrix22(0, 0, 0, 0, 0, 0);
const EMPTY_MATRIX33 = new Matrix33(0, 0, 0, 0, 0, 0);
const EMPTY_TRANSFORM = new Transform(0, EMPTY_MATRIX33);
function toSize(proto) {
if (proto == null) {
@@ -111,18 +117,31 @@ function toSize(proto) {
return EMPTY_BOUNDS;
}
function toBuffer(proto) {
function toActiveBuffer(proto) {
const width = proto?.width ?? 0;
const height = proto?.height ?? 0;
const stride = proto?.stride ?? 0;
const format = proto?.format ?? 0;
if (width || height || stride || format) {
return new Buffer(width, height, stride, format);
return new ActiveBuffer(width, height, stride, format);
}
return EMPTY_BUFFER;
}
function toColor3(proto) {
if (proto == null) {
return EMPTY_COLOR;
}
const r = proto.r ?? 0;
const g = proto.g ?? 0;
const b = proto.b ?? 0;
if (r || g || b) {
return new Color3(r, g, b);
}
return EMPTY_COLOR3;
}
function toColor(proto) {
if (proto == null) {
return EMPTY_COLOR;
@@ -206,16 +225,32 @@ function toTransform(proto) {
const ty = proto.ty ?? 0;
if (dsdx || dtdx || tx || dsdy || dtdy || ty) {
const matrix = new Matrix(dsdx, dtdx, tx, dsdy, dtdy, ty);
const matrix = new Matrix33(dsdx, dtdx, tx, dsdy, dtdy, ty);
return new Transform(proto.type ?? 0, matrix);
}
if (proto.type) {
return new Transform(proto.type ?? 0, EMPTY_MATRIX);
return new Transform(proto.type ?? 0, EMPTY_MATRIX33);
}
return EMPTY_TRANSFORM;
}
function toMatrix22(proto) {
if (proto == null) {
return EMPTY_MATRIX22;
}
const dsdx = proto.dsdx ?? 0;
const dtdx = proto.dtdx ?? 0;
const dsdy = proto.dsdy ?? 0;
const dtdy = proto.dtdy ?? 0;
if (dsdx || dtdx || dsdy || dtdy) {
return new Matrix22(dsdx, dtdx, dsdy, dtdy);
}
return EMPTY_MATRIX22;
}
export {
Activity,
Configuration,
@@ -240,7 +275,8 @@ export {
LayerTraceEntryBuilder,
LayersTrace,
Transform,
Matrix,
Matrix22,
Matrix33,
Display,
// Tags
Tag,
@@ -252,8 +288,9 @@ export {
ErrorTrace,
// Common
Size,
Buffer,
ActiveBuffer,
Color,
Color3,
Point,
Rect,
RectF,
@@ -261,11 +298,13 @@ export {
// Service
TaggingEngine,
toSize,
toBuffer,
toActiveBuffer,
toColor,
toColor3,
toPoint,
toRect,
toRectF,
toRegion,
toMatrix22,
toTransform,
};

View File

@@ -15,14 +15,14 @@
*/
import { Layer, Rect, toBuffer, toColor, toRect, toRectF, toRegion } from "../common"
import { Layer, Rect, toActiveBuffer, toColor, toRect, toRectF, toRegion } from "../common"
import { shortenName } from '../mixin'
import { RELATIVE_Z_CHIP, GPU_CHIP, HWC_CHIP } from '../treeview/Chips'
import Transform from './Transform'
Layer.fromProto = function (proto: any): Layer {
const visibleRegion = toRegion(proto.visibleRegion)
const activeBuffer = toBuffer(proto.activeBuffer)
const activeBuffer = toActiveBuffer(proto.activeBuffer)
const bounds = toRectF(proto.bounds)
const color = toColor(proto.color)
const screenBounds = toRectF(proto.screenBounds)

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { Transform, Matrix } from "../common"
import { Transform, Matrix33 } from "../common"
Transform.fromProto = function (transformProto, positionProto): Transform {
const entry = new Transform(
@@ -24,7 +24,7 @@ Transform.fromProto = function (transformProto, positionProto): Transform {
return entry
}
function getMatrix(transform, position): Matrix {
function getMatrix(transform, position): Matrix33 {
const x = position?.x ?? 0
const y = position?.y ?? 0
@@ -32,33 +32,33 @@ function getMatrix(transform, position): Matrix {
return getDefaultTransform(transform?.type, x, y)
}
return new Matrix(transform.dsdx, transform.dtdx, x, transform.dsdy, transform.dtdy, y)
return new Matrix33(transform.dsdx, transform.dtdx, x, transform.dsdy, transform.dtdy, y)
}
function getDefaultTransform(type, x, y): Matrix {
function getDefaultTransform(type, x, y): Matrix33 {
// IDENTITY
if (!type) {
return new Matrix(1, 0, x, 0, 1, y)
return new Matrix33(1, 0, x, 0, 1, y)
}
// ROT_270 = ROT_90|FLIP_H|FLIP_V
if (isFlagSet(type, ROT_90_VAL | FLIP_V_VAL | FLIP_H_VAL)) {
return new Matrix(0, -1, x, 1, 0, y)
return new Matrix33(0, -1, x, 1, 0, y)
}
// ROT_180 = FLIP_H|FLIP_V
if (isFlagSet(type, FLIP_V_VAL | FLIP_H_VAL)) {
return new Matrix(-1, 0, x, 0, -1, y)
return new Matrix33(-1, 0, x, 0, -1, y)
}
// ROT_90
if (isFlagSet(type, ROT_90_VAL)) {
return new Matrix(0, 1, x, -1, 0, y)
return new Matrix33(0, 1, x, -1, 0, y)
}
// IDENTITY
if (isFlagClear(type, SCALE_VAL | ROTATE_VAL)) {
return new Matrix(1, 0, x, 0, 1, y)
return new Matrix33(1, 0, x, 0, 1, y)
}
throw new Error(`Unknown transform type ${type}`)
@@ -87,4 +87,4 @@ const FLIP_V_VAL = 0x0200 // (1 << 1 << 8)
const ROT_90_VAL = 0x0400 // (1 << 2 << 8)
const ROT_INVALID_VAL = 0x8000 // (0x80 << 8)
export default Transform
export default Transform

View File

@@ -33,7 +33,7 @@ Vue.use(VueMaterial)
const fileOrder = {
[TRACE_TYPES.WINDOW_MANAGER]: 1,
[TRACE_TYPES.SURFACE_FLINGER]: 2,
[TRACE_TYPES.TRANSACTION]: 3,
[TRACE_TYPES.TRANSACTION_LEGACY]: 3,
[TRACE_TYPES.PROTO_LOG]: 4,
[TRACE_TYPES.IME_CLIENTS]: 5,
[TRACE_TYPES.IME_SERVICE]: 6,
@@ -416,7 +416,7 @@ Vue.mixin({
this.$gtag.event(string, {
'event_category': "Opened trace",
'event_label': "Winscope Interactions",
'value': field,
'value': entryType,
});
},
recordChangedNavigationStyleEvent(field) {

View File

@@ -21,6 +21,7 @@ const mixin = {
return file.type == TRACE_TYPES.WINDOW_MANAGER ||
file.type == TRACE_TYPES.ACCESSIBILITY ||
file.type == TRACE_TYPES.SURFACE_FLINGER ||
file.type == TRACE_TYPES.TRANSACTION ||
file.type == TRACE_TYPES.WAYLAND ||
file.type == TRACE_TYPES.SYSTEM_UI ||
file.type == TRACE_TYPES.LAUNCHER ||
@@ -48,12 +49,15 @@ const mixin = {
isTransactions(file) {
return file.type == TRACE_TYPES.TRANSACTION;
},
isTransactionsLegacy(file) {
return file.type == TRACE_TYPES.TRANSACTION_LEGACY;
},
isLog(file) {
return file.type == TRACE_TYPES.PROTO_LOG;
},
hasDataView(file) {
return this.isLog(file) || this.showInTraceView(file) ||
this.isTransactions(file);
this.isTransactionsLegacy(file);
},
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020, The Android Open Source Project
* Copyright 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +17,8 @@
import { FILE_TYPES, TRACE_TYPES } from '@/decode.js';
import TraceBase from './TraceBase';
export default class Transactions extends TraceBase {
export default class TransactionsTrace extends TraceBase {
transactionsFile: Object;
transactionHistory: TransactionHistory;
constructor(files: any[]) {
const transactionsFile = files[FILE_TYPES.TRANSACTIONS_TRACE];
@@ -27,197 +26,9 @@ export default class Transactions extends TraceBase {
super(transactionsFile.data, transactionsFile.timeline, files);
this.transactionsFile = transactionsFile;
// Create new transaction history
this.transactionHistory = new TransactionHistory(transactionsFile);
}
get type() {
return TRACE_TYPES.TRANSACTION;
}
}
class TransactionHistory {
history: Object;
applied: Object;
mergeTrees: any;
constructor(transactionsEventsFiles) {
this.history = {};
this.applied = {};
if (!transactionsEventsFiles) {
return;
}
for (const eventsFile of transactionsEventsFiles) {
for (const event of eventsFile.data) {
if (event.merge) {
const merge = event.merge;
const originalId = merge.originalTransaction.id;
const mergedId = merge.mergedTransaction.id;
this.addMerge(originalId, mergedId);
} else if (event.apply) {
this.addApply(event.apply.tx_id);
}
}
}
}
addMerge(originalId, mergedId) {
const merge = new Merge(originalId, mergedId, this.history);
this.addToHistoryOf(originalId, merge);
}
addApply(transactionId) {
this.applied[transactionId] = true;
this.addToHistoryOf(transactionId, new Apply(transactionId));
}
addToHistoryOf(transactionId, event) {
if (!this.history[transactionId]) {
this.history[transactionId] = [];
}
this.history[transactionId].push(event);
}
generateHistoryTreesOf(transactionId) {
return this._generateHistoryTree(transactionId);
}
_generateHistoryTree(transactionId, upTo = null) {
if (!this.history[transactionId]) {
return [];
}
const children = [];
const events = this.history[transactionId];
for (let i = 0; i < (upTo ?? events.length); i++) {
const event = events[i];
if (event instanceof Merge) {
const historyTree = this.
_generateHistoryTree(event.mergedId, event.mergedAt);
const mergeTreeNode = new MergeTreeNode(event.mergedId, historyTree);
children.push(mergeTreeNode);
} else if (event instanceof Apply) {
children.push(new ApplyTreeNode());
} else {
throw new Error('Unhandled event type');
}
}
return children;
}
/**
* Generates the list of all the transactions that have ever been merged into
* the target transaction directly or indirectly through the merges of
* transactions that ended up being merged into the transaction.
* This includes both merges that occur before and after the transaction is
* applied.
* @param {Number} transactionId - The id of the transaction we want the list
* of transactions merged in for
* @return {Set<Number>} a set of all the transaction ids that are in the
* history of merges of the transaction
*/
allTransactionsMergedInto(transactionId) {
const allTransactionsMergedIn = new Set();
let event;
const toVisit = this.generateHistoryTreesOf(transactionId);
while (event = toVisit.pop()) {
if (event instanceof MergeTreeNode) {
allTransactionsMergedIn.add(event.mergedId);
for (const child of event.children) {
toVisit.push(child);
}
}
}
return allTransactionsMergedIn;
}
/**
* Generated the list of transactions that have been directly merged into the
* target transaction those are transactions that have explicitly been merged
* in the code with a call to merge.
* @param {Number} transactionId - The id of the target transaction.
* @return {Array<Number>} an array of the transaction ids of the transactions
* directly merged into the target transaction
*/
allDirectMergesInto(transactionId) {
return (this.history[transactionId] ?? [])
.filter((event) => event instanceof Merge)
.map((merge) => merge.mergedId);
}
}
class MergeTreeNode {
mergedId: Number;
mergedTransactionHistory: TransactionHistory;
children: TransactionHistory[];
constructor(mergedId, mergedTransactionHistory) {
this.mergedId = mergedId;
this.mergedTransactionHistory = mergedTransactionHistory;
this.children = mergedTransactionHistory;
}
get type() {
return 'merge';
}
}
class ApplyTreeNode {
children: any[];
constructor() {
this.children = [];
}
get type() {
return 'apply';
}
}
class Merge {
originalId: Number;
mergedId: Number;
mergedAt: Number;
constructor(originalId, mergedId, history) {
this.originalId = originalId;
this.mergedId = mergedId;
// Specifies how long the merge chain of the merged transaction was at the
// time is was merged.
this.mergedAt = history[mergedId]?.length ?? 0;
}
}
class Apply {
transactionId: Number;
constructor(transactionId) {
this.transactionId = transactionId;
}
}
/**
* Converts the transactionId to the values that compose the identifier.
* The top 32 bits is the PID of the process that created the transaction
* and the bottom 32 bits is the ID of the transaction unique within that
* process.
* @param {Number} transactionId
* @return {Object} An object containing the id and pid of the transaction.
*/
export function expandTransactionId(transactionId) {
// Can't use bit shift operation because it isn't a 32 bit integer...
// Because js uses floating point numbers for everything, maths isn't 100%
// accurate so we need to round...
return Object.freeze({
id: Math.round(transactionId % Math.pow(2, 32)),
pid: Math.round(transactionId / Math.pow(2, 32)),
});
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { FILE_TYPES, TRACE_TYPES } from '@/decode.js';
import TraceBase from './TraceBase';
/**
* @deprecated This trace has been replaced by the new transactions trace
*/
export default class TransactionsTraceLegacy extends TraceBase {
transactionsFile: Object;
transactionHistory: TransactionHistory;
constructor(files: any[]) {
const transactionsFile = files[FILE_TYPES.TRANSACTIONS_TRACE_LEGACY];
super(transactionsFile.data, transactionsFile.timeline, files);
this.transactionsFile = transactionsFile;
// Create new transaction history
this.transactionHistory = new TransactionHistory(transactionsFile);
}
get type() {
return TRACE_TYPES.TRANSACTION_LEGACY;
}
}
class TransactionHistory {
history: Object;
applied: Object;
mergeTrees: any;
constructor(transactionsEventsFiles) {
this.history = {};
this.applied = {};
if (!transactionsEventsFiles) {
return;
}
for (const eventsFile of transactionsEventsFiles) {
for (const event of eventsFile.data) {
if (event.merge) {
const merge = event.merge;
const originalId = merge.originalTransaction.id;
const mergedId = merge.mergedTransaction.id;
this.addMerge(originalId, mergedId);
} else if (event.apply) {
this.addApply(event.apply.tx_id);
}
}
}
}
addMerge(originalId, mergedId) {
const merge = new Merge(originalId, mergedId, this.history);
this.addToHistoryOf(originalId, merge);
}
addApply(transactionId) {
this.applied[transactionId] = true;
this.addToHistoryOf(transactionId, new Apply(transactionId));
}
addToHistoryOf(transactionId, event) {
if (!this.history[transactionId]) {
this.history[transactionId] = [];
}
this.history[transactionId].push(event);
}
generateHistoryTreesOf(transactionId) {
return this._generateHistoryTree(transactionId);
}
_generateHistoryTree(transactionId, upTo = null) {
if (!this.history[transactionId]) {
return [];
}
const children = [];
const events = this.history[transactionId];
for (let i = 0; i < (upTo ?? events.length); i++) {
const event = events[i];
if (event instanceof Merge) {
const historyTree = this.
_generateHistoryTree(event.mergedId, event.mergedAt);
const mergeTreeNode = new MergeTreeNode(event.mergedId, historyTree);
children.push(mergeTreeNode);
} else if (event instanceof Apply) {
children.push(new ApplyTreeNode());
} else {
throw new Error('Unhandled event type');
}
}
return children;
}
/**
* Generates the list of all the transactions that have ever been merged into
* the target transaction directly or indirectly through the merges of
* transactions that ended up being merged into the transaction.
* This includes both merges that occur before and after the transaction is
* applied.
* @param {Number} transactionId - The id of the transaction we want the list
* of transactions merged in for
* @return {Set<Number>} a set of all the transaction ids that are in the
* history of merges of the transaction
*/
allTransactionsMergedInto(transactionId) {
const allTransactionsMergedIn = new Set();
let event;
const toVisit = this.generateHistoryTreesOf(transactionId);
while (event = toVisit.pop()) {
if (event instanceof MergeTreeNode) {
allTransactionsMergedIn.add(event.mergedId);
for (const child of event.children) {
toVisit.push(child);
}
}
}
return allTransactionsMergedIn;
}
/**
* Generated the list of transactions that have been directly merged into the
* target transaction those are transactions that have explicitly been merged
* in the code with a call to merge.
* @param {Number} transactionId - The id of the target transaction.
* @return {Array<Number>} an array of the transaction ids of the transactions
* directly merged into the target transaction
*/
allDirectMergesInto(transactionId) {
return (this.history[transactionId] ?? [])
.filter((event) => event instanceof Merge)
.map((merge) => merge.mergedId);
}
}
class MergeTreeNode {
mergedId: Number;
mergedTransactionHistory: TransactionHistory;
children: TransactionHistory[];
constructor(mergedId, mergedTransactionHistory) {
this.mergedId = mergedId;
this.mergedTransactionHistory = mergedTransactionHistory;
this.children = mergedTransactionHistory;
}
get type() {
return 'merge';
}
}
class ApplyTreeNode {
children: any[];
constructor() {
this.children = [];
}
get type() {
return 'apply';
}
}
class Merge {
originalId: Number;
mergedId: Number;
mergedAt: Number;
constructor(originalId, mergedId, history) {
this.originalId = originalId;
this.mergedId = mergedId;
// Specifies how long the merge chain of the merged transaction was at the
// time is was merged.
this.mergedAt = history[mergedId]?.length ?? 0;
}
}
class Apply {
transactionId: Number;
constructor(transactionId) {
this.transactionId = transactionId;
}
}
/**
* Converts the transactionId to the values that compose the identifier.
* The top 32 bits is the PID of the process that created the transaction
* and the bottom 32 bits is the ID of the transaction unique within that
* process.
* @param {Number} transactionId
* @return {Object} An object containing the id and pid of the transaction.
*/
export function expandTransactionId(transactionId) {
// Can't use bit shift operation because it isn't a 32 bit integer...
// Because js uses floating point numbers for everything, maths isn't 100%
// accurate so we need to round...
return Object.freeze({
id: Math.round(transactionId % Math.pow(2, 32)),
pid: Math.round(transactionId / Math.pow(2, 32)),
});
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019, The Android Open Source Project
* Copyright 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,69 +14,59 @@
* limitations under the License.
*/
import {nanos_to_string} from './transform.js';
import {nanos_to_string, transform} from './transform.js'
function transform_transaction(transaction, layerIdToName) {
const transactions = [];
for (const surfaceChange of transaction.surfaceChange) {
transactions.push(Object.freeze({
type: 'surfaceChange',
obj: surfaceChange,
layerName: layerIdToName[surfaceChange.id],
}));
}
for (const displayChange of transaction.displayChange) {
transactions.push(Object.freeze({
type: 'displayChange',
obj: displayChange,
layerName: layerIdToName[displayChange.id],
}));
}
return transactions;
function transform_change(change_data) {
const kind = change_data.__proto__.$type.name;
const name = change_data.layerId || change_data.id;
return transform({
kind: kind,
name: name,
stableId: kind + name,
obj: change_data,
children: [],
isVisible: true,
});
}
function transform_entry(entry, layerIdToName) {
const type = entry.increment;
const timestamp = entry.timeStamp;
const time = nanos_to_string(timestamp);
switch (type) {
case 'transaction':
return Object.freeze({
type,
// TODO: Rename to changes
transactions: transform_transaction(entry.transaction, layerIdToName),
synchronous: entry.transaction.synchronous,
animation: entry.transaction.animation,
identifier: entry.transaction.id,
time,
origin: entry.transaction.origin,
timestamp,
});
case 'surfaceCreation':
// NOTE: There is no break on purpose — we want to fall through to default
layerIdToName[entry[type].id] = entry[type].name;
default:
return Object.freeze({
type,
obj: entry[type],
layerName: entry[type].name ?? layerIdToName[entry[type].id],
time,
timestamp,
});
}
function transform_transaction_state(transaction_state) {
const obj = Object.assign({}, transaction_state)
if (obj.displayChanges) delete obj.displayChanges;
if (obj.layerChanges) delete obj.layerChanges;
const stableId = 'pid=' + transaction_state.pid +
' uid=' + transaction_state.uid +
' postTime=' + transaction_state.postTime;
return transform({
kind: 'TransactionState',
name: stableId,
stableId: stableId,
obj: obj,
children: [
[
[...transaction_state.layerChanges, ...transaction_state.displayChanges],
transform_change]
]
});
}
function transform_transaction_trace(entries) {
const layerIdToName = {};
const data = entries.increment.map((entry) => transform_entry(entry, layerIdToName));
function transform_transaction_trace_entry(entry) {
const obj = Object.assign({}, entry)
if (obj.transactions) delete obj.transactions;
return transform({
obj: obj,
kind: 'entry',
stableId: 'entry',
timestamp: entry.elapsedRealtimeNanos,
name: nanos_to_string(entry.elapsedRealtimeNanos),
children: [
[entry.transactions, transform_transaction_state]
],
});
}
function transform_transaction_trace(trace) {
const data = trace.entry.map((entry) => transform_transaction_trace_entry(entry));
return {children: data};
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {nanos_to_string} from './transform.js';
function transform_transaction(transaction, layerIdToName) {
const transactions = [];
for (const surfaceChange of transaction.surfaceChange) {
transactions.push(Object.freeze({
type: 'surfaceChange',
obj: surfaceChange,
layerName: layerIdToName[surfaceChange.id],
}));
}
for (const displayChange of transaction.displayChange) {
transactions.push(Object.freeze({
type: 'displayChange',
obj: displayChange,
layerName: layerIdToName[displayChange.id],
}));
}
return transactions;
}
function transform_entry(entry, layerIdToName) {
const type = entry.increment;
const timestamp = entry.timeStamp;
const time = nanos_to_string(timestamp);
switch (type) {
case 'transaction':
return Object.freeze({
type,
// TODO: Rename to changes
transactions: transform_transaction(entry.transaction, layerIdToName),
synchronous: entry.transaction.synchronous,
animation: entry.transaction.animation,
identifier: entry.transaction.id,
time,
origin: entry.transaction.origin,
timestamp,
});
case 'surfaceCreation':
// NOTE: There is no break on purpose — we want to fall through to default
layerIdToName[entry[type].id] = entry[type].name;
default:
return Object.freeze({
type,
obj: entry[type],
layerName: entry[type].name ?? layerIdToName[entry[type].id],
time,
timestamp,
});
}
}
/**
* @deprecated This trace has been replaced by the new transactions trace
*/
function transform_transaction_trace_legacy(entries) {
const layerIdToName = {};
const data = entries.increment.map((entry) => transform_entry(entry, layerIdToName));
return {children: data};
}
export {transform_transaction_trace_legacy};