blob: 5babf300c841e2e8d950dc98cfcc54693050165f [file] [log] [blame]
/*
* 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 {assertDefined} from 'common/assert_utils';
import {ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType} from 'common/time';
import {AbstractParser} from 'parsers/abstract_parser';
import root from 'protos/transitions/udc/json';
import {com} from 'protos/transitions/udc/static';
import {TraceFile} from 'trace/trace_file';
import {TraceType} from 'trace/trace_type';
import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
import {ParserTransitionsUtils} from './parser_transitions_utils';
export class ParserTransitionsShell extends AbstractParser<PropertyTreeNode> {
private static readonly WmShellTransitionsTraceProto = root.lookupType(
'com.android.wm.shell.WmShellTransitionTraceProto'
);
private realToElapsedTimeOffsetNs: undefined | bigint;
private handlerMapping: undefined | {[key: number]: string};
protected override shouldAddDefaultsToProto = false;
constructor(trace: TraceFile) {
super(trace);
}
override getTraceType(): TraceType {
return TraceType.SHELL_TRANSITION;
}
override decodeTrace(traceBuffer: Uint8Array): com.android.wm.shell.ITransition[] {
const decodedProto = ParserTransitionsShell.WmShellTransitionsTraceProto.decode(
traceBuffer
) as unknown as com.android.wm.shell.IWmShellTransitionTraceProto;
const timeOffset = BigInt(decodedProto.realToElapsedTimeOffsetNanos?.toString() ?? '0');
this.realToElapsedTimeOffsetNs = timeOffset !== 0n ? timeOffset : undefined;
this.handlerMapping = {};
for (const mapping of decodedProto.handlerMappings ?? []) {
this.handlerMapping[mapping.id] = mapping.name;
}
return decodedProto.transitions ?? [];
}
override processDecodedEntry(
index: number,
timestampType: TimestampType,
entryProto: com.android.wm.shell.ITransition
): PropertyTreeNode {
return this.makePropertiesTree(timestampType, entryProto);
}
override getTimestamp(
type: TimestampType,
entry: com.android.wm.shell.ITransition
): undefined | Timestamp {
// for consistency with all transitions, elapsed nanos are defined as shell dispatch time else 0n
const decodedEntry = this.processDecodedEntry(0, type, entry);
const dispatchTimeLong = decodedEntry
.getChildByName('shellData')
?.getChildByName('dispatchTimeNs')
?.getValue();
const timestampNs = dispatchTimeLong ? BigInt(dispatchTimeLong.toString()) : 0n;
if (type === TimestampType.ELAPSED) {
return new ElapsedTimestamp(timestampNs);
}
if (type === TimestampType.REAL) {
return new RealTimestamp(timestampNs + assertDefined(this.realToElapsedTimeOffsetNs));
}
throw Error('Timestamp type unsupported');
}
protected getMagicNumber(): number[] | undefined {
return [0x09, 0x57, 0x4d, 0x53, 0x54, 0x52, 0x41, 0x43, 0x45]; // .WMSTRACE
}
private validateShellTransitionEntry(entry: com.android.wm.shell.ITransition) {
if (entry.id === 0) {
throw new Error('Proto needs a non-null id');
}
if (
!entry.dispatchTimeNs &&
!entry.mergeRequestTimeNs &&
!entry.mergeTimeNs &&
!entry.abortTimeNs
) {
throw new Error('Requires at least one non-null timestamp');
}
if (this.realToElapsedTimeOffsetNs === undefined) {
throw new Error('missing realToElapsedTimeOffsetNs');
}
if (this.handlerMapping === undefined) {
throw new Error('Missing handler mapping');
}
}
private makePropertiesTree(
timestampType: TimestampType,
entryProto: com.android.wm.shell.ITransition
): PropertyTreeNode {
this.validateShellTransitionEntry(entryProto);
const shellEntryTree = ParserTransitionsUtils.makeShellPropertiesTree({
entry: entryProto,
realToElapsedTimeOffsetNs: this.realToElapsedTimeOffsetNs,
timestampType,
handlerMapping: this.handlerMapping,
});
const wmEntryTree = ParserTransitionsUtils.makeWmPropertiesTree();
return ParserTransitionsUtils.makeTransitionPropertiesTree(shellEntryTree, wmEntryTree);
}
}