• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import {
2  CrossPlatform,
3  ShellTransitionData,
4  Transition,
5  TransitionChange,
6  TransitionType,
7  WmTransitionData,
8} from 'trace/flickerlib/common';
9import {ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType} from 'trace/timestamp';
10import {TraceType} from 'trace/trace_type';
11import {AbstractParser} from './abstract_parser';
12import {WmTransitionsTraceFileProto} from './proto_types';
13
14export class ParserTransitionsWm extends AbstractParser {
15  private realToElapsedTimeOffsetNs: undefined | bigint;
16
17  override getTraceType(): TraceType {
18    return TraceType.WM_TRANSITION;
19  }
20
21  override processDecodedEntry(index: number, timestampType: TimestampType, entryProto: any): any {
22    return this.parseWmTransitionEntry(entryProto);
23  }
24
25  override decodeTrace(buffer: Uint8Array): any[] {
26    const decodedProto = WmTransitionsTraceFileProto.decode(buffer) as any;
27    if (Object.prototype.hasOwnProperty.call(decodedProto, 'realToElapsedTimeOffsetNanos')) {
28      this.realToElapsedTimeOffsetNs = BigInt(decodedProto.realToElapsedTimeOffsetNanos);
29    } else {
30      console.warn('Missing realToElapsedTimeOffsetNanos property on SF trace proto');
31      this.realToElapsedTimeOffsetNs = undefined;
32    }
33    return decodedProto.transitions;
34  }
35
36  override getMagicNumber(): number[] | undefined {
37    return [0x09, 0x54, 0x52, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TRNTRACE
38  }
39
40  override getTimestamp(type: TimestampType, decodedEntry: Transition): undefined | Timestamp {
41    decodedEntry = this.parseWmTransitionEntry(decodedEntry);
42
43    if (type === TimestampType.ELAPSED) {
44      return new ElapsedTimestamp(BigInt(decodedEntry.timestamp.elapsedNanos.toString()));
45    }
46
47    if (type === TimestampType.REAL) {
48      return new RealTimestamp(BigInt(decodedEntry.timestamp.unixNanos.toString()));
49    }
50
51    throw new Error('Timestamp type unsupported');
52  }
53
54  private parseWmTransitionEntry(entry: any): Transition {
55    this.validateWmTransitionEntry(entry);
56    let changes: TransitionChange[] | null;
57    if (entry.targets.length === 0) {
58      changes = null;
59    } else {
60      changes = entry.targets.map(
61        (it: any) =>
62          new TransitionChange(TransitionType.Companion.fromInt(it.mode), it.layerId, it.windowId)
63      );
64    }
65
66    if (this.realToElapsedTimeOffsetNs === undefined) {
67      throw new Error('missing realToElapsedTimeOffsetNs');
68    }
69
70    let createTime = null;
71    if (entry.createTimeNs && BigInt(entry.createTimeNs.toString()) !== 0n) {
72      const unixNs = BigInt(entry.createTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
73      createTime = CrossPlatform.timestamp.fromString(
74        entry.createTimeNs.toString(),
75        null,
76        unixNs.toString()
77      );
78    }
79
80    let sendTime = null;
81    if (entry.sendTimeNs && BigInt(entry.sendTimeNs.toString()) !== 0n) {
82      const unixNs = BigInt(entry.sendTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
83      sendTime = CrossPlatform.timestamp.fromString(
84        entry.sendTimeNs.toString(),
85        null,
86        unixNs.toString()
87      );
88    }
89
90    let abortTime = null;
91    if (entry.abortTimeNs && BigInt(entry.abortTimeNs.toString()) !== 0n) {
92      const unixNs = BigInt(entry.abortTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
93      abortTime = CrossPlatform.timestamp.fromString(
94        entry.abortTimeNs.toString(),
95        null,
96        unixNs.toString()
97      );
98    }
99
100    let finishTime = null;
101    if (entry.finishTimeNs && BigInt(entry.finishTimeNs.toString()) !== 0n) {
102      const unixNs = BigInt(entry.finishTimeNs.toString()) + this.realToElapsedTimeOffsetNs;
103      finishTime = CrossPlatform.timestamp.fromString(
104        entry.finishTimeNs.toString(),
105        null,
106        unixNs.toString()
107      );
108    }
109
110    let startTransactionId = null;
111    if (entry.startTransactionId && BigInt(entry.startTransactionId.toString()) !== 0n) {
112      startTransactionId = BigInt(entry.startTransactionId.toString());
113    }
114
115    let finishTransactionId = null;
116    if (entry.finishTransactionId && BigInt(entry.finishTransactionId.toString()) !== 0n) {
117      finishTransactionId = BigInt(entry.finishTransactionId.toString());
118    }
119
120    let type = null;
121    if (entry.type !== 0) {
122      type = TransitionType.Companion.fromInt(entry.type);
123    }
124
125    return new Transition(
126      entry.id,
127      new WmTransitionData(
128        createTime,
129        sendTime,
130        abortTime,
131        finishTime,
132        startTransactionId?.toString(),
133        finishTransactionId?.toString(),
134        type,
135        changes
136      ),
137      new ShellTransitionData()
138    );
139  }
140
141  private validateWmTransitionEntry(entry: any) {
142    if (entry.id === 0) {
143      throw new Error('Entry need a non null id');
144    }
145    if (!entry.createTimeNs && !entry.sendTimeNs && !entry.abortTimeNs && !entry.finishTimeNs) {
146      throw new Error('Requires at least one non-null timestamp');
147    }
148  }
149}
150