Add WM & Shell side transitions parsers am: 28c77be00f
Original change: https://googleplex-android-review.googlesource.com/c/platform/development/+/23367118 Change-Id: I17c85057921e652810572f12c8c4efef5e62b7b2 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -125,8 +125,13 @@ export const TRACE_INFO: TraceInfoMap = {
|
||||
icon: EVENT_LOG_ICON,
|
||||
color: '#fdd663',
|
||||
},
|
||||
[TraceType.TRANSITION]: {
|
||||
name: 'Transition Trace',
|
||||
[TraceType.WM_TRANSITION]: {
|
||||
name: 'WM Transitions',
|
||||
icon: TRANSITION_ICON,
|
||||
color: '#EC407A',
|
||||
},
|
||||
[TraceType.SHELL_TRANSITION]: {
|
||||
name: 'Shell Transitions',
|
||||
icon: TRANSITION_ICON,
|
||||
color: '#EC407A',
|
||||
},
|
||||
|
||||
@@ -28,7 +28,8 @@ import {ParserScreenRecording} from './parser_screen_recording';
|
||||
import {ParserScreenRecordingLegacy} from './parser_screen_recording_legacy';
|
||||
import {ParserSurfaceFlinger} from './parser_surface_flinger';
|
||||
import {ParserTransactions} from './parser_transactions';
|
||||
import {ParserTransitions} from './parser_transitions';
|
||||
import {ParserTransitionsShell} from './parser_transitions_shell';
|
||||
import {ParserTransitionsWm} from './parser_transitions_wm';
|
||||
import {ParserWindowManager} from './parser_window_manager';
|
||||
import {ParserWindowManagerDump} from './parser_window_manager_dump';
|
||||
|
||||
@@ -46,7 +47,8 @@ export class ParserFactory {
|
||||
ParserWindowManager,
|
||||
ParserWindowManagerDump,
|
||||
ParserEventLog,
|
||||
ParserTransitions,
|
||||
ParserTransitionsWm,
|
||||
ParserTransitionsShell,
|
||||
];
|
||||
|
||||
private parsers = new Map<TraceType, Parser<object>>();
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {
|
||||
CrossPlatform,
|
||||
Transition,
|
||||
TransitionChange,
|
||||
TransitionType,
|
||||
WindowingMode,
|
||||
} from 'trace/flickerlib/common';
|
||||
import {ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType} from 'trace/timestamp';
|
||||
import {TraceFile} from 'trace/trace_file';
|
||||
import {TraceType} from 'trace/trace_type';
|
||||
import {AbstractParser} from './abstract_parser';
|
||||
import {TransitionsTraceFileProto} from './proto_types';
|
||||
|
||||
export class ParserTransitions extends AbstractParser {
|
||||
constructor(trace: TraceFile) {
|
||||
super(trace);
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
override getTraceType(): TraceType {
|
||||
return TraceType.TRANSITION;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] {
|
||||
return ParserTransitions.MAGIC_NUMBER;
|
||||
}
|
||||
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
const decodedProto = TransitionsTraceFileProto.decode(buffer) as any;
|
||||
this.realToElapsedTimeOffsetNs = BigInt(decodedProto.realToElapsedTimeOffsetNanos);
|
||||
|
||||
return decodedProto.transitions;
|
||||
}
|
||||
|
||||
override getTimestamp(type: TimestampType, entryProto: any): undefined | Timestamp {
|
||||
if (type === TimestampType.ELAPSED) {
|
||||
return new ElapsedTimestamp(BigInt(entryProto.createTimeNs));
|
||||
}
|
||||
if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) {
|
||||
return new RealTimestamp(this.realToElapsedTimeOffsetNs + BigInt(entryProto.createTimeNs));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
override processDecodedEntry(
|
||||
index: number,
|
||||
timestampType: TimestampType,
|
||||
entryProto: any
|
||||
): Transition {
|
||||
if (!this.transitions) {
|
||||
const transitions = this.decodedEntries.map((it) => this.parseProto(it));
|
||||
this.transitions = transitions;
|
||||
}
|
||||
return this.transitions[index];
|
||||
}
|
||||
|
||||
private parseProto(entryProto: any): Transition {
|
||||
const changes = entryProto.targets.map((it: any) => {
|
||||
const windowingMode = WindowingMode.WINDOWING_MODE_UNDEFINED; // TODO: Get the windowing mode
|
||||
|
||||
return new TransitionChange(
|
||||
TransitionType.Companion.fromInt(it.mode),
|
||||
it.layerId,
|
||||
it.windowId,
|
||||
windowingMode
|
||||
);
|
||||
});
|
||||
|
||||
const createTime = CrossPlatform.timestamp.fromString(
|
||||
entryProto.createTimeNs.toString(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
const sendTime = CrossPlatform.timestamp.fromString(
|
||||
entryProto.sendTimeNs.toString(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
const finishTime = CrossPlatform.timestamp.fromString(
|
||||
entryProto.finishTimeNs.toString(),
|
||||
null,
|
||||
null
|
||||
);
|
||||
const startTransactionId = entryProto.startTransactionId;
|
||||
const finishTransactionId = entryProto.finishTransactionId;
|
||||
const type = TransitionType.Companion.fromInt(entryProto.type);
|
||||
const played = entryProto.finishTimeNs > 0;
|
||||
const aborted = entryProto.sendTimeNs === 0;
|
||||
|
||||
return new Transition(
|
||||
createTime,
|
||||
sendTime,
|
||||
finishTime,
|
||||
startTransactionId,
|
||||
finishTransactionId,
|
||||
type,
|
||||
changes,
|
||||
played,
|
||||
aborted
|
||||
);
|
||||
}
|
||||
|
||||
private transitions: Transition[] | undefined;
|
||||
private realToElapsedTimeOffsetNs: undefined | bigint;
|
||||
private static readonly MAGIC_NUMBER = [0x09, 0x54, 0x52, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TRNTRACE
|
||||
}
|
||||
159
tools/winscope/src/parsers/parser_transitions_shell.ts
Normal file
159
tools/winscope/src/parsers/parser_transitions_shell.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {
|
||||
CrossPlatform,
|
||||
ShellTransitionData,
|
||||
Transition,
|
||||
WmTransitionData,
|
||||
} from 'trace/flickerlib/common';
|
||||
import {ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType} from 'trace/timestamp';
|
||||
import {TraceType} from 'trace/trace_type';
|
||||
import {AbstractParser} from './abstract_parser';
|
||||
import {ShellTransitionsTraceFileProto} from './proto_types';
|
||||
|
||||
export class ParserTransitionsShell extends AbstractParser {
|
||||
private realToElapsedTimeOffsetNs: undefined | bigint;
|
||||
private handlerMapping: undefined | Map<number, string>;
|
||||
|
||||
override getTraceType(): TraceType {
|
||||
return TraceType.SHELL_TRANSITION;
|
||||
}
|
||||
|
||||
override decodeTrace(traceBuffer: Uint8Array): Transition[] {
|
||||
const decodedProto = ShellTransitionsTraceFileProto.decode(traceBuffer) as any;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(decodedProto, 'realToElapsedTimeOffsetNanos')) {
|
||||
this.realToElapsedTimeOffsetNs = BigInt(decodedProto.realToElapsedTimeOffsetNanos);
|
||||
} else {
|
||||
console.warn('Missing realToElapsedTimeOffsetNanos property on SF trace proto');
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
|
||||
this.handlerMapping = new Map<number, string>();
|
||||
for (const mapping of decodedProto.handlerMappings) {
|
||||
this.handlerMapping.set(mapping.id, mapping.name);
|
||||
}
|
||||
|
||||
return decodedProto.transitions;
|
||||
}
|
||||
|
||||
override processDecodedEntry(index: number, timestampType: TimestampType, entryProto: any): any {
|
||||
return this.parseShellTransitionEntry(entryProto);
|
||||
}
|
||||
|
||||
private parseShellTransitionEntry(entry: any): Transition {
|
||||
this.validateShellTransitionEntry(entry);
|
||||
|
||||
if (this.realToElapsedTimeOffsetNs === undefined) {
|
||||
throw new Error('missing realToElapsedTimeOffsetNs');
|
||||
}
|
||||
|
||||
let dispatchTime = null;
|
||||
if (entry.dispatchTimeNs && BigInt(entry.dispatchTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.dispatchTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
dispatchTime = CrossPlatform.timestamp.fromString(
|
||||
entry.dispatchTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let mergeRequestTime = null;
|
||||
if (entry.mergeRequestTimeNs && BigInt(entry.mergeRequestTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.mergeRequestTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
mergeRequestTime = CrossPlatform.timestamp.fromString(
|
||||
entry.mergeRequestTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let mergeTime = null;
|
||||
if (entry.mergeTimeNs && BigInt(entry.mergeTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.mergeTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
mergeTime = CrossPlatform.timestamp.fromString(
|
||||
entry.mergeTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let abortTime = null;
|
||||
if (entry.abortTimeNs && BigInt(entry.abortTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.abortTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
abortTime = CrossPlatform.timestamp.fromString(
|
||||
entry.abortTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let mergedInto = null;
|
||||
if (entry.mergedInto !== 0) {
|
||||
mergedInto = entry.mergedInto;
|
||||
}
|
||||
|
||||
if (this.handlerMapping === undefined) {
|
||||
throw new Error('Missing handler mapping!');
|
||||
}
|
||||
|
||||
return new Transition(
|
||||
entry.id,
|
||||
new WmTransitionData(),
|
||||
new ShellTransitionData(
|
||||
dispatchTime,
|
||||
mergeRequestTime,
|
||||
mergeTime,
|
||||
abortTime,
|
||||
this.handlerMapping.get(entry.handler),
|
||||
mergedInto
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private validateShellTransitionEntry(entry: any) {
|
||||
if (entry.id === 0) {
|
||||
throw new Error('Entry need a non null id');
|
||||
}
|
||||
if (
|
||||
!entry.dispatchTimeNs &&
|
||||
!entry.mergeRequestTimeNs &&
|
||||
!entry.mergeTimeNs &&
|
||||
!entry.abortTimeNs
|
||||
) {
|
||||
throw new Error('Requires at least one non-null timestamp');
|
||||
}
|
||||
}
|
||||
|
||||
protected getMagicNumber(): number[] | undefined {
|
||||
return [0x09, 0x57, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WMSTRACE
|
||||
}
|
||||
|
||||
override getTimestamp(type: TimestampType, decodedEntry: Transition): undefined | Timestamp {
|
||||
decodedEntry = this.parseShellTransitionEntry(decodedEntry);
|
||||
|
||||
if (type === TimestampType.ELAPSED) {
|
||||
return new ElapsedTimestamp(BigInt(decodedEntry.timestamp.elapsedNanos.toString()));
|
||||
}
|
||||
|
||||
if (type === TimestampType.REAL) {
|
||||
return new RealTimestamp(BigInt(decodedEntry.timestamp.unixNanos.toString()));
|
||||
}
|
||||
|
||||
throw new Error('Timestamp type unsupported');
|
||||
}
|
||||
}
|
||||
61
tools/winscope/src/parsers/parser_transitions_shell_test.ts
Normal file
61
tools/winscope/src/parsers/parser_transitions_shell_test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {UnitTestUtils} from 'test/unit/utils';
|
||||
import {Parser} from 'trace/parser';
|
||||
import {ElapsedTimestamp, RealTimestamp, TimestampType} from 'trace/timestamp';
|
||||
import {TraceType} from 'trace/trace_type';
|
||||
|
||||
describe('ShellFileParserTransitions', () => {
|
||||
let parser: Parser<object>;
|
||||
|
||||
beforeAll(async () => {
|
||||
parser = await UnitTestUtils.getParser(
|
||||
'traces/elapsed_and_real_timestamp/shell_transition_trace.pb'
|
||||
);
|
||||
});
|
||||
|
||||
it('has expected trace type', () => {
|
||||
expect(parser.getTraceType()).toEqual(TraceType.SHELL_TRANSITION);
|
||||
});
|
||||
|
||||
it('provides elapsed timestamps', () => {
|
||||
const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!;
|
||||
|
||||
expect(timestamps.length).toEqual(6);
|
||||
|
||||
const expected = [
|
||||
new ElapsedTimestamp(57649649922341n),
|
||||
new ElapsedTimestamp(57649829445249n),
|
||||
new ElapsedTimestamp(57649829526223n),
|
||||
];
|
||||
expect(timestamps.slice(0, 3)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('provides real timestamps', () => {
|
||||
const expected = [
|
||||
new RealTimestamp(1683188477607285317n),
|
||||
new RealTimestamp(1683188477786808225n),
|
||||
new RealTimestamp(1683188477786889199n),
|
||||
];
|
||||
|
||||
const timestamps = parser.getTimestamps(TimestampType.REAL)!;
|
||||
|
||||
expect(timestamps.length).toEqual(6);
|
||||
|
||||
expect(timestamps.slice(0, 3)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {UnitTestUtils} from 'test/unit/utils';
|
||||
import {Parser} from 'trace/parser';
|
||||
import {ElapsedTimestamp, TimestampType} from 'trace/timestamp';
|
||||
import {TraceType} from 'trace/trace_type';
|
||||
|
||||
describe('ParserTransitions', () => {
|
||||
describe('trace with elapsed (only) timestamp', () => {
|
||||
let parser: Parser<object>;
|
||||
|
||||
beforeAll(async () => {
|
||||
parser = await UnitTestUtils.getParser('traces/elapsed_timestamp/Transitions.pb');
|
||||
});
|
||||
|
||||
it('has expected trace type', () => {
|
||||
expect(parser.getTraceType()).toEqual(TraceType.TRANSITION);
|
||||
});
|
||||
|
||||
it('provides elapsed timestamps', () => {
|
||||
const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!;
|
||||
|
||||
expect(timestamps.length).toEqual(7);
|
||||
|
||||
const expected = [
|
||||
new ElapsedTimestamp(1862299518404n),
|
||||
new ElapsedTimestamp(1863412780164n),
|
||||
new ElapsedTimestamp(1865439877129n),
|
||||
];
|
||||
expect(timestamps.slice(0, 3)).toEqual(expected);
|
||||
});
|
||||
|
||||
it("doesn't provide real timestamps", () => {
|
||||
expect(parser.getTimestamps(TimestampType.REAL)).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
149
tools/winscope/src/parsers/parser_transitions_wm.ts
Normal file
149
tools/winscope/src/parsers/parser_transitions_wm.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import {
|
||||
CrossPlatform,
|
||||
ShellTransitionData,
|
||||
Transition,
|
||||
TransitionChange,
|
||||
TransitionType,
|
||||
WmTransitionData,
|
||||
} from 'trace/flickerlib/common';
|
||||
import {ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType} from 'trace/timestamp';
|
||||
import {TraceType} from 'trace/trace_type';
|
||||
import {AbstractParser} from './abstract_parser';
|
||||
import {WmTransitionsTraceFileProto} from './proto_types';
|
||||
|
||||
export class ParserTransitionsWm extends AbstractParser {
|
||||
private realToElapsedTimeOffsetNs: undefined | bigint;
|
||||
|
||||
override getTraceType(): TraceType {
|
||||
return TraceType.WM_TRANSITION;
|
||||
}
|
||||
|
||||
override processDecodedEntry(index: number, timestampType: TimestampType, entryProto: any): any {
|
||||
return this.parseWmTransitionEntry(entryProto);
|
||||
}
|
||||
|
||||
override decodeTrace(buffer: Uint8Array): any[] {
|
||||
const decodedProto = WmTransitionsTraceFileProto.decode(buffer) as any;
|
||||
if (Object.prototype.hasOwnProperty.call(decodedProto, 'realToElapsedTimeOffsetNanos')) {
|
||||
this.realToElapsedTimeOffsetNs = BigInt(decodedProto.realToElapsedTimeOffsetNanos);
|
||||
} else {
|
||||
console.warn('Missing realToElapsedTimeOffsetNanos property on SF trace proto');
|
||||
this.realToElapsedTimeOffsetNs = undefined;
|
||||
}
|
||||
return decodedProto.transitions;
|
||||
}
|
||||
|
||||
override getMagicNumber(): number[] | undefined {
|
||||
return [0x09, 0x54, 0x52, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TRNTRACE
|
||||
}
|
||||
|
||||
override getTimestamp(type: TimestampType, decodedEntry: Transition): undefined | Timestamp {
|
||||
decodedEntry = this.parseWmTransitionEntry(decodedEntry);
|
||||
|
||||
if (type === TimestampType.ELAPSED) {
|
||||
return new ElapsedTimestamp(BigInt(decodedEntry.timestamp.elapsedNanos.toString()));
|
||||
}
|
||||
|
||||
if (type === TimestampType.REAL) {
|
||||
return new RealTimestamp(BigInt(decodedEntry.timestamp.unixNanos.toString()));
|
||||
}
|
||||
|
||||
throw new Error('Timestamp type unsupported');
|
||||
}
|
||||
|
||||
private parseWmTransitionEntry(entry: any): Transition {
|
||||
this.validateWmTransitionEntry(entry);
|
||||
let changes: TransitionChange[] | null;
|
||||
if (entry.targets.length === 0) {
|
||||
changes = null;
|
||||
} else {
|
||||
changes = entry.targets.map(
|
||||
(it: any) =>
|
||||
new TransitionChange(TransitionType.Companion.fromInt(it.mode), it.layerId, it.windowId)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.realToElapsedTimeOffsetNs === undefined) {
|
||||
throw new Error('missing realToElapsedTimeOffsetNs');
|
||||
}
|
||||
|
||||
let createTime = null;
|
||||
if (entry.createTimeNs && BigInt(entry.createTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.createTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
createTime = CrossPlatform.timestamp.fromString(
|
||||
entry.createTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let sendTime = null;
|
||||
if (entry.sendTimeNs && BigInt(entry.sendTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.sendTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
sendTime = CrossPlatform.timestamp.fromString(
|
||||
entry.sendTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let abortTime = null;
|
||||
if (entry.abortTimeNs && BigInt(entry.abortTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.abortTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
abortTime = CrossPlatform.timestamp.fromString(
|
||||
entry.abortTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let finishTime = null;
|
||||
if (entry.finishTimeNs && BigInt(entry.finishTimeNs.toString()) !== 0n) {
|
||||
const unixNs = BigInt(entry.finishTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
|
||||
finishTime = CrossPlatform.timestamp.fromString(
|
||||
entry.finishTimeNs.toString(),
|
||||
null,
|
||||
unixNs.toString()
|
||||
);
|
||||
}
|
||||
|
||||
let startTransactionId = null;
|
||||
if (entry.startTransactionId !== 0) {
|
||||
startTransactionId = entry.startTransactionId;
|
||||
}
|
||||
|
||||
let finishTransactionId = null;
|
||||
if (entry.finishTransactionId !== 0) {
|
||||
finishTransactionId = entry.finishTransactionId;
|
||||
}
|
||||
|
||||
let type = null;
|
||||
if (entry.type !== 0) {
|
||||
type = TransitionType.Companion.fromInt(entry.type);
|
||||
}
|
||||
|
||||
return new Transition(
|
||||
entry.id,
|
||||
new WmTransitionData(
|
||||
createTime,
|
||||
sendTime,
|
||||
abortTime,
|
||||
finishTime,
|
||||
startTransactionId,
|
||||
finishTransactionId,
|
||||
type,
|
||||
changes
|
||||
),
|
||||
new ShellTransitionData()
|
||||
);
|
||||
}
|
||||
|
||||
private validateWmTransitionEntry(entry: any) {
|
||||
if (entry.id === 0) {
|
||||
throw new Error('Entry need a non null id');
|
||||
}
|
||||
if (!entry.createTimeNs && !entry.sendTimeNs && !entry.abortTimeNs && !entry.finishTimeNs) {
|
||||
throw new Error('Requires at least one non-null timestamp');
|
||||
}
|
||||
}
|
||||
}
|
||||
61
tools/winscope/src/parsers/parser_transitions_wm_test.ts
Normal file
61
tools/winscope/src/parsers/parser_transitions_wm_test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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 {UnitTestUtils} from 'test/unit/utils';
|
||||
import {Parser} from 'trace/parser';
|
||||
import {ElapsedTimestamp, RealTimestamp, TimestampType} from 'trace/timestamp';
|
||||
import {TraceType} from 'trace/trace_type';
|
||||
|
||||
describe('WmFileParserTransitions', () => {
|
||||
let parser: Parser<object>;
|
||||
|
||||
beforeAll(async () => {
|
||||
parser = await UnitTestUtils.getParser(
|
||||
'traces/elapsed_and_real_timestamp/wm_transition_trace.pb'
|
||||
);
|
||||
});
|
||||
|
||||
it('has expected trace type', () => {
|
||||
expect(parser.getTraceType()).toEqual(TraceType.WM_TRANSITION);
|
||||
});
|
||||
|
||||
it('provides elapsed timestamps', () => {
|
||||
const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!;
|
||||
|
||||
expect(timestamps.length).toEqual(8);
|
||||
|
||||
const expected = [
|
||||
new ElapsedTimestamp(57649586217344n),
|
||||
new ElapsedTimestamp(57649691956439n),
|
||||
new ElapsedTimestamp(57650183020323n),
|
||||
];
|
||||
expect(timestamps.slice(0, 3)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('provides real timestamps', () => {
|
||||
const expected = [
|
||||
new RealTimestamp(1683188477542869667n),
|
||||
new RealTimestamp(1683188477648608762n),
|
||||
new RealTimestamp(1683188478139672646n),
|
||||
];
|
||||
|
||||
const timestamps = parser.getTimestamps(TimestampType.REAL)!;
|
||||
|
||||
expect(timestamps.length).toEqual(8);
|
||||
|
||||
expect(timestamps.slice(0, 3)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
@@ -22,8 +22,9 @@ protobuf.configure();
|
||||
import protoLogJson from 'frameworks/base/core/proto/android/internal/protolog.proto';
|
||||
import accessibilityJson from 'frameworks/base/core/proto/android/server/accessibilitytrace.proto';
|
||||
import windowManagerJson from 'frameworks/base/core/proto/android/server/windowmanagertrace.proto';
|
||||
import transitionsJson from 'frameworks/base/core/proto/android/server/windowmanagertransitiontrace.proto';
|
||||
import wmTransitionsJson from 'frameworks/base/core/proto/android/server/windowmanagertransitiontrace.proto';
|
||||
import inputMethodClientsJson from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto';
|
||||
import shellTransitionsJson from 'frameworks/base/libs/WindowManager/Shell/proto/wm_shell_transition_trace.proto';
|
||||
import layersJson from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto';
|
||||
import transactionsJson from 'frameworks/native/services/surfaceflinger/layerproto/transactions.proto';
|
||||
|
||||
@@ -54,9 +55,12 @@ const WindowManagerServiceDumpProto = protobuf.Root.fromJSON(windowManagerJson).
|
||||
const WindowManagerTraceFileProto = protobuf.Root.fromJSON(windowManagerJson).lookupType(
|
||||
'com.android.server.wm.WindowManagerTraceFileProto'
|
||||
);
|
||||
const TransitionsTraceFileProto = protobuf.Root.fromJSON(transitionsJson).lookupType(
|
||||
const WmTransitionsTraceFileProto = protobuf.Root.fromJSON(wmTransitionsJson).lookupType(
|
||||
'com.android.server.wm.shell.TransitionTraceProto'
|
||||
);
|
||||
const ShellTransitionsTraceFileProto = protobuf.Root.fromJSON(shellTransitionsJson).lookupType(
|
||||
'com.android.wm.shell.WmShellTransitionTraceProto'
|
||||
);
|
||||
|
||||
export {
|
||||
AccessibilityTraceFileProto,
|
||||
@@ -68,5 +72,6 @@ export {
|
||||
TransactionsTraceFileProto,
|
||||
WindowManagerServiceDumpProto,
|
||||
WindowManagerTraceFileProto,
|
||||
TransitionsTraceFileProto,
|
||||
WmTransitionsTraceFileProto,
|
||||
ShellTransitionsTraceFileProto,
|
||||
};
|
||||
|
||||
2
tools/winscope/src/test/fixtures/traces/elapsed_and_real_timestamp/shell_transition_trace.pb
vendored
Normal file
2
tools/winscope/src/test/fixtures/traces/elapsed_and_real_timestamp/shell_transition_trace.pb
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
WMSTRACE<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
7
tools/winscope/src/test/fixtures/traces/elapsed_and_real_timestamp/wm_transition_trace.pb
vendored
Normal file
7
tools/winscope/src/test/fixtures/traces/elapsed_and_real_timestamp/wm_transition_trace.pb
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
TRNTRACE#<23><><06><>[? <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8B
|
||||
<10>֒<>XB q<18><><EFBFBD>UF ש<><D7A9><EFBFBD><EFBFBD>
|
||||
(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>8B <20><><10>ۉ<>/B <20><><10><18><><EFBFBD>
|
||||
0<><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
@@ -67,6 +67,9 @@ const EventLogParser = require('flicker').android.tools.common.parsers.events.Ev
|
||||
const Transition = require('flicker').android.tools.common.traces.wm.Transition;
|
||||
const TransitionType = require('flicker').android.tools.common.traces.wm.TransitionType;
|
||||
const TransitionChange = require('flicker').android.tools.common.traces.wm.TransitionChange;
|
||||
const TransitionsTrace = require('flicker').android.tools.common.traces.wm.TransitionsTrace;
|
||||
const ShellTransitionData = require('flicker').android.tools.common.traces.wm.ShellTransitionData;
|
||||
const WmTransitionData = require('flicker').android.tools.common.traces.wm.WmTransitionData;
|
||||
|
||||
// Common
|
||||
const Size = require('flicker').android.tools.common.datatypes.Size;
|
||||
@@ -314,6 +317,9 @@ export {
|
||||
Transition,
|
||||
TransitionType,
|
||||
TransitionChange,
|
||||
TransitionsTrace,
|
||||
ShellTransitionData,
|
||||
WmTransitionData,
|
||||
// Common
|
||||
Size,
|
||||
ActiveBuffer,
|
||||
|
||||
@@ -36,7 +36,8 @@ export enum TraceType {
|
||||
INPUT_METHOD_MANAGER_SERVICE,
|
||||
INPUT_METHOD_SERVICE,
|
||||
EVENT_LOG,
|
||||
TRANSITION,
|
||||
WM_TRANSITION,
|
||||
SHELL_TRANSITION,
|
||||
TAG,
|
||||
ERROR,
|
||||
TEST_TRACE_STRING,
|
||||
@@ -59,7 +60,8 @@ export interface TraceEntryTypeMap {
|
||||
[TraceType.INPUT_METHOD_MANAGER_SERVICE]: object;
|
||||
[TraceType.INPUT_METHOD_SERVICE]: object;
|
||||
[TraceType.EVENT_LOG]: Event;
|
||||
[TraceType.TRANSITION]: Transition;
|
||||
[TraceType.WM_TRANSITION]: object;
|
||||
[TraceType.SHELL_TRANSITION]: object;
|
||||
[TraceType.TAG]: object;
|
||||
[TraceType.ERROR]: object;
|
||||
[TraceType.TEST_TRACE_STRING]: string;
|
||||
|
||||
Reference in New Issue
Block a user