1/* 2 * Copyright (C) 2024 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 {assertDefined} from 'common/assert_utils'; 18import {android} from 'protos/transactions/udc/static'; 19import {FixedStringFormatter} from 'trace/tree_node/formatters'; 20import {Operation} from 'trace/tree_node/operations/operation'; 21import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 22 23export class TranslateChanges implements Operation<PropertyTreeNode> { 24 apply(value: PropertyTreeNode): void { 25 value 26 .getChildByName('transactions') 27 ?.getAllChildren() 28 .forEach((transactionState) => { 29 transactionState 30 .getChildByName('layerChanges') 31 ?.getAllChildren() 32 .forEach((layerState) => { 33 this.translateLayerChanges(layerState); 34 }); 35 36 transactionState 37 .getChildByName('displayChanges') 38 ?.getAllChildren() 39 .forEach((displayState) => { 40 this.translateDisplayChanges(displayState); 41 }); 42 }); 43 44 value 45 .getChildByName('addedDisplays') 46 ?.getAllChildren() 47 .forEach((displayState) => { 48 this.translateDisplayChanges(displayState); 49 }); 50 } 51 52 private translateLayerChanges(layerState: PropertyTreeNode) { 53 const what = assertDefined(layerState.getChildByName('what')); 54 55 const originalValue = what.getValue(); 56 let translation: string = ''; 57 58 if (originalValue.low !== undefined && originalValue.high !== undefined) { 59 translation = this.concatBitsetTokens( 60 this.decodeBitset32( 61 originalValue.low, 62 android.surfaceflinger.proto.LayerState.ChangesLsb, 63 ).concat( 64 this.decodeBitset32( 65 originalValue.high, 66 android.surfaceflinger.proto.LayerState.ChangesMsb, 67 ), 68 ), 69 ); 70 } else { 71 const bigintValue = BigInt(originalValue?.toString() ?? 0n); 72 translation = this.concatBitsetTokens( 73 this.decodeBitset32( 74 Number(bigintValue), 75 android.surfaceflinger.proto.LayerState.ChangesLsb, 76 ).concat( 77 this.decodeBitset32( 78 Number(bigintValue >> 32n), 79 android.surfaceflinger.proto.LayerState.ChangesMsb, 80 ), 81 ), 82 ); 83 } 84 85 what.setFormatter(new FixedStringFormatter(translation)); 86 } 87 88 private translateDisplayChanges(displayState: PropertyTreeNode) { 89 const what = assertDefined(displayState.getChildByName('what')); 90 const originalValue = what.getValue(); 91 92 const translation = this.concatBitsetTokens( 93 this.decodeBitset32( 94 Number(originalValue), 95 android.surfaceflinger.proto.DisplayState.Changes, 96 ), 97 ); 98 99 what.setFormatter(new FixedStringFormatter(translation)); 100 } 101 102 private decodeBitset32( 103 bitset: number, 104 EnumProto: {[key: number]: string}, 105 ): string[] { 106 const changes = Object.values(EnumProto) 107 .filter((key) => { 108 if (Number.isNaN(Number(key))) { 109 return false; 110 } 111 return (bitset & Number(key)) !== 0; 112 }) 113 .map((key) => EnumProto[Number(key)]); 114 return changes; 115 } 116 117 private concatBitsetTokens(tokens: string[]): string { 118 if (tokens.length === 0) { 119 return '0'; 120 } 121 return tokens.join(' | '); 122 } 123} 124