Implement Transition trace parser in Winscope
Bug: 265791162 Test: npm run build:all && npm run test:all Change-Id: Ib37d722079ed75f7c1b75cba506757b6c41f41aa
This commit is contained in:
@@ -28,6 +28,7 @@ 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 {ParserWindowManager} from './parser_window_manager';
|
||||
import {ParserWindowManagerDump} from './parser_window_manager_dump';
|
||||
|
||||
@@ -45,6 +46,7 @@ export class ParserFactory {
|
||||
ParserWindowManager,
|
||||
ParserWindowManagerDump,
|
||||
ParserEventLog,
|
||||
ParserTransitions,
|
||||
];
|
||||
|
||||
private parsers = new Map<TraceType, Parser<object>>();
|
||||
|
||||
122
tools/winscope/src/parsers/parser_transitions.ts
Normal file
122
tools/winscope/src/parsers/parser_transitions.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
50
tools/winscope/src/parsers/parser_transitions_test.ts
Normal file
50
tools/winscope/src/parsers/parser_transitions_test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -22,6 +22,7 @@ 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 inputMethodClientsJson from 'frameworks/base/core/proto/android/view/inputmethod/inputmethodeditortrace.proto';
|
||||
import layersJson from 'frameworks/native/services/surfaceflinger/layerproto/layerstrace.proto';
|
||||
import transactionsJson from 'frameworks/native/services/surfaceflinger/layerproto/transactions.proto';
|
||||
@@ -53,6 +54,9 @@ 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(
|
||||
'com.android.server.wm.shell.TransitionTraceProto'
|
||||
);
|
||||
|
||||
export {
|
||||
AccessibilityTraceFileProto,
|
||||
@@ -64,4 +68,5 @@ export {
|
||||
TransactionsTraceFileProto,
|
||||
WindowManagerServiceDumpProto,
|
||||
WindowManagerTraceFileProto,
|
||||
TransitionsTraceFileProto,
|
||||
};
|
||||
|
||||
9
tools/winscope/src/test/fixtures/traces/elapsed_timestamp/Transitions.pb
vendored
Normal file
9
tools/winscope/src/test/fixtures/traces/elapsed_timestamp/Transitions.pb
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
TRNTRACE@<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)8B
|
||||
<10><18><><EFBFBD>B .<18><><EFBFBD> ċ<>͙6(<28>Ԏٙ60<36><30><EFBFBD>ۛ6@<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*8B .<18><><EFBFBD>B
|
||||
<10><18><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>6(<28><><EFBFBD><EFBFBD><EFBFBD>60<36><30><EFBFBD><EFBFBD><EFBFBD>6@<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+8B
|
||||
<10>ת<>-B .<18><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>6(<28><><EFBFBD><EFBFBD><EFBFBD>60<36><30><EFBFBD><EFBFBD><EFBFBD>6@<><EEB480><EFBFBD>ﴀ<><EFB480><EFBFBD>,8B .<18><><EFBFBD>B
|
||||
<10>ת<>- <20><><EFBFBD>Ы6(<28><><EFBFBD><EFBFBD><EFBFBD>60<36><30><EFBFBD><EFBFBD><EFBFBD>6@<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-8B
|
||||
<10><18><><EFBFBD>vB .<18><><EFBFBD> ɴ<>ʴ6(<28><><EFBFBD>״60<36><30><EFBFBD>Ҷ6A<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.8B
|
||||
<10><18><><EFBFBD>oB
|
||||
<10><18><><EFBFBD>r ѸȈ<D1B8>6(<><EF9394>60<36><30><EFBFBD><EFBFBD><EFBFBD>6@<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><18><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/8B .<18><><EFBFBD>B
|
||||
<10><18><><EFBFBD>v <20><><EFBFBD><EFBFBD><EFBFBD>6(<28><><EFBFBD><EFBFBD><EFBFBD>60<36>꼪<EFBFBD>6
|
||||
@@ -63,6 +63,11 @@ const FlickerEvent = require('flicker').android.tools.common.traces.events.Flick
|
||||
const FocusEvent = require('flicker').android.tools.common.traces.events.FocusEvent;
|
||||
const EventLogParser = require('flicker').android.tools.common.parsers.events.EventLogParser;
|
||||
|
||||
// Transitions
|
||||
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;
|
||||
|
||||
// Common
|
||||
const Size = require('flicker').android.tools.common.datatypes.Size;
|
||||
const ActiveBuffer = require('flicker').android.tools.common.datatypes.ActiveBuffer;
|
||||
@@ -77,6 +82,9 @@ const Point = require('flicker').android.tools.common.datatypes.Point;
|
||||
const PointF = require('flicker').android.tools.common.datatypes.PointF;
|
||||
const Rect = require('flicker').android.tools.common.datatypes.Rect;
|
||||
const RectF = require('flicker').android.tools.common.datatypes.RectF;
|
||||
const WindowingMode = require('flicker').android.tools.common.traces.wm.WindowingMode;
|
||||
const CrossPlatform = require('flicker').android.tools.common.CrossPlatform;
|
||||
const TimestampFactory = require('flicker').android.tools.common.TimestampFactory;
|
||||
|
||||
const EMPTY_SIZE = Size.Companion.EMPTY;
|
||||
const EMPTY_BUFFER = ActiveBuffer.Companion.EMPTY;
|
||||
@@ -302,6 +310,10 @@ export {
|
||||
FlickerEvent,
|
||||
FocusEvent,
|
||||
EventLogParser,
|
||||
// Transitions
|
||||
Transition,
|
||||
TransitionType,
|
||||
TransitionChange,
|
||||
// Common
|
||||
Size,
|
||||
ActiveBuffer,
|
||||
@@ -314,6 +326,9 @@ export {
|
||||
RectF,
|
||||
Region,
|
||||
Rotation,
|
||||
WindowingMode,
|
||||
CrossPlatform,
|
||||
TimestampFactory,
|
||||
// Service
|
||||
toSize,
|
||||
toActiveBuffer,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {Event} from 'trace/flickerlib/common';
|
||||
import {Transition} from './flickerlib/common';
|
||||
import {LayerTraceEntry} from './flickerlib/layers/LayerTraceEntry';
|
||||
import {WindowManagerState} from './flickerlib/windows/WindowManagerState';
|
||||
import {LogMessage} from './protolog';
|
||||
@@ -35,6 +36,7 @@ export enum TraceType {
|
||||
INPUT_METHOD_MANAGER_SERVICE,
|
||||
INPUT_METHOD_SERVICE,
|
||||
EVENT_LOG,
|
||||
TRANSITION,
|
||||
TAG,
|
||||
ERROR,
|
||||
TEST_TRACE_STRING,
|
||||
@@ -57,6 +59,7 @@ export interface TraceEntryTypeMap {
|
||||
[TraceType.INPUT_METHOD_MANAGER_SERVICE]: object;
|
||||
[TraceType.INPUT_METHOD_SERVICE]: object;
|
||||
[TraceType.EVENT_LOG]: Event;
|
||||
[TraceType.TRANSITION]: Transition;
|
||||
[TraceType.TAG]: object;
|
||||
[TraceType.ERROR]: object;
|
||||
[TraceType.TEST_TRACE_STRING]: string;
|
||||
|
||||
Reference in New Issue
Block a user