Display transaction merge information in Winscope
Test: N/A
Change-Id: I04836e844e2aa3158c36c12e375eca365c003ada
diff --git a/tools/winscope/src/TransactionEntry.vue b/tools/winscope/src/TransactionEntry.vue
index 138bca1..fb0702b 100644
--- a/tools/winscope/src/TransactionEntry.vue
+++ b/tools/winscope/src/TransactionEntry.vue
@@ -18,18 +18,29 @@
</div>
</div>
<div class="type-column">{{transactionTypeOf(source)}}</div>
- <div class="origin-column">
- <span style="white-space: pre;">{{formatOrigin(source)}}</span>
- </div>
<div class="affected-surfaces-column">
- <span v-for="(surface, index) in sufacesAffectedBy(source)" v-bind:key="surface.id">
- <span v-if="surface.name" class="surface-name"> {{ surface.name }}</span>
+ <span
+ v-for="(surface, index) in sufacesAffectedBy(source)"
+ v-bind:key="surface.id"
+ >
+ <span v-if="surface.name" class="surface-name">{{ surface.name }}</span>
<span class="surface-id">
+ <!-- eslint-disable-next-line max-len -->
<span v-if="surface.name">(</span>{{surface.id}}<span v-if="surface.name">)</span>
</span>
<span v-if="index + 1 < sufacesAffectedBy(source).length">, </span>
</span>
</div>
+ <div class="extra-info-column">
+ <span v-if="source.identifier">
+ <!-- eslint-disable-next-line max-len -->
+ Tx Id: <span class="light">{{ prettifyTransactionId(source.identifier) }}</span><br/>
+ </span>
+ <span v-if="source.origin">
+ PID: <span class="light">{{ source.origin.pid }}</span><br/>
+ TID: <span class="light">{{ source.origin.uid }}</span><br/>
+ </span>
+ </div>
</div>
</template>
@@ -42,16 +53,22 @@
},
source: {
type: Object,
- default () {
- return {}
- }
+ default() {
+ return {};
+ },
},
onClick: {
type: Function,
},
selectedTransaction: {
type: Object,
- }
+ },
+ transactionsTrace: {
+ type: Object,
+ },
+ prettifyTransactionId: {
+ type: Function,
+ },
},
computed: {
currentTimestamp() {
@@ -60,6 +77,27 @@
isSelected() {
return this.source === this.selectedTransaction;
},
+ hasOverrideChangeDueToMerge() {
+ const transaction = this.source;
+
+ if (!transaction.identifier) {
+ return;
+ }
+
+ // console.log('transaction', transaction.identifier);
+
+ // const history = this.transactionsTrace.transactionHistory;
+
+ // const allTransactionsMergedInto = history
+ // .allTransactionsMergedInto(transaction.identifier);
+ // console.log('All merges', allTransactionsMergedInto);
+
+ // console.log('Direct merges',
+ // history.allDirectMergesInto(transaction.identifier));
+
+
+ return true;
+ },
},
methods: {
setTimelineTime(timestamp) {
@@ -71,13 +109,13 @@
}
if (transaction.transactions.length === 0) {
- return "Empty Transaction";
+ return 'Empty Transaction';
}
const types = new Set();
- transaction.transactions.forEach(t => types.add(t.type));
+ transaction.transactions.forEach((t) => types.add(t.type));
- return Array.from(types).join(", ");
+ return Array.from(types).join(', ');
},
sufacesAffectedBy(transaction) {
if (transaction.type !== 'transaction') {
@@ -95,25 +133,10 @@
}
}
- return affectedSurfaces
- },
- formatOrigin(transaction) {
- if (!transaction.origin) {
- return "unavailable";
- }
-
- const originString = [];
- originString.push(`PID: ${transaction.origin.pid}`);
- originString.push(`UID: ${transaction.origin.uid}`);
-
- if (transaction.origin.appliedByMainThread) {
- originString.push("Applied by main thread");
- }
-
- return originString.join("\n");
+ return affectedSurfaces;
},
},
-}
+};
</script>
<style scoped>
.time-column {
@@ -138,6 +161,10 @@
width: 30em;
}
+.extra-info-column {
+ width: 20em;
+}
+
.entry {
display: inline-flex;
cursor: pointer;
@@ -190,4 +217,12 @@
.inactive .affected-surfaces-column .surface-id {
color: #b4b4b4
}
-</style>
\ No newline at end of file
+
+.light {
+ color: #999999
+}
+
+.inactive .light {
+ color: #b4b4b4
+}
+</style>
diff --git a/tools/winscope/src/TransactionsView.vue b/tools/winscope/src/TransactionsView.vue
index c89b52d..66002a3 100644
--- a/tools/winscope/src/TransactionsView.vue
+++ b/tools/winscope/src/TransactionsView.vue
@@ -81,7 +81,12 @@
:data-key="'timestamp'"
:data-sources="filteredData"
:data-component="transactionEntryComponent"
- :extra-props="{onClick: transactionSelected, selectedTransaction }"
+ :extra-props="{
+ onClick: transactionSelected,
+ selectedTransaction,
+ transactionsTrace,
+ prettifyTransactionId,
+ }"
ref="loglist"
/>
</flat-card>
@@ -95,12 +100,22 @@
<h2 class="md-title" style="flex: 1">Changes</h2>
</md-content>
<div class="changes-content" v-if="selectedTree">
- <div v-if="selectedTransaction.type === 'transaction'">
+ <div
+ v-if="selectedTransaction.type === 'transaction'"
+ class="transaction-events"
+ >
<div
- v-for="history in transactionHistory(selectedTransaction)"
- v-bind:key="history.id"
+ v-for="(event, i) in transactionHistory(selectedTransaction)"
+ v-bind:key="`${selectedTransaction.identifier}-${i}`"
+ class="transaction-event"
>
- {{ history.type }}
+ <div v-if="event.type === 'apply'" class="applied-event">
+ applied
+ </div>
+ <div v-if="event.type === 'merge'" class="merged-event">
+ <!-- eslint-disable-next-line max-len -->
+ {{ prettifyTransactionId(event.mergedId) }}
+ </div>
</div>
</div>
<tree-view
@@ -126,6 +141,7 @@
import FlatCard from './components/FlatCard.vue';
import {ObjectTransformer} from './transform.js';
+import {expandTransactionId} from '@/traces/Transactions.js';
export default {
name: 'transactionsview',
@@ -168,6 +184,7 @@
selectedTransaction: null,
transactionEntryComponent: TransactionEntry,
transactionsTrace,
+ expandTransactionId,
};
},
computed: {
@@ -411,27 +428,12 @@
const history = this.transactionsTrace.transactionHistory
.generateHistoryTreesOf(transactionId);
- const historyElements = [];
- for (const [i, event] of history.entries()) {
- const elementId = transactionId + '.' + i;
+ return history;
+ },
- switch (event.type) {
- case 'apply':
- break;
- case 'merge':
- break;
- default:
- throw new Error('Unhandled event type');
- }
-
- const element = {
- id: elementId,
- type: event.type,
- };
- historyElements.push(element);
- }
-
- return historyElements;
+ prettifyTransactionId(transactionId) {
+ const expandedId = expandTransactionId(transactionId);
+ return `${expandedId.pid}.${expandedId.id}`;
},
},
components: {
diff --git a/tools/winscope/src/decode.js b/tools/winscope/src/decode.js
index 271d219..7b5dce2 100644
--- a/tools/winscope/src/decode.js
+++ b/tools/winscope/src/decode.js
@@ -14,82 +14,84 @@
* limitations under the License.
*/
+/* eslint-disable max-len */
+/* eslint-disable camelcase */
-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 jsonProtoDefsTransactionEvents from 'frameworks/native/libs/gui/proto/src/transactions.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'
-import protobuf from 'protobufjs'
-import { transform_layers, transform_layers_trace } from './transform_sf.js'
-import { transform_window_service, transform_window_trace } from './transform_wm.js'
-import { transform_transaction_trace, transform_TRANSACTION_EVENTS_TRACE } from './transform_transaction.js'
-import { transform_wl_outputstate, transform_wayland_trace } from './transform_wl.js'
-import { transform_protolog } from './transform_protolog.js'
-import { transform_sysui_trace } from './transform_sys_ui.js'
-import { transform_launcher_trace } from './transform_launcher.js'
-import { fill_transform_data } from './matrix_utils.js'
-import { mp4Decoder } from './decodeVideo.js'
+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 jsonProtoDefsTransactionEvents from 'frameworks/native/libs/gui/proto/transactions.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';
+import protobuf from 'protobufjs';
+import {transform_layers, transform_layers_trace} from './transform_sf.js';
+import {transform_window_service, transform_window_trace} from './transform_wm.js';
+import {transform_transaction_trace, transform_TRANSACTION_EVENTS_TRACE} from './transform_transaction.js';
+import {transform_wl_outputstate, transform_wayland_trace} from './transform_wl.js';
+import {transform_protolog} from './transform_protolog.js';
+import {transform_sysui_trace} from './transform_sys_ui.js';
+import {transform_launcher_trace} from './transform_launcher.js';
+import {fill_transform_data} from './matrix_utils.js';
+import {mp4Decoder} from './decodeVideo.js';
-import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.js'
-import WindowManagerTrace from '@/traces/WindowManager.js'
-import TransactionsTrace from '@/traces/Transactions.js'
-import ScreenRecordingTrace from '@/traces/ScreenRecording.js'
-import WaylandTrace from '@/traces/Wayland.js'
-import ProtoLogTrace from '@/traces/ProtoLog.js'
-import SystemUITrace from '@/traces/SystemUI.js'
-import LauncherTrace from '@/traces/Launcher.js'
+import SurfaceFlingerTrace from '@/traces/SurfaceFlinger.js';
+import WindowManagerTrace from '@/traces/WindowManager.js';
+import TransactionsTrace from '@/traces/Transactions.js';
+import ScreenRecordingTrace from '@/traces/ScreenRecording.js';
+import WaylandTrace from '@/traces/Wayland.js';
+import ProtoLogTrace from '@/traces/ProtoLog.js';
+import SystemUITrace from '@/traces/SystemUI.js';
+import LauncherTrace from '@/traces/Launcher.js';
-import SurfaceFlingerDump from '@/dumps/SurfaceFlinger.js'
-import WindowManagerDump from '@/dumps/WindowManager.js'
-import WaylandDump from '@/dumps/Wayland.js'
+import SurfaceFlingerDump from '@/dumps/SurfaceFlinger.js';
+import WindowManagerDump from '@/dumps/WindowManager.js';
+import WaylandDump from '@/dumps/Wayland.js';
-const WmTraceMessage = lookup_type(jsonProtoDefsWm, "com.android.server.wm.WindowManagerTraceFileProto");
-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 SfTransactionEventsTraceMessage = lookup_type(jsonProtoDefsTransactionEvents, "android.TransactionEventsProto");
-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");
-const SystemUiTraceMessage = lookup_type(jsonProtoDefsSysUi, "com.android.systemui.tracing.SystemUiTraceFileProto");
-const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, "com.android.launcher3.tracing.LauncherTraceFileProto");
+const WmTraceMessage = lookup_type(jsonProtoDefsWm, 'com.android.server.wm.WindowManagerTraceFileProto');
+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 SfTransactionEventsTraceMessage = lookup_type(jsonProtoDefsTransactionEvents, 'android.TransactionEventsProto');
+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');
+const SystemUiTraceMessage = lookup_type(jsonProtoDefsSysUi, 'com.android.systemui.tracing.SystemUiTraceFileProto');
+const LauncherTraceMessage = lookup_type(jsonProtoDefsLauncher, 'com.android.launcher3.tracing.LauncherTraceFileProto');
-const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45] // .LYRTRACE
-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
-const PROTO_LOG_MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47] // .PROTOLOG
-const SYSTEM_UI_MAGIC_NUMBER = [0x09, 0x53, 0x59, 0x53, 0x55, 0x49, 0x54, 0x52, 0x43] // .SYSUITRC
-const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0x43] // .LNCHRTRC
+const LAYER_TRACE_MAGIC_NUMBER = [0x09, 0x4c, 0x59, 0x52, 0x54, 0x52, 0x41, 0x43, 0x45]; // .LYRTRACE
+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
+const PROTO_LOG_MAGIC_NUMBER = [0x09, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47]; // .PROTOLOG
+const SYSTEM_UI_MAGIC_NUMBER = [0x09, 0x53, 0x59, 0x53, 0x55, 0x49, 0x54, 0x52, 0x43]; // .SYSUITRC
+const LAUNCHER_MAGIC_NUMBER = [0x09, 0x4C, 0x4E, 0x43, 0x48, 0x52, 0x54, 0x52, 0x43]; // .LNCHRTRC
const FILE_TYPES = Object.freeze({
- WINDOW_MANAGER_TRACE: "WindowManagerTrace",
- SURFACE_FLINGER_TRACE: "SurfaceFlingerTrace",
- WINDOW_MANAGER_DUMP: "WindowManagerDump",
- SURFACE_FLINGER_DUMP: "SurfaceFlingerDump",
- SCREEN_RECORDING: "ScreenRecording",
- TRANSACTIONS_TRACE: "TransactionsTrace",
- TRANSACTION_EVENTS_TRACE: "TransactionMergesTrace",
- WAYLAND_TRACE: "WaylandTrace",
- WAYLAND_DUMP: "WaylandDump",
- PROTO_LOG: "ProtoLog",
- SYSTEM_UI: "SystemUI",
- LAUNCHER: "Launcher",
+ WINDOW_MANAGER_TRACE: 'WindowManagerTrace',
+ SURFACE_FLINGER_TRACE: 'SurfaceFlingerTrace',
+ WINDOW_MANAGER_DUMP: 'WindowManagerDump',
+ SURFACE_FLINGER_DUMP: 'SurfaceFlingerDump',
+ SCREEN_RECORDING: 'ScreenRecording',
+ TRANSACTIONS_TRACE: 'TransactionsTrace',
+ TRANSACTION_EVENTS_TRACE: 'TransactionMergesTrace',
+ WAYLAND_TRACE: 'WaylandTrace',
+ WAYLAND_DUMP: 'WaylandDump',
+ PROTO_LOG: 'ProtoLog',
+ SYSTEM_UI: 'SystemUI',
+ LAUNCHER: 'Launcher',
});
-const WINDOW_MANAGER_ICON = "view_compact"
-const SURFACE_FLINGER_ICON = "filter_none"
-const SCREEN_RECORDING_ICON = "videocam"
-const TRANSACTION_ICON = "timeline"
-const WAYLAND_ICON = "filter_none"
-const PROTO_LOG_ICON = "notes"
-const SYSTEM_UI_ICON = "filter_none"
-const LAUNCHER_ICON = "filter_none"
+const WINDOW_MANAGER_ICON = 'view_compact';
+const SURFACE_FLINGER_ICON = 'filter_none';
+const SCREEN_RECORDING_ICON = 'videocam';
+const TRANSACTION_ICON = 'timeline';
+const WAYLAND_ICON = 'filter_none';
+const PROTO_LOG_ICON = 'notes';
+const SYSTEM_UI_ICON = 'filter_none';
+const LAUNCHER_ICON = 'filter_none';
const FILE_ICONS = {
[FILE_TYPES.WINDOW_MANAGER_TRACE]: WINDOW_MANAGER_ICON,
@@ -104,48 +106,48 @@
[FILE_TYPES.PROTO_LOG]: PROTO_LOG_ICON,
[FILE_TYPES.SYSTEM_UI]: SYSTEM_UI_ICON,
[FILE_TYPES.LAUNCHER]: LAUNCHER_ICON,
-}
+};
function oneOf(dataType) {
- return { oneOf: true, type: dataType };
+ return {oneOf: true, type: dataType};
}
function manyOf(dataType, fold = null) {
- return { manyOf: true, type: dataType, fold };
+ return {manyOf: true, type: dataType, fold};
}
const TRACE_TYPES = Object.freeze({
- WINDOW_MANAGER: "WindowManagerTrace",
- SURFACE_FLINGER: "SurfaceFlingerTrace",
- SCREEN_RECORDING: "ScreenRecording",
- TRANSACTION: "Transaction",
- WAYLAND: "Wayland",
- PROTO_LOG: "ProtoLog",
- SYSTEM_UI: "SystemUI",
- LAUNCHER: "Launcher"
+ WINDOW_MANAGER: 'WindowManagerTrace',
+ SURFACE_FLINGER: 'SurfaceFlingerTrace',
+ SCREEN_RECORDING: 'ScreenRecording',
+ TRANSACTION: 'Transaction',
+ WAYLAND: 'Wayland',
+ PROTO_LOG: 'ProtoLog',
+ SYSTEM_UI: 'SystemUI',
+ LAUNCHER: 'Launcher',
});
const TRACE_INFO = {
[TRACE_TYPES.WINDOW_MANAGER]: {
- name: "WindowManager",
+ name: 'WindowManager',
icon: WINDOW_MANAGER_ICON,
files: [oneOf(FILE_TYPES.WINDOW_MANAGER_TRACE)],
constructor: WindowManagerTrace,
},
[TRACE_TYPES.SURFACE_FLINGER]: {
- name: "SurfaceFlinger",
+ name: 'SurfaceFlinger',
icon: SURFACE_FLINGER_ICON,
files: [oneOf(FILE_TYPES.SURFACE_FLINGER_TRACE)],
constructor: SurfaceFlingerTrace,
},
[TRACE_TYPES.SCREEN_RECORDING]: {
- name: "Screen recording",
+ name: 'Screen recording',
icon: SCREEN_RECORDING_ICON,
files: [oneOf(FILE_TYPES.SCREEN_RECORDING)],
constructor: ScreenRecordingTrace,
},
[TRACE_TYPES.TRANSACTION]: {
- name: "Transaction",
+ name: 'Transaction',
icon: TRANSACTION_ICON,
files: [
oneOf(FILE_TYPES.TRANSACTIONS_TRACE),
@@ -154,62 +156,62 @@
constructor: TransactionsTrace,
},
[TRACE_TYPES.WAYLAND]: {
- name: "Wayland",
+ name: 'Wayland',
icon: WAYLAND_ICON,
files: [oneOf(FILE_TYPES.WAYLAND_TRACE)],
constructor: WaylandTrace,
},
[TRACE_TYPES.PROTO_LOG]: {
- name: "ProtoLog",
+ name: 'ProtoLog',
icon: PROTO_LOG_ICON,
files: [oneOf(FILE_TYPES.PROTO_LOG)],
constructor: ProtoLogTrace,
},
[TRACE_TYPES.SYSTEM_UI]: {
- name: "SystemUI",
+ name: 'SystemUI',
icon: SYSTEM_UI_ICON,
files: [oneOf(FILE_TYPES.SYSTEM_UI)],
constructor: SystemUITrace,
},
[TRACE_TYPES.LAUNCHER]: {
- name: "Launcher",
+ name: 'Launcher',
icon: LAUNCHER_ICON,
files: [oneOf(FILE_TYPES.LAUNCHER)],
constructor: LauncherTrace,
},
-}
+};
const DUMP_TYPES = Object.freeze({
- WINDOW_MANAGER: "WindowManagerDump",
- SURFACE_FLINGER: "SurfaceFlingerDump",
- WAYLAND: "WaylandDump",
+ WINDOW_MANAGER: 'WindowManagerDump',
+ SURFACE_FLINGER: 'SurfaceFlingerDump',
+ WAYLAND: 'WaylandDump',
});
const DUMP_INFO = {
[DUMP_TYPES.WINDOW_MANAGER]: {
- name: "WindowManager",
+ name: 'WindowManager',
icon: WINDOW_MANAGER_ICON,
files: [oneOf(FILE_TYPES.WINDOW_MANAGER_DUMP)],
constructor: WindowManagerDump,
},
[DUMP_TYPES.SURFACE_FLINGER]: {
- name: "SurfaceFlinger",
+ name: 'SurfaceFlinger',
icon: SURFACE_FLINGER_ICON,
files: [oneOf(FILE_TYPES.SURFACE_FLINGER_DUMP)],
constructor: SurfaceFlingerDump,
},
[DUMP_TYPES.WAYLAND]: {
- name: "Wayland",
+ name: 'Wayland',
icon: WAYLAND_ICON,
files: [oneOf(FILE_TYPES.WAYLAND_DUMP)],
constructor: WaylandDump,
},
-}
+};
// TODO: Rename name to defaultName
const FILE_DECODERS = {
[FILE_TYPES.WINDOW_MANAGER_TRACE]: {
- name: "WindowManager trace",
+ name: 'WindowManager trace',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.WINDOW_MANAGER_TRACE,
@@ -219,123 +221,123 @@
},
},
[FILE_TYPES.SURFACE_FLINGER_TRACE]: {
- name: "SurfaceFlinger trace",
+ name: 'SurfaceFlinger trace',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.SURFACE_FLINGER_TRACE,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: SfTraceMessage,
transform: transform_layers_trace,
timeline: true,
},
},
[FILE_TYPES.WAYLAND_TRACE]: {
- name: "Wayland trace",
+ name: 'Wayland trace',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.WAYLAND_TRACE,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: WaylandTraceMessage,
transform: transform_wayland_trace,
timeline: true,
},
},
[FILE_TYPES.SURFACE_FLINGER_DUMP]: {
- name: "SurfaceFlinger dump",
+ name: 'SurfaceFlinger dump',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.SURFACE_FLINGER_DUMP,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: SfDumpMessage,
- transform: (decoded) => transform_layers(true /*includesCompositionState*/, decoded),
+ transform: (decoded) => transform_layers(true /* includesCompositionState*/, decoded),
timeline: false,
},
},
[FILE_TYPES.WINDOW_MANAGER_DUMP]: {
- name: "WindowManager dump",
+ name: 'WindowManager dump',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.WINDOW_MANAGER_DUMP,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: WmDumpMessage,
transform: transform_window_service,
timeline: false,
},
},
[FILE_TYPES.WAYLAND_DUMP]: {
- name: "Wayland dump",
+ name: 'Wayland dump',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.WAYLAND_DUMP,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: WaylandDumpMessage,
transform: transform_wl_outputstate,
timeline: false,
},
},
[FILE_TYPES.SCREEN_RECORDING]: {
- name: "Screen recording",
+ name: 'Screen recording',
decoder: videoDecoder,
decoderParams: {
type: FILE_TYPES.SCREEN_RECORDING,
- mime: "video/mp4",
+ mime: 'video/mp4',
videoDecoder: mp4Decoder,
},
},
[FILE_TYPES.TRANSACTIONS_TRACE]: {
- name: "Transaction",
+ name: 'Transaction',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.TRANSACTIONS_TRACE,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: SfTransactionTraceMessage,
transform: transform_transaction_trace,
timeline: true,
- }
+ },
},
[FILE_TYPES.TRANSACTION_EVENTS_TRACE]: {
- name: "Transaction merges",
+ name: 'Transaction merges',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.TRANSACTION_EVENTS_TRACE,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: SfTransactionEventsTraceMessage,
transform: transform_TRANSACTION_EVENTS_TRACE,
timeline: true,
- }
+ },
},
[FILE_TYPES.PROTO_LOG]: {
- name: "ProtoLog",
+ name: 'ProtoLog',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.PROTO_LOG,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: ProtoLogMessage,
transform: transform_protolog,
timeline: true,
- }
+ },
},
[FILE_TYPES.SYSTEM_UI]: {
- name: "SystemUI trace",
+ name: 'SystemUI trace',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.SYSTEM_UI,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: SystemUiTraceMessage,
transform: transform_sysui_trace,
timeline: true,
- }
+ },
},
[FILE_TYPES.LAUNCHER]: {
- name: "Launcher trace",
+ name: 'Launcher trace',
decoder: protoDecoder,
decoderParams: {
type: FILE_TYPES.LAUNCHER,
- mime: "application/octet-stream",
+ mime: 'application/octet-stream',
protoType: LauncherTraceMessage,
transform: transform_launcher_trace,
timeline: true,
- }
+ },
},
};
@@ -351,31 +353,33 @@
if (!protoObj || protoObj !== Object(protoObj) || !protoObj.$type) {
return;
}
- for (var fieldName in protoObj.$type.fields) {
- var fieldProperties = protoObj.$type.fields[fieldName];
- var field = protoObj[fieldName];
+ for (const fieldName in protoObj.$type.fields) {
+ if (protoObj.$type.fields.hasOwnProperty(fieldName)) {
+ const fieldProperties = protoObj.$type.fields[fieldName];
+ const field = protoObj[fieldName];
- if (Array.isArray(field)) {
- field.forEach((item, _) => {
- modifyProtoFields(item, displayDefaults);
- })
- continue;
- }
+ if (Array.isArray(field)) {
+ field.forEach((item, _) => {
+ modifyProtoFields(item, displayDefaults);
+ });
+ continue;
+ }
- if (displayDefaults && !(field)) {
- protoObj[fieldName] = fieldProperties.defaultValue;
- }
+ if (displayDefaults && !(field)) {
+ protoObj[fieldName] = fieldProperties.defaultValue;
+ }
- if (fieldProperties.type === 'TransformProto') {
- fill_transform_data(protoObj[fieldName]);
- continue;
- }
+ if (fieldProperties.type === 'TransformProto') {
+ fill_transform_data(protoObj[fieldName]);
+ continue;
+ }
- if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) {
- protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]];
- continue;
+ if (fieldProperties.resolvedType && fieldProperties.resolvedType.valuesById) {
+ protoObj[fieldName] = fieldProperties.resolvedType.valuesById[protoObj[fieldProperties.name]];
+ continue;
+ }
+ modifyProtoFields(protoObj[fieldName], displayDefaults);
}
- modifyProtoFields(protoObj[fieldName], displayDefaults);
}
}
@@ -395,13 +399,13 @@
} else {
data = [transformed];
}
- let blobUrl = URL.createObjectURL(new Blob([buffer], { type: params.mime }));
- return dataFile(fileName, data.map(x => x.timestamp), data, blobUrl, params.type);
+ const blobUrl = URL.createObjectURL(new Blob([buffer], {type: params.mime}));
+ return dataFile(fileName, data.map((x) => x.timestamp), data, blobUrl, params.type);
}
function videoDecoder(buffer, params, fileName, store) {
- let [data, timeline] = params.videoDecoder(buffer);
- let blobUrl = URL.createObjectURL(new Blob([data], { type: params.mime }));
+ const [data, timeline] = params.videoDecoder(buffer);
+ const blobUrl = URL.createObjectURL(new Blob([data], {type: params.mime}));
return dataFile(fileName, timeline, blobUrl, blobUrl, params.type);
}
@@ -418,14 +422,14 @@
destroy() {
URL.revokeObjectURL(this.blobUrl);
},
- }
+ };
}
function arrayEquals(a, b) {
if (a.length !== b.length) {
return false;
}
- for (var i = 0; i < a.length; i++) {
+ for (let i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
@@ -473,7 +477,7 @@
[FILE_TYPES.TRANSACTION_EVENTS_TRACE], // TODO: Add magic number at begging of file for better auto detection
]) {
try {
- const [_, fileData] = decodedFile(filetype, buffer, fileName, store);
+ const [, fileData] = decodedFile(filetype, buffer, fileName, store);
// A generic file will often wrongly be decoded as an empty wayland dump file
if (condition && !condition(fileData)) {
@@ -495,4 +499,4 @@
*/
class UndetectableFileType extends Error { }
-export { detectAndDecode, decodeAndTransformProto, FILE_TYPES, TRACE_INFO, TRACE_TYPES, DUMP_TYPES, DUMP_INFO, FILE_DECODERS, FILE_ICONS, UndetectableFileType };
+export {detectAndDecode, decodeAndTransformProto, FILE_TYPES, TRACE_INFO, TRACE_TYPES, DUMP_TYPES, DUMP_INFO, FILE_DECODERS, FILE_ICONS, UndetectableFileType};
diff --git a/tools/winscope/src/traces/Transactions.js b/tools/winscope/src/traces/Transactions.js
index 67be26e..5d08844 100644
--- a/tools/winscope/src/traces/Transactions.js
+++ b/tools/winscope/src/traces/Transactions.js
@@ -14,23 +14,19 @@
* limitations under the License.
*/
-import { FILE_TYPES, TRACE_TYPES } from "@/decode.js";
+import {FILE_TYPES, TRACE_TYPES} from '@/decode.js';
import TraceBase from './TraceBase.js';
export default class Transactions extends TraceBase {
constructor(files) {
const transactionsFile = files[FILE_TYPES.TRANSACTIONS_TRACE];
- // There should be one file for each process which recorded transaction events
+ // There should be one file for each process which recorded transaction
+ // events
const transactionsEventsFiles = files[FILE_TYPES.TRANSACTION_EVENTS_TRACE];
super(transactionsFile.data, transactionsFile.timeline);
- const transactions = transactionsFile.data
- .filter(e => e.type === "transaction")
- .map(e => e.transactions)
- .flat();
-
this.transactionsFile = transactionsFile;
this.transactionsEventsFiles = transactionsEventsFiles;
@@ -55,12 +51,13 @@
for (const event of eventsFile.data) {
if (event.merge) {
const merge = event.merge;
- const originalId = merge.originalTransaction.identifier.id;
- const mergedId = merge.mergedTransaction.identifier.id;
+ const originalId = merge.originalTransaction.id;
+ const mergedId = merge.mergedTransaction.id;
this.addMerge(originalId, mergedId);
} else if (event.apply) {
- this.addApply(event.apply.identifier.id);
+ console.log(event);
+ this.addApply(event.apply.tx_id);
}
}
}
@@ -98,21 +95,60 @@
const event = events[i];
if (event instanceof Merge) {
- const historyTree = this._generateHistoryTree(event.mergedId, event.mergedAt);
+ 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");
+ throw new Error('Unhandled event type');
}
}
return children;
}
- getMergeTreeOf(transactionId) {
- return this.mergeTrees[transactionId];
+ /**
+ * 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);
}
}
@@ -124,7 +160,7 @@
}
get type() {
- return "merge";
+ return 'merge';
}
}
@@ -134,7 +170,7 @@
}
get type() {
- return "apply";
+ return 'apply';
}
}
@@ -142,7 +178,8 @@
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.
+ // Specifies how long the merge chain of the merged transaction was at the
+ // time is was merged.
this.mergedAt = history[mergedId]?.length ?? 0;
}
}
@@ -151,4 +188,23 @@
constructor(transactionId) {
this.transactionId = transactionId;
}
-}
\ No newline at end of file
+}
+
+/**
+ * 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) {
+ console.log('Expanding', 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)),
+ });
+}