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 {StringUtils} from 'common/string_utils'; 19import {CujType} from 'parsers/events/cuj_type'; 20import {EventTag} from 'parsers/events/event_tag'; 21import {AddOperation} from 'trace/tree_node/operations/add_operation'; 22import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 23import {DEFAULT_PROPERTY_TREE_NODE_FACTORY} from 'trace/tree_node/property_tree_node_factory'; 24 25export class AddCujProperties extends AddOperation<PropertyTreeNode> { 26 protected override makeProperties( 27 value: PropertyTreeNode, 28 ): PropertyTreeNode[] { 29 const data = assertDefined(value.getChildByName('eventData')).getValue(); 30 const tag = assertDefined(value.getChildByName('tag')).getValue(); 31 const dataEntries = this.getDataEntries(data, tag); 32 const cujType = this.getCujTypeFromData(dataEntries); 33 const cujTag = this.getCujTagFromData(dataEntries, tag); 34 35 const cujTimestamp = { 36 unixNanos: this.getUnixNanosFromData(dataEntries), 37 elapsedNanos: this.getElapsedNanosFromData(dataEntries), 38 systemUptimeNanos: this.getSystemUptimeNanosFromData(dataEntries), 39 }; 40 41 return [ 42 DEFAULT_PROPERTY_TREE_NODE_FACTORY.makeProtoProperty( 43 value.id, 44 'cujType', 45 cujType, 46 ), 47 DEFAULT_PROPERTY_TREE_NODE_FACTORY.makeProtoProperty( 48 value.id, 49 'cujTimestamp', 50 cujTimestamp, 51 ), 52 DEFAULT_PROPERTY_TREE_NODE_FACTORY.makeProtoProperty( 53 value.id, 54 'cujTag', 55 cujTag, 56 ), 57 ]; 58 } 59 60 private getDataEntries(data: string, tag: EventTag): string[] { 61 let [cujType, unixNs, elapsedNs, uptimeNs, _tag] = ['', '', '', '', '', '']; 62 if (tag === EventTag.JANK_CUJ_BEGIN_TAG) { 63 // (CUJ Type|1|5),(Unix Time Ns|2|3),(Elapsed Time Ns|2|3),(Uptime Time Ns|2|3) 64 [cujType, unixNs, elapsedNs, uptimeNs, _tag] = data 65 .replace('[', '') 66 .replace(']', '') 67 .split(','); 68 } else { 69 [cujType, unixNs, elapsedNs, uptimeNs] = data 70 .replace('[', '') 71 .replace(']', '') 72 .split(','); 73 } 74 75 if ( 76 !StringUtils.isNumeric(cujType) || 77 !StringUtils.isNumeric(unixNs) || 78 !StringUtils.isNumeric(elapsedNs) || 79 !StringUtils.isNumeric(uptimeNs) 80 ) { 81 throw Error(`Data ${data} didn't match expected format`); 82 } 83 84 return data.slice(1, data.length - 2).split(','); 85 } 86 87 private getCujTypeFromData(dataEntries: string[]): CujType { 88 const eventId = Number(dataEntries[0]); 89 const cujType = Object.values(CujType).find((type) => type === eventId); 90 if (!cujType || typeof cujType === 'string') { 91 return CujType.UNKNOWN; 92 } 93 return cujType; 94 } 95 96 private getUnixNanosFromData(dataEntries: string[]): bigint { 97 return BigInt(dataEntries[1]); 98 } 99 100 private getElapsedNanosFromData(dataEntries: string[]): bigint { 101 return BigInt(dataEntries[2]); 102 } 103 104 private getSystemUptimeNanosFromData(dataEntries: string[]): bigint { 105 return BigInt(dataEntries[3]); 106 } 107 108 private getCujTagFromData( 109 dataEntries: string[], 110 tag: EventTag, 111 ): string | null { 112 return tag === EventTag.JANK_CUJ_BEGIN_TAG ? dataEntries[4] : null; 113 } 114} 115