1# 2# Copyright (C) 2017 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 16import logging 17import os 18 19from vts.proto import VtsReportMessage_pb2 as ReportMsg 20from vts.runners.host import keys 21from vts.utils.python.systrace import systrace_controller 22from vts.utils.python.web import feature_utils 23 24_SYSTRACE_CONTROLLER = "systrace_controller" 25 26 27class SystraceFeature(feature_utils.Feature): 28 """Feature object for systrace functionality. 29 30 Attributes: 31 enabled: boolean, True if systrace is enabled, False otherwise 32 web: (optional) WebFeature, object storing web feature util for test run 33 """ 34 35 _TOGGLE_PARAM = keys.ConfigKeys.IKEY_ENABLE_SYSTRACE 36 _REQUIRED_PARAMS = [ 37 keys.ConfigKeys.KEY_TESTBED_NAME, keys.ConfigKeys.IKEY_ANDROID_DEVICE, 38 keys.ConfigKeys.IKEY_DATA_FILE_PATH, 39 keys.ConfigKeys.IKEY_SYSTRACE_REPORT_PATH, 40 keys.ConfigKeys.IKEY_SYSTRACE_REPORT_URL_PREFIX 41 ] 42 _OPTIONAL_PARAMS = [keys.ConfigKeys.IKEY_SYSTRACE_PROCESS_NAME] 43 44 def __init__(self, user_params, web=None): 45 """Initializes the systrace feature. 46 47 Args: 48 user_params: A dictionary from parameter name (String) to parameter value. 49 web: (optional) WebFeature, object storing web feature util for test run 50 """ 51 self.ParseParameters(self._TOGGLE_PARAM, self._REQUIRED_PARAMS, 52 self._OPTIONAL_PARAMS, user_params) 53 self.web = web 54 if self.enabled: 55 logging.info("Systrace is enabled.") 56 else: 57 logging.debug("Systrace is disabled.") 58 59 def StartSystrace(self): 60 """Initialize systrace controller if enabled. 61 62 Requires the feature to be enabled; no-op otherwise. 63 """ 64 if not self.enabled: 65 return 66 67 process_name = getattr(self, 68 keys.ConfigKeys.IKEY_SYSTRACE_PROCESS_NAME, '') 69 process_name = str(process_name) 70 data_file_path = getattr(self, keys.ConfigKeys.IKEY_DATA_FILE_PATH) 71 72 # TODO: handle device_serial for multi-device 73 android_devices = getattr(self, keys.ConfigKeys.IKEY_ANDROID_DEVICE) 74 if not isinstance(android_devices, list): 75 logging.warn("android device information not available") 76 return 77 device_spec = android_devices[0] 78 serial = device_spec.get(keys.ConfigKeys.IKEY_SERIAL) 79 if not serial: 80 logging.error("Serial for device at index 0 is not available.") 81 self.enabled = False 82 serial = str(serial) 83 84 android_vts_path = os.path.normpath(os.path.join(data_file_path, '..')) 85 self.controller = systrace_controller.SystraceController( 86 android_vts_path, device_serial=serial, process_name=process_name) 87 self.controller.Start() 88 89 def ProcessAndUploadSystrace(self, test_name): 90 """Stops and outputs the systrace data to configured path. 91 92 Requires the feature to be enabled; no-op otherwise. 93 94 Args: 95 test_name: String, the name of the test 96 """ 97 if not self.enabled: 98 return 99 100 controller = getattr(self, "controller", None) 101 if not controller: 102 logging.warn("ProcessSystrace: missing systrace controller") 103 return 104 105 controller.Stop() 106 107 if not controller.has_output: 108 logging.warn("ProcessSystrace: systrace controller has no output") 109 return 110 111 try: 112 test_module_name = getattr(self, keys.ConfigKeys.KEY_TESTBED_NAME) 113 process = controller.process_name 114 time = feature_utils.GetTimestamp() 115 report_path = getattr(self, 116 keys.ConfigKeys.IKEY_SYSTRACE_REPORT_PATH) 117 report_destination_file_name = 'systrace_{test}_{process}_{time}.html'.format( 118 test=test_name, process=process, time=time) 119 report_destination_file_path = os.path.join( 120 report_path, report_destination_file_name) 121 if controller.SaveLastOutput(report_destination_file_path): 122 logging.debug('Systrace output saved to %s', 123 report_destination_file_path) 124 else: 125 logging.error('Failed to save systrace output.') 126 127 report_url_prefix = getattr( 128 self, keys.ConfigKeys.IKEY_SYSTRACE_REPORT_URL_PREFIX) 129 report_url_prefix = str(report_url_prefix) 130 report_destination_file_url = '%s%s' % ( 131 report_url_prefix, report_destination_file_name) 132 133 if self.web and self.web.enabled: 134 self.web.AddSystraceUrl(report_destination_file_url) 135 logging.info('systrace result path %s .', 136 report_destination_file_url) 137 except Exception as e: # TODO(yuexima): more specific exceptions catch 138 logging.exception('Failed to add systrace to report message %s', e) 139 finally: 140 if not controller.ClearLastOutput(): 141 logging.error('failed to clear last systrace output.') 142