普通文本  |  142行  |  5.52 KB

#
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os

from vts.proto import VtsReportMessage_pb2 as ReportMsg
from vts.runners.host import keys
from vts.utils.python.systrace import systrace_controller
from vts.utils.python.web import feature_utils

_SYSTRACE_CONTROLLER = "systrace_controller"


class SystraceFeature(feature_utils.Feature):
    """Feature object for systrace functionality.

    Attributes:
        enabled: boolean, True if systrace is enabled, False otherwise
        web: (optional) WebFeature, object storing web feature util for test run
    """

    _TOGGLE_PARAM = keys.ConfigKeys.IKEY_ENABLE_SYSTRACE
    _REQUIRED_PARAMS = [
        keys.ConfigKeys.KEY_TESTBED_NAME, keys.ConfigKeys.IKEY_ANDROID_DEVICE,
        keys.ConfigKeys.IKEY_DATA_FILE_PATH,
        keys.ConfigKeys.IKEY_SYSTRACE_REPORT_PATH,
        keys.ConfigKeys.IKEY_SYSTRACE_REPORT_URL_PREFIX
    ]
    _OPTIONAL_PARAMS = [keys.ConfigKeys.IKEY_SYSTRACE_PROCESS_NAME]

    def __init__(self, user_params, web=None):
        """Initializes the systrace feature.

        Args:
            user_params: A dictionary from parameter name (String) to parameter value.
            web: (optional) WebFeature, object storing web feature util for test run
        """
        self.ParseParameters(self._TOGGLE_PARAM, self._REQUIRED_PARAMS,
                             self._OPTIONAL_PARAMS, user_params)
        self.web = web
        if self.enabled:
            logging.info("Systrace is enabled.")
        else:
            logging.debug("Systrace is disabled.")

    def StartSystrace(self):
        """Initialize systrace controller if enabled.

        Requires the feature to be enabled; no-op otherwise.
        """
        if not self.enabled:
            return

        process_name = getattr(self,
                               keys.ConfigKeys.IKEY_SYSTRACE_PROCESS_NAME, '')
        process_name = str(process_name)
        data_file_path = getattr(self, keys.ConfigKeys.IKEY_DATA_FILE_PATH)

        # TODO: handle device_serial for multi-device
        android_devices = getattr(self, keys.ConfigKeys.IKEY_ANDROID_DEVICE)
        if not isinstance(android_devices, list):
            logging.warn("android device information not available")
            return
        device_spec = android_devices[0]
        serial = device_spec.get(keys.ConfigKeys.IKEY_SERIAL)
        if not serial:
            logging.error("Serial for device at index 0 is not available.")
            self.enabled = False
        serial = str(serial)

        android_vts_path = os.path.normpath(os.path.join(data_file_path, '..'))
        self.controller = systrace_controller.SystraceController(
            android_vts_path, device_serial=serial, process_name=process_name)
        self.controller.Start()

    def ProcessAndUploadSystrace(self, test_name):
        """Stops and outputs the systrace data to configured path.

        Requires the feature to be enabled; no-op otherwise.

        Args:
            test_name: String, the name of the test
        """
        if not self.enabled:
            return

        controller = getattr(self, "controller", None)
        if not controller:
            logging.warn("ProcessSystrace: missing systrace controller")
            return

        controller.Stop()

        if not controller.has_output:
            logging.warn("ProcessSystrace: systrace controller has no output")
            return

        try:
            test_module_name = getattr(self, keys.ConfigKeys.KEY_TESTBED_NAME)
            process = controller.process_name
            time = feature_utils.GetTimestamp()
            report_path = getattr(self,
                                  keys.ConfigKeys.IKEY_SYSTRACE_REPORT_PATH)
            report_destination_file_name = 'systrace_{test}_{process}_{time}.html'.format(
                test=test_name, process=process, time=time)
            report_destination_file_path = os.path.join(
                report_path, report_destination_file_name)
            if controller.SaveLastOutput(report_destination_file_path):
                logging.debug('Systrace output saved to %s',
                              report_destination_file_path)
            else:
                logging.error('Failed to save systrace output.')

            report_url_prefix = getattr(
                self, keys.ConfigKeys.IKEY_SYSTRACE_REPORT_URL_PREFIX)
            report_url_prefix = str(report_url_prefix)
            report_destination_file_url = '%s%s' % (
                report_url_prefix, report_destination_file_name)

            if self.web and self.web.enabled:
                self.web.AddSystraceUrl(report_destination_file_url)
            logging.info('systrace result path %s .',
                         report_destination_file_url)
        except Exception as e:  # TODO(yuexima): more specific exceptions catch
            logging.exception('Failed to add systrace to report message %s', e)
        finally:
            if not controller.ClearLastOutput():
                logging.error('failed to clear last systrace output.')