1/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {INVALID_TIME_NS, Timestamp} from 'common/time';
18import {AbstractParser} from 'parsers/legacy/abstract_parser';
19import {ParserTransitionsUtils} from 'parsers/transitions/parser_transitions_utils';
20import root from 'protos/transitions/udc/json';
21import {com} from 'protos/transitions/udc/static';
22import {TraceType} from 'trace/trace_type';
23import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
24
25export class ParserTransitionsWm extends AbstractParser<PropertyTreeNode> {
26  private static readonly TransitionTraceProto = root.lookupType(
27    'com.android.server.wm.shell.TransitionTraceProto',
28  );
29
30  private realToBootTimeOffsetNs: bigint | undefined;
31
32  override getTraceType(): TraceType {
33    return TraceType.WM_TRANSITION;
34  }
35
36  override getRealToBootTimeOffsetNs(): bigint | undefined {
37    return this.realToBootTimeOffsetNs;
38  }
39
40  override getRealToMonotonicTimeOffsetNs(): bigint | undefined {
41    return undefined;
42  }
43
44  override processDecodedEntry(
45    index: number,
46    entryProto: com.android.server.wm.shell.ITransition,
47  ): PropertyTreeNode {
48    return this.makePropertiesTree(entryProto);
49  }
50
51  override decodeTrace(
52    buffer: Uint8Array,
53  ): com.android.server.wm.shell.ITransition[] {
54    const decodedProto = ParserTransitionsWm.TransitionTraceProto.decode(
55      buffer,
56    ) as unknown as com.android.server.wm.shell.ITransitionTraceProto;
57
58    const timeOffset = BigInt(
59      decodedProto.realToElapsedTimeOffsetNanos?.toString() ?? '0',
60    );
61    this.realToBootTimeOffsetNs = timeOffset !== 0n ? timeOffset : undefined;
62
63    return decodedProto.transitions ?? [];
64  }
65
66  override getMagicNumber(): number[] | undefined {
67    return [0x09, 0x54, 0x52, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TRNTRACE
68  }
69
70  protected override getTimestamp(
71    entry: com.android.server.wm.shell.ITransition,
72  ): Timestamp {
73    // for consistency with all transitions, elapsed nanos are defined as shell dispatch time else INVALID_TIME_NS
74    return this.timestampConverter.makeTimestampFromBootTimeNs(INVALID_TIME_NS);
75  }
76
77  private validateWmTransitionEntry(
78    entry: com.android.server.wm.shell.ITransition,
79  ) {
80    if (entry.id === 0) {
81      throw new Error('Entry need a non null id');
82    }
83    if (
84      !entry.createTimeNs &&
85      !entry.sendTimeNs &&
86      !entry.abortTimeNs &&
87      !entry.finishTimeNs
88    ) {
89      throw new Error('Requires at least one non-null timestamp');
90    }
91    if (this.realToBootTimeOffsetNs === undefined) {
92      throw new Error('missing realToBootTimeOffsetNs');
93    }
94  }
95
96  private makePropertiesTree(
97    entryProto: com.android.server.wm.shell.ITransition,
98  ): PropertyTreeNode {
99    this.validateWmTransitionEntry(entryProto);
100
101    const shellEntryTree = ParserTransitionsUtils.makeShellPropertiesTree();
102    const wmEntryTree = ParserTransitionsUtils.makeWmPropertiesTree({
103      entry: entryProto,
104      realToBootTimeOffsetNs: this.realToBootTimeOffsetNs,
105      timestampConverter: this.timestampConverter,
106    });
107
108    return ParserTransitionsUtils.makeTransitionPropertiesTree(
109      shellEntryTree,
110      wmEntryTree,
111    );
112  }
113}
114