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