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