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:
Pablo Gamito
2023-04-05 14:05:09 +00:00
parent d27b1735e6
commit 4cb72593d0
7 changed files with 206 additions and 0 deletions

View File

@@ -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>>();

View 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
}

View 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);
});
});
});

View File

@@ -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,
};

View 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

View File

@@ -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,

View File

@@ -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;