webkitpy: Refactor port code for devices
[WebKit-https.git] / Tools / Scripts / webkitpy / port / ios_device.py
1 # Copyright (C) 2014-2018 Apple Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1.  Redistributions of source code must retain the above copyright
7 #     notice, this list of conditions and the following disclaimer.
8 # 2.  Redistributions in binary form must reproduce the above copyright
9 #     notice, this list of conditions and the following disclaimer in the
10 #     documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23 import logging
24
25 from webkitpy.common.memoized import memoized
26 from webkitpy.common.system.crashlogs import CrashLogs
27 from webkitpy.common.version import Version
28 from webkitpy.port.config import apple_additions
29 from webkitpy.port.ios import IOSPort
30
31 _log = logging.getLogger(__name__)
32
33
34 class IOSDevicePort(IOSPort):
35     port_name = 'ios-device'
36
37     ARCHITECTURES = ['armv7', 'armv7s', 'arm64']
38     DEFAULT_ARCHITECTURE = 'arm64'
39     VERSION_FALLBACK_ORDER = ['ios-7', 'ios-8', 'ios-9', 'ios-10']
40
41     DEVICE_MANAGER = apple_additions().device_manager() if apple_additions() else None
42
43     SDK = apple_additions().get_sdk('iphoneos') if apple_additions() else 'iphoneos'
44     NO_ON_DEVICE_TESTING = 'On-device testing is not supported on this machine'
45
46     @memoized
47     def default_child_processes(self):
48         if apple_additions():
49             return apple_additions().ios_device_default_child_processes(self)
50         return 1
51
52     def _driver_class(self):
53         if apple_additions():
54             return apple_additions().ios_device_driver()
55         return super(IOSDevicePort, self)._driver_class()
56
57     @classmethod
58     def determine_full_port_name(cls, host, options, port_name):
59         if port_name == cls.port_name:
60             iphoneos_sdk_version = host.platform.xcode_sdk_version(cls.SDK)
61             if not iphoneos_sdk_version:
62                 raise Exception("Please install the iOS SDK.")
63             port_name = port_name + '-' + str(iphoneos_sdk_version.major)
64         return port_name
65
66     def path_to_crash_logs(self):
67         if not apple_additions():
68             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
69         return apple_additions().ios_crash_log_path()
70
71     def _look_for_all_crash_logs_in_log_dir(self, newer_than):
72         log_list = {}
73         for device in self.devices():
74             crash_log = CrashLogs(device, self.path_to_crash_logs(), crash_logs_to_skip=self._crash_logs_to_skip_for_host.get(device, []))
75             log_list.update(crash_log.find_all_logs(include_errors=True, newer_than=newer_than))
76         return log_list
77
78     def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=None, sleep_fn=None, wait_for_log=True, target_host=None):
79         if target_host:
80             return super(IOSDevicePort, self)._get_crash_log(name, pid, stdout, stderr, newer_than, time_fn=time_fn, sleep_fn=sleep_fn, wait_for_log=wait_for_log, target_host=target_host)
81
82         # We need to search every device since one was not specified.
83         for device in self.devices():
84             stderr_out, crashlog = super(IOSDevicePort, self)._get_crash_log(name, pid, stdout, stderr, newer_than, time_fn=time_fn, sleep_fn=sleep_fn, wait_for_log=False, target_host=device)
85             if crashlog:
86                 return (stderr, crashlog)
87         return (stderr, None)
88
89     @memoized
90     def ios_version(self):
91         if self.get_option('version'):
92             return Version.from_string(self.get_option('version'))
93
94         if not apple_additions():
95             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
96
97         if not self.devices():
98             raise RuntimeError('No devices are available')
99         version = None
100         for device in self.devices():
101             if not version:
102                 version = device.platform.os_version
103             else:
104                 if device.platform.os_version != version:
105                     raise RuntimeError('Multiple connected devices have different iOS versions')
106         return version
107
108     # FIXME: These need device implementations <rdar://problem/30497991>.
109     def check_for_leaks(self, process_name, process_pid):
110         pass
111
112     def operating_system(self):
113         return 'ios-device'
114
115     def _create_devices(self, device_class):
116         if not apple_additions():
117             raise RuntimeError(self.NO_ON_DEVICE_TESTING)
118         if not self.devices():
119             raise RuntimeError('No devices are available for testing')
120
121         if self.default_child_processes() < self.child_processes():
122             raise RuntimeError('Not enought connected devices for {} processes'.format(self.child_processes()))
123
124     def clean_up_test_run(self):
125         super(IOSDevicePort, self).clean_up_test_run()
126         apple_additions().ios_device_clean_up_test_run(self, self._path_to_driver(), self._build_path())