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 {MakeTimestampStrategyType, Timestamp} from 'common/time/time'; 19import {ParserTimestampConverter} from 'common/time/timestamp_converter'; 20import {AddDefaults} from 'parsers/operations/add_defaults'; 21import {SetFormatters} from 'parsers/operations/set_formatters'; 22import {TransformToTimestamp} from 'parsers/operations/transform_to_timestamp'; 23import {TranslateIntDef} from 'parsers/operations/translate_intdef'; 24import {TamperedMessageType} from 'parsers/tampered_message_type'; 25import {perfetto} from 'protos/transitions/latest/static'; 26import root from 'protos/transitions/udc/json'; 27import {com} from 'protos/transitions/udc/static'; 28import { 29 EnumFormatter, 30 PropertyFormatter, 31 TIMESTAMP_NODE_FORMATTER, 32} from 'trace/tree_node/formatters'; 33import {PropertyTreeBuilderFromProto} from 'trace/tree_node/property_tree_builder_from_proto'; 34import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 35import {AddDuration} from './operations/add_duration'; 36import {AddRealToBootTimeOffsetTimestamp} from './operations/add_real_to_elapsed_time_offset_timestamp'; 37import {AddRootProperties} from './operations/add_root_properties'; 38import {AddStatus} from './operations/add_status'; 39import {UpdateAbortTimeNodes} from './operations/update_abort_time_nodes'; 40import {TransitionType} from './transition_type'; 41 42interface TransitionInfo { 43 entry: 44 | com.android.server.wm.shell.ITransition 45 | com.android.wm.shell.ITransition 46 | perfetto.protos.IShellTransition; 47 realToBootTimeOffsetNs: bigint | undefined; 48 timestampConverter: ParserTimestampConverter; 49 handlerMapping?: {[key: number]: string}; 50} 51 52export class EntryPropertiesTreeFactory { 53 static readonly TRANSITION_OPERATIONS = [ 54 new AddDuration(), 55 new AddStatus(), 56 new AddRootProperties(), 57 ]; 58 59 private static readonly TransitionTraceProto = TamperedMessageType.tamper( 60 root.lookupType('com.android.server.wm.shell.TransitionTraceProto'), 61 ); 62 private static readonly TransitionField = 63 EntryPropertiesTreeFactory.TransitionTraceProto.fields['transitions']; 64 private static readonly WM_ADD_DEFAULTS_OPERATION = new AddDefaults( 65 EntryPropertiesTreeFactory.TransitionField, 66 ['type', 'targets'], 67 ); 68 private static WM_INTDEF_OPERATION = new TranslateIntDef( 69 EntryPropertiesTreeFactory.TransitionField, 70 ); 71 private static readonly SET_FORMATTERS_OPERATION = new SetFormatters(); 72 private static readonly PERFETTO_TRANSITION_OPERATIONS = [ 73 new UpdateAbortTimeNodes(), 74 ]; 75 private static readonly TRANSITION_TYPE_FORMATTER = new EnumFormatter( 76 TransitionType, 77 ); 78 79 static makeTransitionPropertiesTree( 80 shellEntryTree: PropertyTreeNode, 81 wmEntryTree: PropertyTreeNode, 82 ): PropertyTreeNode { 83 const transitionTree = new PropertyTreeNode( 84 wmEntryTree.id, 85 wmEntryTree.name, 86 wmEntryTree.source, 87 undefined, 88 ); 89 90 transitionTree.addOrReplaceChild( 91 assertDefined(shellEntryTree.getChildByName('shellData')), 92 ); 93 transitionTree.addOrReplaceChild( 94 assertDefined(wmEntryTree.getChildByName('wmData')), 95 ); 96 EntryPropertiesTreeFactory.TRANSITION_OPERATIONS.forEach((operation) => 97 operation.apply(transitionTree), 98 ); 99 return transitionTree; 100 } 101 102 static makeWmPropertiesTree( 103 info?: TransitionInfo, 104 denylistProperties: string[] = [], 105 ): PropertyTreeNode { 106 const tree = new PropertyTreeBuilderFromProto() 107 .setData({wmData: info?.entry ?? null}) 108 .setRootId('TransitionTraceEntry') 109 .setRootName('Selected Transition') 110 .setDenyList(denylistProperties) 111 .setVisitPrototype(false) 112 .build(); 113 114 if (!info) { 115 EntryPropertiesTreeFactory.SET_FORMATTERS_OPERATION.apply(tree); 116 return tree; 117 } 118 119 if (denylistProperties.length > 0) { 120 EntryPropertiesTreeFactory.PERFETTO_TRANSITION_OPERATIONS.forEach( 121 (operation) => operation.apply(tree), 122 ); 123 } 124 125 let realToBootTimeOffsetTimestamp: Timestamp | undefined; 126 127 if (info.realToBootTimeOffsetNs !== undefined) { 128 realToBootTimeOffsetTimestamp = 129 info.timestampConverter.makeTimestampFromRealNs( 130 info.realToBootTimeOffsetNs, 131 ); 132 } 133 134 const wmDataNode = assertDefined(tree.getChildByName('wmData')); 135 new AddRealToBootTimeOffsetTimestamp(realToBootTimeOffsetTimestamp).apply( 136 wmDataNode, 137 ); 138 EntryPropertiesTreeFactory.WM_ADD_DEFAULTS_OPERATION.apply(wmDataNode); 139 new TransformToTimestamp( 140 [ 141 'abortTimeNs', 142 'createTimeNs', 143 'sendTimeNs', 144 'finishTimeNs', 145 'startingWindowRemoveTimeNs', 146 ], 147 EntryPropertiesTreeFactory.makeTimestampStrategy(info.timestampConverter), 148 ).apply(wmDataNode); 149 150 const customFormatters = new Map<string, PropertyFormatter>([ 151 ['type', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER], 152 ['mode', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER], 153 ['abortTimeNs', TIMESTAMP_NODE_FORMATTER], 154 ['createTimeNs', TIMESTAMP_NODE_FORMATTER], 155 ['sendTimeNs', TIMESTAMP_NODE_FORMATTER], 156 ['finishTimeNs', TIMESTAMP_NODE_FORMATTER], 157 ['startingWindowRemoveTimeNs', TIMESTAMP_NODE_FORMATTER], 158 ]); 159 160 new SetFormatters(undefined, customFormatters).apply(tree); 161 162 EntryPropertiesTreeFactory.WM_INTDEF_OPERATION.apply(tree); 163 return tree; 164 } 165 166 static makeShellPropertiesTree( 167 info?: TransitionInfo, 168 denylistProperties: string[] = [], 169 ): PropertyTreeNode { 170 const tree = new PropertyTreeBuilderFromProto() 171 .setData({shellData: info?.entry ?? null}) 172 .setRootId('TransitionTraceEntry') 173 .setRootName('Selected Transition') 174 .setDenyList(denylistProperties) 175 .setVisitPrototype(false) 176 .build(); 177 178 if (!info) { 179 EntryPropertiesTreeFactory.SET_FORMATTERS_OPERATION.apply(tree); 180 return tree; 181 } 182 183 if (denylistProperties.length > 0) { 184 EntryPropertiesTreeFactory.PERFETTO_TRANSITION_OPERATIONS.forEach( 185 (operation) => operation.apply(tree), 186 ); 187 } 188 189 let realToBootTimeOffsetTimestamp: Timestamp | undefined; 190 if (info.realToBootTimeOffsetNs !== undefined) { 191 realToBootTimeOffsetTimestamp = 192 info.timestampConverter.makeTimestampFromRealNs( 193 info.realToBootTimeOffsetNs, 194 ); 195 } 196 197 const shellDataNode = assertDefined(tree.getChildByName('shellData')); 198 new AddRealToBootTimeOffsetTimestamp(realToBootTimeOffsetTimestamp).apply( 199 shellDataNode, 200 ); 201 new TransformToTimestamp( 202 ['dispatchTimeNs', 'mergeRequestTimeNs', 'mergeTimeNs', 'abortTimeNs'], 203 EntryPropertiesTreeFactory.makeTimestampStrategy(info.timestampConverter), 204 ).apply(shellDataNode); 205 206 const customFormatters = new Map<string, PropertyFormatter>([ 207 ['type', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER], 208 ['mode', EntryPropertiesTreeFactory.TRANSITION_TYPE_FORMATTER], 209 ['dispatchTimeNs', TIMESTAMP_NODE_FORMATTER], 210 ['mergeRequestTimeNs', TIMESTAMP_NODE_FORMATTER], 211 ['mergeTimeNs', TIMESTAMP_NODE_FORMATTER], 212 ['abortTimeNs', TIMESTAMP_NODE_FORMATTER], 213 ]); 214 215 if (info.handlerMapping) { 216 customFormatters.set('handler', new EnumFormatter(info.handlerMapping)); 217 } 218 219 new SetFormatters(undefined, customFormatters).apply(tree); 220 221 return tree; 222 } 223 224 private static makeTimestampStrategy( 225 timestampConverter: ParserTimestampConverter, 226 ): MakeTimestampStrategyType { 227 return (valueNs: bigint) => { 228 return timestampConverter.makeTimestampFromBootTimeNs(valueNs); 229 }; 230 } 231} 232