1/* 2 * Copyright (C) 2022 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 {Timestamp, TimestampType} from 'trace/timestamp'; 18import {TraceFile} from 'trace/trace_file'; 19import {TraceType} from 'trace/trace_type'; 20import {AbstractParser} from './abstract_parser'; 21import {TransactionsTraceFileProto} from './proto_types'; 22 23class ParserTransactions extends AbstractParser { 24 constructor(trace: TraceFile) { 25 super(trace); 26 this.realToElapsedTimeOffsetNs = undefined; 27 } 28 29 override getTraceType(): TraceType { 30 return TraceType.TRANSACTIONS; 31 } 32 33 override getMagicNumber(): number[] { 34 return ParserTransactions.MAGIC_NUMBER; 35 } 36 37 override decodeTrace(buffer: Uint8Array): any[] { 38 const decodedProto = TransactionsTraceFileProto.decode(buffer) as any; 39 this.decodeWhatFields(decodedProto); 40 41 if (Object.prototype.hasOwnProperty.call(decodedProto, 'realToElapsedTimeOffsetNanos')) { 42 this.realToElapsedTimeOffsetNs = BigInt(decodedProto.realToElapsedTimeOffsetNanos); 43 } else { 44 this.realToElapsedTimeOffsetNs = undefined; 45 } 46 return decodedProto.entry; 47 } 48 49 private decodeWhatFields(decodedProto: any) { 50 const decodeBitset32 = (bitset: number, EnumProto: any) => { 51 return Object.keys(EnumProto).filter((key) => { 52 const value = EnumProto[key]; 53 return (bitset & value) !== 0; 54 }); 55 }; 56 57 const concatBitsetTokens = (tokens: string[]) => { 58 if (tokens.length === 0) { 59 return '0'; 60 } 61 return tokens.join(' | '); 62 }; 63 64 const LayerStateChangesLsbEnum = (TransactionsTraceFileProto?.parent as any).LayerState 65 .ChangesLsb; 66 const LayerStateChangesMsbEnum = (TransactionsTraceFileProto?.parent as any).LayerState 67 .ChangesMsb; 68 const DisplayStateChangesEnum = (TransactionsTraceFileProto?.parent as any).DisplayState 69 .Changes; 70 71 decodedProto.entry.forEach((transactionTraceEntry: any) => { 72 transactionTraceEntry.transactions.forEach((transactionState: any) => { 73 transactionState.layerChanges.forEach((layerState: any) => { 74 layerState.what = concatBitsetTokens( 75 decodeBitset32(layerState.what.low, LayerStateChangesLsbEnum).concat( 76 decodeBitset32(layerState.what.high, LayerStateChangesMsbEnum) 77 ) 78 ); 79 }); 80 81 transactionState.displayChanges.forEach((displayState: any) => { 82 displayState.what = concatBitsetTokens( 83 decodeBitset32(displayState.what, DisplayStateChangesEnum) 84 ); 85 }); 86 }); 87 88 transactionTraceEntry.addedDisplays.forEach((displayState: any) => { 89 displayState.what = concatBitsetTokens( 90 decodeBitset32(displayState.what, DisplayStateChangesEnum) 91 ); 92 }); 93 }); 94 } 95 96 override getTimestamp(type: TimestampType, entryProto: any): undefined | Timestamp { 97 if (type === TimestampType.ELAPSED) { 98 return new Timestamp(type, BigInt(entryProto.elapsedRealtimeNanos)); 99 } else if (type === TimestampType.REAL && this.realToElapsedTimeOffsetNs !== undefined) { 100 return new Timestamp( 101 type, 102 this.realToElapsedTimeOffsetNs + BigInt(entryProto.elapsedRealtimeNanos) 103 ); 104 } 105 return undefined; 106 } 107 108 override processDecodedEntry( 109 index: number, 110 timestampType: TimestampType, 111 entryProto: object 112 ): object { 113 return entryProto; 114 } 115 116 private realToElapsedTimeOffsetNs: undefined | bigint; 117 private static readonly MAGIC_NUMBER = [0x09, 0x54, 0x4e, 0x58, 0x54, 0x52, 0x41, 0x43, 0x45]; // .TNXTRACE 118} 119 120export {ParserTransactions}; 121