• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {TimestampConverterUtils} from 'common/time/test_utils';
18import {TracesUtils} from 'test/unit/traces_utils';
19import {TraceBuilder} from 'test/unit/trace_builder';
20import {CustomQueryType} from './custom_query';
21import {FrameMapper} from './frame_mapper';
22import {AbsoluteFrameIndex} from './index_types';
23import {MediaBasedTraceEntry} from './media_based_trace_entry';
24import {Trace} from './trace';
25import {Traces} from './traces';
26import {TraceType} from './trace_type';
27import {HierarchyTreeNode} from './tree_node/hierarchy_tree_node';
28import {PropertyTreeNode} from './tree_node/property_tree_node';
29
30describe('FrameMapper', () => {
31  const time0 = TimestampConverterUtils.makeRealTimestamp(0n);
32  const time1 = TimestampConverterUtils.makeRealTimestamp(1n);
33  const time2 = TimestampConverterUtils.makeRealTimestamp(2n);
34  const time3 = TimestampConverterUtils.makeRealTimestamp(3n);
35  const time4 = TimestampConverterUtils.makeRealTimestamp(4n);
36  const time5 = TimestampConverterUtils.makeRealTimestamp(5n);
37  const time6 = TimestampConverterUtils.makeRealTimestamp(6n);
38  const time7 = TimestampConverterUtils.makeRealTimestamp(7n);
39  const time8 = TimestampConverterUtils.makeRealTimestamp(8n);
40  const time10seconds = TimestampConverterUtils.makeRealTimestamp(
41    10n * 1000000000n,
42  );
43
44  describe('ProtoLog <-> WindowManager', () => {
45    let protoLog: Trace<PropertyTreeNode>;
46    let windowManager: Trace<HierarchyTreeNode>;
47    let traces: Traces;
48
49    beforeAll(async () => {
50      // Frames              F0        F1
51      //                 |<------>|  |<->|
52      // PROTO_LOG:      0  1  2     3  4  5
53      // WINDOW_MANAGER:          0     1
54      // Time:           0  1  2  3  4  5  6
55      protoLog = new TraceBuilder<PropertyTreeNode>()
56        .setType(TraceType.PROTO_LOG)
57        .setEntries([
58          'entry-0' as unknown as PropertyTreeNode,
59          'entry-1' as unknown as PropertyTreeNode,
60          'entry-2' as unknown as PropertyTreeNode,
61          'entry-3' as unknown as PropertyTreeNode,
62          'entry-4' as unknown as PropertyTreeNode,
63          'entry-5' as unknown as PropertyTreeNode,
64        ])
65        .setTimestamps([time0, time1, time2, time4, time5, time6])
66        .build();
67
68      windowManager = new TraceBuilder<HierarchyTreeNode>()
69        .setType(TraceType.WINDOW_MANAGER)
70        .setEntries([
71          'entry-0' as unknown as HierarchyTreeNode,
72          'entry-1' as unknown as HierarchyTreeNode,
73        ])
74        .setTimestamps([time3, time5])
75        .build();
76
77      traces = new Traces();
78      traces.addTrace(protoLog);
79      traces.addTrace(windowManager);
80      await new FrameMapper(traces).computeMapping();
81    });
82
83    it('associates entries/frames', async () => {
84      const expectedFrames = new Map<
85        AbsoluteFrameIndex,
86        Map<TraceType, Array<{}>>
87      >();
88      expectedFrames.set(
89        0,
90        new Map<TraceType, Array<{}>>([
91          [TraceType.PROTO_LOG, ['entry-0', 'entry-1', 'entry-2']],
92          [TraceType.WINDOW_MANAGER, ['entry-0']],
93        ]),
94      );
95      expectedFrames.set(
96        1,
97        new Map<TraceType, Array<{}>>([
98          [TraceType.PROTO_LOG, ['entry-3', 'entry-4']],
99          [TraceType.WINDOW_MANAGER, ['entry-1']],
100        ]),
101      );
102
103      expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
104    });
105  });
106
107  describe('IME <-> WindowManager', () => {
108    let ime: Trace<HierarchyTreeNode>;
109    let windowManager: Trace<HierarchyTreeNode>;
110    let traces: Traces;
111
112    beforeAll(async () => {
113      // IME:            0--1--2     3
114      //                    |        |
115      // WINDOW_MANAGER:    0        1  2
116      // Time:           0  1  2  3  4  5
117      ime = new TraceBuilder<HierarchyTreeNode>()
118        .setType(TraceType.INPUT_METHOD_CLIENTS)
119        .setEntries([
120          'entry-0' as unknown as HierarchyTreeNode,
121          'entry-1' as unknown as HierarchyTreeNode,
122          'entry-2' as unknown as HierarchyTreeNode,
123          'entry-3' as unknown as HierarchyTreeNode,
124        ])
125        .setTimestamps([time0, time1, time2, time4])
126        .build();
127
128      windowManager = new TraceBuilder<HierarchyTreeNode>()
129        .setType(TraceType.WINDOW_MANAGER)
130        .setEntries([
131          'entry-0' as unknown as HierarchyTreeNode,
132          'entry-1' as unknown as HierarchyTreeNode,
133          'entry-2' as unknown as HierarchyTreeNode,
134        ])
135        .setTimestamps([time1, time4, time5])
136        .build();
137
138      traces = new Traces();
139      traces.addTrace(ime);
140      traces.addTrace(windowManager);
141      await new FrameMapper(traces).computeMapping();
142    });
143
144    it('associates entries/frames', async () => {
145      const expectedFrames = new Map<
146        AbsoluteFrameIndex,
147        Map<TraceType, Array<{}>>
148      >();
149      expectedFrames.set(
150        0,
151        new Map<TraceType, Array<{}>>([
152          [TraceType.INPUT_METHOD_CLIENTS, ['entry-0', 'entry-1', 'entry-2']],
153          [TraceType.WINDOW_MANAGER, ['entry-0']],
154        ]),
155      );
156      expectedFrames.set(
157        1,
158        new Map<TraceType, Array<{}>>([
159          [TraceType.INPUT_METHOD_CLIENTS, ['entry-3']],
160          [TraceType.WINDOW_MANAGER, ['entry-1']],
161        ]),
162      );
163      expectedFrames.set(
164        2,
165        new Map<TraceType, Array<{}>>([
166          [TraceType.INPUT_METHOD_CLIENTS, []],
167          [TraceType.WINDOW_MANAGER, ['entry-2']],
168        ]),
169      );
170
171      expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
172    });
173  });
174
175  describe('WindowManager <-> Transactions', () => {
176    let windowManager: Trace<HierarchyTreeNode>;
177    let transactions: Trace<PropertyTreeNode>;
178    let traces: Traces;
179
180    beforeAll(async () => {
181      // WINDOW_MANAGER:     0  1     2  3
182      //                     |  |     |    \
183      // TRANSACTIONS:    0  1  2--3  4     5  ... 6  <-- ignored (not connected) because too far
184      //                  |  |   |    |     |      |
185      // Frames:          0  1   2    3     4  ... 5
186      // Time:            0  1  2  3  4  5  6  ... 10s
187      windowManager = new TraceBuilder<HierarchyTreeNode>()
188        .setType(TraceType.WINDOW_MANAGER)
189        .setEntries([
190          'entry-0' as unknown as HierarchyTreeNode,
191          'entry-1' as unknown as HierarchyTreeNode,
192          'entry-2' as unknown as HierarchyTreeNode,
193          'entry-3' as unknown as HierarchyTreeNode,
194        ])
195        .setTimestamps([time1, time2, time4, time5])
196        .build();
197
198      transactions = new TraceBuilder<PropertyTreeNode>()
199        .setType(TraceType.TRANSACTIONS)
200        .setEntries([
201          'entry-0' as unknown as PropertyTreeNode,
202          'entry-1' as unknown as PropertyTreeNode,
203          'entry-2' as unknown as PropertyTreeNode,
204          'entry-3' as unknown as PropertyTreeNode,
205          'entry-4' as unknown as PropertyTreeNode,
206          'entry-5' as unknown as PropertyTreeNode,
207          'entry-6' as unknown as PropertyTreeNode,
208        ])
209        .setTimestamps([
210          time0,
211          time1,
212          time2,
213          time3,
214          time4,
215          time5,
216          time10seconds,
217        ])
218        .setFrame(0, 0)
219        .setFrame(1, 1)
220        .setFrame(2, 2)
221        .setFrame(3, 2)
222        .setFrame(4, 3)
223        .setFrame(5, 4)
224        .setFrame(6, 5)
225        .build();
226
227      traces = new Traces();
228      traces.addTrace(windowManager);
229      traces.addTrace(transactions);
230      await new FrameMapper(traces).computeMapping();
231    });
232
233    it('associates entries/frames', async () => {
234      const expectedFrames = new Map<
235        AbsoluteFrameIndex,
236        Map<TraceType, Array<{}>>
237      >();
238      expectedFrames.set(
239        0,
240        new Map<TraceType, Array<{}>>([
241          [TraceType.WINDOW_MANAGER, []],
242          [TraceType.TRANSACTIONS, ['entry-0']],
243        ]),
244      );
245      expectedFrames.set(
246        1,
247        new Map<TraceType, Array<{}>>([
248          [TraceType.WINDOW_MANAGER, ['entry-0']],
249          [TraceType.TRANSACTIONS, ['entry-1']],
250        ]),
251      );
252      expectedFrames.set(
253        2,
254        new Map<TraceType, Array<{}>>([
255          [TraceType.WINDOW_MANAGER, ['entry-1']],
256          [TraceType.TRANSACTIONS, ['entry-2', 'entry-3']],
257        ]),
258      );
259      expectedFrames.set(
260        3,
261        new Map<TraceType, Array<{}>>([
262          [TraceType.WINDOW_MANAGER, ['entry-2']],
263          [TraceType.TRANSACTIONS, ['entry-4']],
264        ]),
265      );
266      expectedFrames.set(
267        4,
268        new Map<TraceType, Array<{}>>([
269          [TraceType.WINDOW_MANAGER, ['entry-3']],
270          [TraceType.TRANSACTIONS, ['entry-5']],
271        ]),
272      );
273      expectedFrames.set(
274        5,
275        new Map<TraceType, Array<{}>>([
276          [TraceType.WINDOW_MANAGER, []],
277          [TraceType.TRANSACTIONS, ['entry-6']],
278        ]),
279      );
280
281      expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
282    });
283  });
284
285  describe('ViewCapture <-> SurfaceFlinger', () => {
286    let viewCapture: Trace<PropertyTreeNode>;
287    let surfaceFlinger: Trace<HierarchyTreeNode>;
288    let traces: Traces;
289
290    beforeAll(async () => {
291      // VIEW_CAPTURE:   0  1  2---     3
292      //                  \     \  \     \
293      //                   \     \  \     \
294      // SURFACE_FLINGER:   0     1  2     3
295      // Time:           0  1  2  3  4  5  6
296      viewCapture = new TraceBuilder<PropertyTreeNode>()
297        .setType(TraceType.VIEW_CAPTURE)
298        .setEntries([
299          'entry-0' as unknown as PropertyTreeNode,
300          'entry-1' as unknown as PropertyTreeNode,
301          'entry-2' as unknown as PropertyTreeNode,
302          'entry-3' as unknown as PropertyTreeNode,
303        ])
304        .setTimestamps([time0, time1, time2, time5])
305        .build();
306
307      surfaceFlinger = new TraceBuilder<HierarchyTreeNode>()
308        .setType(TraceType.SURFACE_FLINGER)
309        .setEntries([
310          'entry-0' as unknown as HierarchyTreeNode,
311          'entry-1' as unknown as HierarchyTreeNode,
312          'entry-2' as unknown as HierarchyTreeNode,
313          'entry-3' as unknown as HierarchyTreeNode,
314        ])
315        .setTimestamps([time1, time3, time4, time6])
316        .setFrame(0, 0)
317        .setFrame(1, 1)
318        .setFrame(2, 2)
319        .setFrame(3, 3)
320        .build();
321
322      traces = new Traces();
323      traces.addTrace(viewCapture);
324      traces.addTrace(surfaceFlinger);
325      await new FrameMapper(traces).computeMapping();
326    });
327
328    it('associates entries/frames', async () => {
329      const expectedFrames = new Map<
330        AbsoluteFrameIndex,
331        Map<TraceType, Array<{}>>
332      >();
333      expectedFrames.set(
334        0,
335        new Map<TraceType, Array<{}>>([
336          [TraceType.VIEW_CAPTURE, [await viewCapture.getEntry(0).getValue()]],
337          [
338            TraceType.SURFACE_FLINGER,
339            [await surfaceFlinger.getEntry(0).getValue()],
340          ],
341        ]),
342      );
343      expectedFrames.set(
344        1,
345        new Map<TraceType, Array<{}>>([
346          [TraceType.VIEW_CAPTURE, [await viewCapture.getEntry(2).getValue()]],
347          [
348            TraceType.SURFACE_FLINGER,
349            [await surfaceFlinger.getEntry(1).getValue()],
350          ],
351        ]),
352      );
353      expectedFrames.set(
354        2,
355        new Map<TraceType, Array<{}>>([
356          [TraceType.VIEW_CAPTURE, [await viewCapture.getEntry(2).getValue()]],
357          [
358            TraceType.SURFACE_FLINGER,
359            [await surfaceFlinger.getEntry(2).getValue()],
360          ],
361        ]),
362      );
363      expectedFrames.set(
364        3,
365        new Map<TraceType, Array<{}>>([
366          [TraceType.VIEW_CAPTURE, [await viewCapture.getEntry(3).getValue()]],
367          [
368            TraceType.SURFACE_FLINGER,
369            [await surfaceFlinger.getEntry(3).getValue()],
370          ],
371        ]),
372      );
373
374      expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
375    });
376  });
377
378  const TRACES_WITH_VSYNC_IDS = [
379    TraceType.TRANSACTIONS,
380    TraceType.INPUT_EVENT_MERGED,
381  ];
382
383  TRACES_WITH_VSYNC_IDS.forEach((traceType) => {
384    describe(`TraceType[${traceType}] <-> SurfaceFlinger`, () => {
385      const sfTrace = new TraceBuilder<HierarchyTreeNode>()
386        .setType(TraceType.SURFACE_FLINGER)
387        .setEntries([
388          'sfentry-0' as unknown as HierarchyTreeNode,
389          'sfentry-1' as unknown as HierarchyTreeNode,
390          'sfentry-2' as unknown as HierarchyTreeNode,
391        ])
392        .setTimestamps([time0, time1, time2])
393        .setParserCustomQueryResult(CustomQueryType.VSYNCID, [10n, 20n, 30n])
394        .build();
395      const entries = [
396        'entry-0' as unknown as PropertyTreeNode,
397        'entry-1' as unknown as PropertyTreeNode,
398        'entry-2' as unknown as PropertyTreeNode,
399        'entry-3' as unknown as PropertyTreeNode,
400        'entry-4' as unknown as PropertyTreeNode,
401      ];
402      let trace: Trace<PropertyTreeNode>;
403      let traces: Traces;
404
405      it('associates entries/frames', async () => {
406        // TRACE:          0  1--2        3  4
407        //                  \     \        \
408        //                   \     \        \
409        // SURFACE_FLINGER:   0     1        2
410        trace = new TraceBuilder<PropertyTreeNode>()
411          .setType(traceType)
412          .setEntries(entries)
413          .setTimestamps([time0, time1, time2, time5, time6])
414          .setParserCustomQueryResult(CustomQueryType.VSYNCID, [
415            10n,
416            20n,
417            20n,
418            30n,
419            40n,
420          ])
421          .build();
422        await computeMapping();
423        const expectedFrames = await getExpectedFrameMap([
424          [[0], 0],
425          [[1, 2], 1],
426          [[3], 2],
427        ]);
428        expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
429      });
430
431      it('does not propagate mapping if all vsync ids invalid', async () => {
432        trace = new TraceBuilder<PropertyTreeNode>()
433          .setType(traceType)
434          .setEntries(['entry-0' as unknown as PropertyTreeNode])
435          .setTimestamps([time1])
436          .setParserCustomQueryResult(CustomQueryType.VSYNCID, [-1n])
437          .build();
438
439        const sfTrace = new TraceBuilder<HierarchyTreeNode>()
440          .setType(TraceType.SURFACE_FLINGER)
441          .setEntries(['entry-0' as unknown as HierarchyTreeNode])
442          .setTimestamps([time1])
443          .setParserCustomQueryResult(CustomQueryType.VSYNCID, [1n])
444          .build();
445
446        await computeMapping(sfTrace);
447        expect(sfTrace.getEntry(0).getFramesRange()).toBeDefined();
448        expect(trace.hasFrameInfo()).toBeFalse();
449      });
450
451      it('skips invalid vsync ids', async () => {
452        // SURFACE_FLINGER: 0  1  2
453        //                  |   \  \___
454        //                  |    \     \
455        // TRACE:           0  1  2  3  4
456        trace = new TraceBuilder<PropertyTreeNode>()
457          .setType(traceType)
458          .setEntries(entries)
459          .setTimestamps([time0, time1, time2, time3, time4])
460          .setParserCustomQueryResult(CustomQueryType.VSYNCID, [
461            10n,
462            0n,
463            20n,
464            -1n,
465            30n,
466          ])
467          .build();
468
469        await computeMapping();
470        const expectedFrames = await getExpectedFrameMap([
471          [[0], 0],
472          [[2], 1],
473          [[4], 2],
474        ]);
475        expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
476      });
477
478      async function computeMapping(surfaceFlingerTrace = sfTrace) {
479        traces = new Traces();
480        traces.addTrace(trace);
481        traces.addTrace(surfaceFlingerTrace);
482        await new FrameMapper(traces).computeMapping();
483      }
484
485      async function getExpectedFrameMap(
486        expected: Array<[number[], number]>,
487      ): Promise<Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>> {
488        const expectedFrames = new Map();
489        for (const [
490          frameIndex,
491          [traceIndexes, sfIndex],
492        ] of expected.entries()) {
493          const traceEntries = await Promise.all(
494            traceIndexes.map((i) => trace.getEntry(i).getValue()),
495          );
496          const sfEntries = [await sfTrace.getEntry(sfIndex).getValue()];
497          expectedFrames.set(
498            frameIndex,
499            new Map<TraceType, Array<{}>>([
500              [traceType, traceEntries],
501              [TraceType.SURFACE_FLINGER, sfEntries],
502            ]),
503          );
504        }
505        return expectedFrames;
506      }
507    });
508  });
509
510  describe('SurfaceFlinger <-> ScreenRecording', () => {
511    let surfaceFlinger: Trace<HierarchyTreeNode>;
512    let screenRecording: Trace<MediaBasedTraceEntry>;
513    let traces: Traces;
514
515    beforeAll(async () => {
516      // SURFACE_FLINGER:      0  1  2---  3     4  5  6
517      //                              \  \  \        \
518      //                               \  \  \        \
519      // SCREEN_RECORDING:     0        1  2  3        4 ... 5 <-- ignored (not connected) because too far
520      // Time:                 0  1  2  3  4  5  6  7  8     10s
521      surfaceFlinger = new TraceBuilder<HierarchyTreeNode>()
522        .setType(TraceType.SURFACE_FLINGER)
523        .setEntries([
524          'entry-0' as unknown as HierarchyTreeNode,
525          'entry-1' as unknown as HierarchyTreeNode,
526          'entry-2' as unknown as HierarchyTreeNode,
527          'entry-3' as unknown as HierarchyTreeNode,
528          'entry-4' as unknown as HierarchyTreeNode,
529          'entry-5' as unknown as HierarchyTreeNode,
530          'entry-6' as unknown as HierarchyTreeNode,
531        ])
532        .setTimestamps([time0, time1, time2, time4, time6, time7, time8])
533        .build();
534
535      screenRecording = new TraceBuilder<MediaBasedTraceEntry>()
536        .setType(TraceType.SCREEN_RECORDING)
537        .setEntries([
538          'entry-0' as unknown as MediaBasedTraceEntry,
539          'entry-1' as unknown as MediaBasedTraceEntry,
540          'entry-2' as unknown as MediaBasedTraceEntry,
541          'entry-3' as unknown as MediaBasedTraceEntry,
542          'entry-4' as unknown as MediaBasedTraceEntry,
543          'entry-5' as unknown as MediaBasedTraceEntry,
544        ])
545        .setTimestamps([time0, time3, time4, time5, time8, time10seconds])
546        .build();
547
548      traces = new Traces();
549      traces.addTrace(surfaceFlinger);
550      traces.addTrace(screenRecording);
551      await new FrameMapper(traces).computeMapping();
552    });
553
554    it('associates entries/frames', async () => {
555      const expectedFrames = new Map<
556        AbsoluteFrameIndex,
557        Map<TraceType, Array<{}>>
558      >();
559      expectedFrames.set(
560        0,
561        new Map<TraceType, Array<{}>>([
562          [TraceType.SURFACE_FLINGER, []],
563          [TraceType.SCREEN_RECORDING, ['entry-0']],
564        ]),
565      );
566      expectedFrames.set(
567        1,
568        new Map<TraceType, Array<{}>>([
569          [TraceType.SURFACE_FLINGER, ['entry-2']],
570          [TraceType.SCREEN_RECORDING, ['entry-1']],
571        ]),
572      );
573      expectedFrames.set(
574        2,
575        new Map<TraceType, Array<{}>>([
576          [TraceType.SURFACE_FLINGER, ['entry-2']],
577          [TraceType.SCREEN_RECORDING, ['entry-2']],
578        ]),
579      );
580      expectedFrames.set(
581        3,
582        new Map<TraceType, Array<{}>>([
583          [TraceType.SURFACE_FLINGER, ['entry-3']],
584          [TraceType.SCREEN_RECORDING, ['entry-3']],
585        ]),
586      );
587      expectedFrames.set(
588        4,
589        new Map<TraceType, Array<{}>>([
590          [TraceType.SURFACE_FLINGER, ['entry-5']],
591          [TraceType.SCREEN_RECORDING, ['entry-4']],
592        ]),
593      );
594      expectedFrames.set(
595        5,
596        new Map<TraceType, Array<{}>>([
597          [TraceType.SURFACE_FLINGER, []],
598          [TraceType.SCREEN_RECORDING, ['entry-5']],
599        ]),
600      );
601
602      expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames);
603    });
604  });
605
606  it('supports multiple traces with same type', async () => {
607    // SURFACE_FLINGER_0:    0
608    //                        \
609    //                         \
610    // SURFACE_FLINGER_1:    0  \
611    //                        \ |
612    //                         \|
613    // SCREEN_RECORDING:        0
614    // Time:                 0  1
615    const surfaceFlinger0 = new TraceBuilder<HierarchyTreeNode>()
616      .setType(TraceType.SURFACE_FLINGER)
617      .setEntries(['entry-0' as unknown as HierarchyTreeNode])
618      .setTimestamps([time0])
619      .build();
620
621    const surfaceFlinger1 = new TraceBuilder<HierarchyTreeNode>()
622      .setType(TraceType.SURFACE_FLINGER)
623      .setEntries(['entry-0' as unknown as HierarchyTreeNode])
624      .setTimestamps([time0])
625      .build();
626
627    const screenRecording = new TraceBuilder<MediaBasedTraceEntry>()
628      .setType(TraceType.SCREEN_RECORDING)
629      .setEntries(['entry-0' as unknown as MediaBasedTraceEntry])
630      .setTimestamps([time1])
631      .build();
632
633    const traces = new Traces();
634    traces.addTrace(surfaceFlinger0);
635    traces.addTrace(surfaceFlinger1);
636    traces.addTrace(screenRecording);
637    await new FrameMapper(traces).computeMapping();
638
639    expect(surfaceFlinger0.getEntry(0).getFramesRange()).toEqual({
640      start: 0,
641      end: 1,
642    });
643    expect(surfaceFlinger1.getEntry(0).getFramesRange()).toEqual({
644      start: 0,
645      end: 1,
646    });
647    expect(screenRecording.getEntry(0).getFramesRange()).toEqual({
648      start: 0,
649      end: 1,
650    });
651  });
652
653  it('does not propagate mapping if frames range undefined', async () => {
654    const validTs = time1.add(2000000000n);
655    const transactions = new TraceBuilder<PropertyTreeNode>()
656      .setType(TraceType.TRANSACTIONS)
657      .setEntries(['entry-0' as unknown as PropertyTreeNode])
658      .setTimestamps([validTs])
659      .setFrame(0, 0)
660      .build();
661    const windowManager = new TraceBuilder<HierarchyTreeNode>()
662      .setType(TraceType.WINDOW_MANAGER)
663      .setEntries(['entry-0' as unknown as HierarchyTreeNode])
664      .setTimestamps([time0])
665      .build();
666    const ime = new TraceBuilder<MediaBasedTraceEntry>()
667      .setType(TraceType.INPUT_METHOD_MANAGER_SERVICE)
668      .setEntries(['entry-0' as unknown as MediaBasedTraceEntry])
669      .setTimestamps([validTs])
670      .build();
671
672    const traces = new Traces();
673    traces.addTrace(transactions);
674    traces.addTrace(windowManager);
675    traces.addTrace(ime);
676    await new FrameMapper(traces).computeMapping();
677
678    expect(transactions.getEntry(0).getFramesRange()).toBeDefined();
679    expect(windowManager.getEntry(0).getFramesRange()).toBeDefined();
680    expect(ime.hasFrameInfo()).toBeFalse();
681  });
682});
683