• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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