1# 2# Copyright (C) 2025 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 argparse 18from .command import Command 19from .validation_error import ValidationError 20 21TRACED_ENABLE_PROP = "persist.traced.enable" 22TRACED_RELAY_PRODUCER_PORT_PROP = "traced.relay_producer_port" 23TRACED_RELAY_PORT_PROP = "traced_relay.relay_port" 24TRACED_HYPERVISOR_PROP = "ro.traced.hypervisor" 25 26def add_vm_parser(subparsers): 27 vm_parser = subparsers.add_parser('vm', 28 help=('The vm subcommand is used ' 29 'to configure perfetto in ' 30 'virtualized Android.')) 31 vm_subparsers = vm_parser.add_subparsers(dest='vm_subcommand') 32 33 # Traced relay subcommand 34 traced_relay_parser = vm_subparsers.add_parser('traced-relay', 35 help=('Configure traced_relay')) 36 traced_relay_subparsers = traced_relay_parser.add_subparsers(dest='vm_traced_relay_subcommand') 37 38 enable_tr_parser = traced_relay_subparsers.add_parser('enable', help=('Enable traced_relay')) 39 enable_tr_parser.add_argument('relay_port', help='Socket address to communicate with traced.') 40 41 traced_relay_subparsers.add_parser('disable', help=('Disable traced_relay')) 42 43 # Traced relay producer subcommand 44 relay_producer_parser = vm_subparsers.add_parser('relay-producer', 45 help=('Configure traced\'s relay ' 46 'producer socket')) 47 relay_producer_subparsers = \ 48 relay_producer_parser.add_subparsers(dest='vm_relay_producer_subcommand') 49 50 enable_rp_parser = \ 51 relay_producer_subparsers.add_parser('enable', 52 help=('Enable traced\'s relay producer port')) 53 enable_rp_parser.add_argument('--address', dest='relay_prod_port', 54 default='vsock://-1:30001', 55 help='Socket address used for relayed communication.') 56 57 relay_producer_subparsers.add_parser('disable', help=('Disable traced\'s relay producer port')) 58 59 60def create_vm_command(args): 61 if args.vm_subcommand == 'traced-relay': 62 relay_port = None 63 if args.vm_traced_relay_subcommand == 'enable': 64 relay_port = args.relay_port 65 66 return VmCommand(args.vm_subcommand, 67 args.vm_traced_relay_subcommand, 68 relay_port, None) 69 # relay-producer command 70 relay_prod_port = None 71 if args.vm_relay_producer_subcommand == 'enable': 72 relay_prod_port = args.relay_prod_port 73 return VmCommand(args.vm_subcommand, 74 args.vm_relay_producer_subcommand, 75 None, relay_prod_port) 76 77class VmCommand(Command): 78 """ 79 Represents commands which configure perfetto 80 in virtualized Android. 81 """ 82 def __init__(self, type, subcommand, relay_port, relay_prod_port): 83 super().__init__(type) 84 self.subcommand = subcommand 85 self.relay_port = relay_port 86 self.relay_prod_port = relay_prod_port 87 88 def validate(self, device): 89 raise NotImplementedError 90 91 def execute(self, device): 92 error = device.check_device_connection() 93 if error is not None: 94 return error 95 device.root_device() 96 if self.type == 'traced-relay': 97 return self.traced_relay_execute(device) 98 # else it's a relay-producer command 99 return self.relay_producer_execute(device) 100 101 def traced_relay_execute(self, device): 102 if self.subcommand == 'enable': 103 if (len(device.get_prop(TRACED_HYPERVISOR_PROP)) == 0): 104 # Traced_relay can only be used in virtualized environments, 105 # therefore set the |TRACED_HYPERVISOR_PROP| to true if 106 # enabling traced_relay. 107 print(f"Setting sysprop \"{TRACED_HYPERVISOR_PROP}\" to \"true\"") 108 device.set_prop(TRACED_HYPERVISOR_PROP, "true") 109 device.set_prop(TRACED_RELAY_PORT_PROP, self.relay_port) 110 device.set_prop(TRACED_ENABLE_PROP, "2") 111 else: # disable 112 device.set_prop(TRACED_ENABLE_PROP, "1") 113 return None 114 115 def relay_producer_execute(self, device): 116 if self.subcommand == 'enable': 117 device.set_prop(TRACED_ENABLE_PROP, "0") 118 device.set_prop(TRACED_RELAY_PRODUCER_PORT_PROP, self.relay_prod_port) 119 device.set_prop(TRACED_ENABLE_PROP, "1") 120 else: #disable 121 device.set_prop(TRACED_ENABLE_PROP, "0") 122 device.clear_prop(TRACED_RELAY_PRODUCER_PORT_PROP) 123 device.set_prop(TRACED_ENABLE_PROP, "1") 124 return None 125