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 {TracesUtils} from 'test/unit/traces_utils'; 18import {TraceBuilder} from 'test/unit/trace_builder'; 19import {LayerTraceEntry} from './flickerlib/layers/LayerTraceEntry'; 20import {WindowManagerState} from './flickerlib/windows/WindowManagerState'; 21import {FrameMapper} from './frame_mapper'; 22import {AbsoluteFrameIndex} from './index_types'; 23import {LogMessage} from './protolog'; 24import {ScreenRecordingTraceEntry} from './screen_recording'; 25import {RealTimestamp} from './timestamp'; 26import {Trace} from './trace'; 27import {Traces} from './traces'; 28import {TraceType} from './trace_type'; 29 30describe('FrameMapper', () => { 31 const time0 = new RealTimestamp(0n); 32 const time1 = new RealTimestamp(1n); 33 const time2 = new RealTimestamp(2n); 34 const time3 = new RealTimestamp(3n); 35 const time4 = new RealTimestamp(4n); 36 const time5 = new RealTimestamp(5n); 37 const time6 = new RealTimestamp(6n); 38 const time7 = new RealTimestamp(7n); 39 const time8 = new RealTimestamp(8n); 40 const time9 = new RealTimestamp(9n); 41 const time10 = new RealTimestamp(10n); 42 const time10seconds = new RealTimestamp(10n * 1000000000n); 43 44 describe('ProtoLog <-> WindowManager', () => { 45 let protoLog: Trace<LogMessage>; 46 let windowManager: Trace<WindowManagerState>; 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<LogMessage>() 56 .setEntries([ 57 'entry-0' as unknown as LogMessage, 58 'entry-1' as unknown as LogMessage, 59 'entry-2' as unknown as LogMessage, 60 'entry-3' as unknown as LogMessage, 61 'entry-4' as unknown as LogMessage, 62 'entry-5' as unknown as LogMessage, 63 ]) 64 .setTimestamps([time0, time1, time2, time4, time5, time6]) 65 .build(); 66 67 windowManager = new TraceBuilder<WindowManagerState>() 68 .setEntries([ 69 'entry-0' as unknown as WindowManagerState, 70 'entry-1' as unknown as WindowManagerState, 71 ]) 72 .setTimestamps([time3, time5]) 73 .build(); 74 75 traces = new Traces(); 76 traces.setTrace(TraceType.PROTO_LOG, protoLog); 77 traces.setTrace(TraceType.WINDOW_MANAGER, windowManager); 78 await new FrameMapper(traces).computeMapping(); 79 }); 80 81 it('associates entries/frames', async () => { 82 const expectedFrames = new Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>(); 83 expectedFrames.set( 84 0, 85 new Map<TraceType, Array<{}>>([ 86 [TraceType.PROTO_LOG, ['entry-0', 'entry-1', 'entry-2']], 87 [TraceType.WINDOW_MANAGER, ['entry-0']], 88 ]) 89 ); 90 expectedFrames.set( 91 1, 92 new Map<TraceType, Array<{}>>([ 93 [TraceType.PROTO_LOG, ['entry-3', 'entry-4']], 94 [TraceType.WINDOW_MANAGER, ['entry-1']], 95 ]) 96 ); 97 98 expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames); 99 }); 100 }); 101 102 describe('IME <-> WindowManager', () => { 103 let ime: Trace<object>; 104 let windowManager: Trace<WindowManagerState>; 105 let traces: Traces; 106 107 beforeAll(async () => { 108 // IME: 0--1--2 3 109 // | | 110 // WINDOW_MANAGER: 0 1 2 111 // Time: 0 1 2 3 4 5 112 ime = new TraceBuilder<object>() 113 .setEntries([ 114 'entry-0' as unknown as object, 115 'entry-1' as unknown as object, 116 'entry-2' as unknown as object, 117 'entry-3' as unknown as object, 118 ]) 119 .setTimestamps([time0, time1, time2, time4]) 120 .build(); 121 122 windowManager = new TraceBuilder<WindowManagerState>() 123 .setEntries([ 124 'entry-0' as unknown as WindowManagerState, 125 'entry-1' as unknown as WindowManagerState, 126 'entry-2' as unknown as WindowManagerState, 127 ]) 128 .setTimestamps([time1, time4, time5]) 129 .build(); 130 131 traces = new Traces(); 132 traces.setTrace(TraceType.INPUT_METHOD_CLIENTS, ime); 133 traces.setTrace(TraceType.WINDOW_MANAGER, windowManager); 134 await new FrameMapper(traces).computeMapping(); 135 }); 136 137 it('associates entries/frames', async () => { 138 const expectedFrames = new Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>(); 139 expectedFrames.set( 140 0, 141 new Map<TraceType, Array<{}>>([ 142 [TraceType.INPUT_METHOD_CLIENTS, ['entry-0', 'entry-1', 'entry-2']], 143 [TraceType.WINDOW_MANAGER, ['entry-0']], 144 ]) 145 ); 146 expectedFrames.set( 147 1, 148 new Map<TraceType, Array<{}>>([ 149 [TraceType.INPUT_METHOD_CLIENTS, ['entry-3']], 150 [TraceType.WINDOW_MANAGER, ['entry-1']], 151 ]) 152 ); 153 expectedFrames.set( 154 2, 155 new Map<TraceType, Array<{}>>([ 156 [TraceType.INPUT_METHOD_CLIENTS, []], 157 [TraceType.WINDOW_MANAGER, ['entry-2']], 158 ]) 159 ); 160 161 expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames); 162 }); 163 }); 164 165 describe('WindowManager <-> Transactions', () => { 166 let windowManager: Trace<WindowManagerState>; 167 let transactions: Trace<object>; 168 let traces: Traces; 169 170 beforeAll(async () => { 171 // WINDOW_MANAGER: 0 1 2 3 172 // | | | \ 173 // TRANSACTIONS: 0 1 2--3 4 5 ... 6 <-- ignored (not connected) because too far 174 // | | | | | | 175 // Frames: 0 1 2 3 4 ... 5 176 // Time: 0 1 2 3 4 5 6 ... 10s 177 windowManager = new TraceBuilder<LogMessage>() 178 .setEntries([ 179 'entry-0' as unknown as WindowManagerState, 180 'entry-1' as unknown as WindowManagerState, 181 'entry-2' as unknown as WindowManagerState, 182 'entry-3' as unknown as WindowManagerState, 183 ]) 184 .setTimestamps([time1, time2, time4, time5]) 185 .build(); 186 187 transactions = new TraceBuilder<object>() 188 .setEntries([ 189 'entry-0' as unknown as object, 190 'entry-1' as unknown as object, 191 'entry-2' as unknown as object, 192 'entry-3' as unknown as object, 193 'entry-4' as unknown as object, 194 'entry-5' as unknown as object, 195 'entry-6' as unknown as object, 196 ]) 197 .setTimestamps([time0, time1, time2, time3, time4, time5, time10seconds]) 198 .setFrame(0, 0) 199 .setFrame(1, 1) 200 .setFrame(2, 2) 201 .setFrame(3, 2) 202 .setFrame(4, 3) 203 .setFrame(5, 4) 204 .setFrame(6, 5) 205 .build(); 206 207 traces = new Traces(); 208 traces.setTrace(TraceType.WINDOW_MANAGER, windowManager); 209 traces.setTrace(TraceType.TRANSACTIONS, transactions); 210 await new FrameMapper(traces).computeMapping(); 211 }); 212 213 it('associates entries/frames', async () => { 214 const expectedFrames = new Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>(); 215 expectedFrames.set( 216 0, 217 new Map<TraceType, Array<{}>>([ 218 [TraceType.WINDOW_MANAGER, []], 219 [TraceType.TRANSACTIONS, ['entry-0']], 220 ]) 221 ); 222 expectedFrames.set( 223 1, 224 new Map<TraceType, Array<{}>>([ 225 [TraceType.WINDOW_MANAGER, ['entry-0']], 226 [TraceType.TRANSACTIONS, ['entry-1']], 227 ]) 228 ); 229 expectedFrames.set( 230 2, 231 new Map<TraceType, Array<{}>>([ 232 [TraceType.WINDOW_MANAGER, ['entry-1']], 233 [TraceType.TRANSACTIONS, ['entry-2', 'entry-3']], 234 ]) 235 ); 236 expectedFrames.set( 237 3, 238 new Map<TraceType, Array<{}>>([ 239 [TraceType.WINDOW_MANAGER, ['entry-2']], 240 [TraceType.TRANSACTIONS, ['entry-4']], 241 ]) 242 ); 243 expectedFrames.set( 244 4, 245 new Map<TraceType, Array<{}>>([ 246 [TraceType.WINDOW_MANAGER, ['entry-3']], 247 [TraceType.TRANSACTIONS, ['entry-5']], 248 ]) 249 ); 250 expectedFrames.set( 251 5, 252 new Map<TraceType, Array<{}>>([ 253 [TraceType.WINDOW_MANAGER, []], 254 [TraceType.TRANSACTIONS, ['entry-6']], 255 ]) 256 ); 257 258 expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames); 259 }); 260 }); 261 262 describe('Transactions <-> SurfaceFlinger', () => { 263 let transactions: Trace<object>; 264 let surfaceFlinger: Trace<LayerTraceEntry>; 265 let traces: Traces; 266 267 beforeAll(async () => { 268 // TRANSACTIONS: 0 1--2 3 4 269 // \ \ \ 270 // \ \ \ 271 // SURFACE_FLINGER: 0 1 2 272 transactions = new TraceBuilder<object>() 273 .setEntries([ 274 {id: 0, vsyncId: createVsyncId(0)}, 275 {id: 1, vsyncId: createVsyncId(10)}, 276 {id: 2, vsyncId: createVsyncId(10)}, 277 {id: 3, vsyncId: createVsyncId(20)}, 278 {id: 4, vsyncId: createVsyncId(30)}, 279 ]) 280 .setTimestamps([time0, time1, time2, time5, time6]) 281 .build(); 282 283 surfaceFlinger = new TraceBuilder<LayerTraceEntry>() 284 .setEntries([ 285 {id: 0, vSyncId: createVsyncId(0)} as unknown as LayerTraceEntry, 286 {id: 1, vSyncId: createVsyncId(10)} as unknown as LayerTraceEntry, 287 {id: 2, vSyncId: createVsyncId(20)} as unknown as LayerTraceEntry, 288 ]) 289 .setTimestamps([time0, time1, time2]) 290 .build(); 291 292 traces = new Traces(); 293 traces.setTrace(TraceType.TRANSACTIONS, transactions); 294 traces.setTrace(TraceType.SURFACE_FLINGER, surfaceFlinger); 295 await new FrameMapper(traces).computeMapping(); 296 }); 297 298 it('associates entries/frames', async () => { 299 const expectedFrames = new Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>(); 300 expectedFrames.set( 301 0, 302 new Map<TraceType, Array<{}>>([ 303 [TraceType.TRANSACTIONS, [await transactions.getEntry(0).getValue()]], 304 [TraceType.SURFACE_FLINGER, [await surfaceFlinger.getEntry(0).getValue()]], 305 ]) 306 ); 307 expectedFrames.set( 308 1, 309 new Map<TraceType, Array<{}>>([ 310 [ 311 TraceType.TRANSACTIONS, 312 [await transactions.getEntry(1).getValue(), await transactions.getEntry(2).getValue()], 313 ], 314 [TraceType.SURFACE_FLINGER, [await surfaceFlinger.getEntry(1).getValue()]], 315 ]) 316 ); 317 expectedFrames.set( 318 2, 319 new Map<TraceType, Array<{}>>([ 320 [TraceType.TRANSACTIONS, [await transactions.getEntry(3).getValue()]], 321 [TraceType.SURFACE_FLINGER, [await surfaceFlinger.getEntry(2).getValue()]], 322 ]) 323 ); 324 325 expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames); 326 }); 327 }); 328 329 describe('SurfaceFlinger <-> ScreenRecording', () => { 330 let surfaceFlinger: Trace<LayerTraceEntry>; 331 let screenRecording: Trace<ScreenRecordingTraceEntry>; 332 let traces: Traces; 333 334 beforeAll(async () => { 335 // SURFACE_FLINGER: 0 1 2--- 3 4 5 6 336 // \ \ \ \ 337 // \ \ \ \ 338 // SCREEN_RECORDING: 0 1 2 3 4 ... 5 <-- ignored (not connected) because too far 339 // Time: 0 1 2 3 4 5 6 7 8 10s 340 surfaceFlinger = new TraceBuilder<LayerTraceEntry>() 341 .setEntries([ 342 'entry-0' as unknown as LayerTraceEntry, 343 'entry-1' as unknown as LayerTraceEntry, 344 'entry-2' as unknown as LayerTraceEntry, 345 'entry-3' as unknown as LayerTraceEntry, 346 'entry-4' as unknown as LayerTraceEntry, 347 'entry-5' as unknown as LayerTraceEntry, 348 'entry-6' as unknown as LayerTraceEntry, 349 ]) 350 .setTimestamps([time0, time1, time2, time4, time6, time7, time8]) 351 .build(); 352 353 screenRecording = new TraceBuilder<ScreenRecordingTraceEntry>() 354 .setEntries([ 355 'entry-0' as unknown as ScreenRecordingTraceEntry, 356 'entry-1' as unknown as ScreenRecordingTraceEntry, 357 'entry-2' as unknown as ScreenRecordingTraceEntry, 358 'entry-3' as unknown as ScreenRecordingTraceEntry, 359 'entry-4' as unknown as ScreenRecordingTraceEntry, 360 'entry-5' as unknown as ScreenRecordingTraceEntry, 361 ]) 362 .setTimestamps([time0, time3, time4, time5, time8, time10seconds]) 363 .build(); 364 365 traces = new Traces(); 366 traces.setTrace(TraceType.SURFACE_FLINGER, surfaceFlinger); 367 traces.setTrace(TraceType.SCREEN_RECORDING, screenRecording); 368 await new FrameMapper(traces).computeMapping(); 369 }); 370 371 it('associates entries/frames', async () => { 372 const expectedFrames = new Map<AbsoluteFrameIndex, Map<TraceType, Array<{}>>>(); 373 expectedFrames.set( 374 0, 375 new Map<TraceType, Array<{}>>([ 376 [TraceType.SURFACE_FLINGER, []], 377 [TraceType.SCREEN_RECORDING, ['entry-0']], 378 ]) 379 ); 380 expectedFrames.set( 381 1, 382 new Map<TraceType, Array<{}>>([ 383 [TraceType.SURFACE_FLINGER, ['entry-2']], 384 [TraceType.SCREEN_RECORDING, ['entry-1']], 385 ]) 386 ); 387 expectedFrames.set( 388 2, 389 new Map<TraceType, Array<{}>>([ 390 [TraceType.SURFACE_FLINGER, ['entry-2']], 391 [TraceType.SCREEN_RECORDING, ['entry-2']], 392 ]) 393 ); 394 expectedFrames.set( 395 3, 396 new Map<TraceType, Array<{}>>([ 397 [TraceType.SURFACE_FLINGER, ['entry-3']], 398 [TraceType.SCREEN_RECORDING, ['entry-3']], 399 ]) 400 ); 401 expectedFrames.set( 402 4, 403 new Map<TraceType, Array<{}>>([ 404 [TraceType.SURFACE_FLINGER, ['entry-5']], 405 [TraceType.SCREEN_RECORDING, ['entry-4']], 406 ]) 407 ); 408 expectedFrames.set( 409 5, 410 new Map<TraceType, Array<{}>>([ 411 [TraceType.SURFACE_FLINGER, []], 412 [TraceType.SCREEN_RECORDING, ['entry-5']], 413 ]) 414 ); 415 416 expect(await TracesUtils.extractFrames(traces)).toEqual(expectedFrames); 417 }); 418 }); 419 420 const createVsyncId = (value: number): object => { 421 return { 422 toString() { 423 return value.toString(); 424 }, 425 }; 426 }; 427}); 428