| # Copyright 2017 Google Inc. |
| # |
| # 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. |
| """This script provides all needed device information to run tests. |
| |
| """ |
| |
| from __future__ import absolute_import |
| import collections |
| import logging |
| import subprocess |
| |
| import step |
| from utilities import util |
| |
| # iOS attributes to be extracted on the connected iOS device. |
| |
| # iPad and iPhone are examples of the device class. |
| _DEVICE_CLASS = 'DeviceClass' |
| # The name of the connected device. |
| _DEVICE_NAME = 'DeviceName' |
| # The Unique Device Identifier also called UDID. |
| _DEVICE_UDID = 'UniqueDeviceID' |
| # The device iOS version. |
| _DEVICE_VERSION = 'ProductVersion' |
| |
| IOS_DEVICE_CLASSES = { |
| 'iPhone': step.PHONE, |
| 'iPad': step.TABLET, |
| } |
| |
| # A dictionary mapping device names to their CPU type. |
| ANDROID_NAME_TO_CPU = { |
| 'hammerhead': 'arm', |
| 'shamu': 'arm', |
| 'bullhead': 'arm_64', |
| 'sailfish': 'arm_64', |
| 'zerofltedv': 'arm_64', |
| } |
| |
| # Android attributes to be extracted via adb from the connected Android device. |
| |
| # A string that represents certain Android device characteristics, such as the |
| # device class or whether the device has an SD card. |
| _ANDROID_BUILD_CHARACTERISTICS = 'ro.build.characteristics' |
| # The Android device version such as '5.1.1'. |
| _ANDROID_DEVICE_VERSION = 'ro.build.version.release' |
| # The Android device name such as Nexus 6. |
| _ANDROID_DEVICE_NAME = 'ro.product.name' |
| # The Android device serial number. |
| _ANDROID_SERIAL_NUMBER = 'ro.serialno' |
| # The Android architecture. |
| _ANDROID_CPU_ARCHITECTURE = 'ro.product.cpu.abi' |
| # The Android API level. |
| _ANDROID_API_LEVEL = 'ro.build.version.sdk' |
| # The Android build type. |
| _ANDROID_BUILD_TYPE = 'ro.build.type' |
| # The Android product brand. |
| _ANDROID_PRODUCT_BRAND = 'ro.product.brand' |
| # The Android build ID. |
| _ANDROID_BUILD_ID = 'ro.build.id' |
| # The Android product build ID. |
| _ANDROID_PRODUCT_BUILD_ID = 'ro.product.build.id' |
| # The Android product board. |
| _ANDROID_PRODUCT_BOARD = 'ro.product.board' |
| # The Android product brand. |
| _ANDROID_PRODUCT_MODEL = 'ro.product.model' |
| # User build type. |
| BUILD_TYPE_USERDEBUG = 'userdebug' |
| |
| # All information needed about the connected device to run tests on. |
| # device_class: phone or tablet on iOS and Android. |
| # id: UDID for iOS i.e. 6a5eb3ef1ee5406f704301b730678416b3f40167 and serial |
| # number for Android i.e. 285300350. |
| # name: device name could be any string. |
| # version: could be 9.3.2 for iOS and 5.1.1 for Android. |
| # build_type: can be userdebug, release etc. Only for Android. |
| DeviceInfo = collections.namedtuple('DeviceInfo', |
| ['device_class', 'name', 'id', 'version', |
| 'build_type']) |
| ANDROID_N_API_VERSION = 24 |
| # Standalone web-view |
| STANDALONE_SYSTEM_WEBVIEW_PACKAGE = 'com.google.android.webview' |
| |
| |
| def GetIOSDeviceInformation(device_id): |
| """Retrieves information from the connected iOS device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A tuple of DeviceInfo. |
| """ |
| device_class = _GetIDeviceInfoValue(_DEVICE_CLASS, device_id) |
| name = _GetIDeviceInfoValue(_DEVICE_NAME, device_id) |
| udid = _GetIDeviceInfoValue(_DEVICE_UDID, device_id) |
| version = _GetIDeviceInfoValue(_DEVICE_VERSION, device_id) |
| return DeviceInfo(IOS_DEVICE_CLASSES[device_class], name, udid, version, '') |
| |
| |
| def GetAndroidCPUInformation(device_id): |
| """Retrieves the CPU info of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string representing the cpu architecture. |
| """ |
| name = _GetADBDeviceInfoValue(_DEVICE_NAME, device_id) |
| cpu_info = _GetADBDeviceInfoValue(_ANDROID_CPU_ARCHITECTURE, device_id) |
| if name in ANDROID_NAME_TO_CPU: |
| return ANDROID_NAME_TO_CPU[name] |
| # Wasn't in dictionary, so try to guess. |
| if 'arm' in cpu_info: |
| return 'arm_64' if '64' in cpu_info else 'arm' |
| if 'x86' in cpu_info: |
| return 'x86_64' if '64' in cpu_info else 'x86' |
| |
| return cpu_info |
| |
| |
| def GetAndroidAPILevel(device_id): |
| """Retrieves the API level of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| An int representing the Android API level. |
| |
| Raises: |
| ValueError: api_level are not all digits. |
| """ |
| api_level = _GetADBDeviceInfoValue(_ANDROID_API_LEVEL, device_id) |
| if not api_level.isdigit(): |
| logging.error('api_level not all digits, assign it to 99') |
| return 99 |
| |
| return int(api_level) |
| |
| |
| def GetAndroidBuildType(device_id): |
| """Retrieves the build type of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string representing the Android build type. |
| """ |
| return _GetADBDeviceInfoValue(_ANDROID_BUILD_TYPE, device_id) |
| |
| |
| def GetAndroidProductBrand(device_id): |
| """Retrieves the product brand of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string representing the Android product brand. |
| """ |
| return _GetADBDeviceInfoValue(_ANDROID_PRODUCT_BRAND, device_id) |
| |
| |
| def GetAndroidProductBoard(device_id): |
| """Retrieves the product board of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string representing the Android product board. |
| """ |
| return _GetADBDeviceInfoValue(_ANDROID_PRODUCT_BOARD, device_id) |
| |
| |
| def GetAndroidProductBuildId(device_id): |
| """Retrieves the product build id of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string representing the Android product build id. |
| """ |
| return _GetADBDeviceInfoValue( |
| _ANDROID_PRODUCT_BUILD_ID, device_id) or _GetADBDeviceInfoValue( |
| _ANDROID_BUILD_ID, device_id) |
| |
| |
| def GetAndroidProductModel(device_id): |
| """Retrieves the product model of the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string representing the Android product model. |
| """ |
| return _GetADBDeviceInfoValue(_ANDROID_PRODUCT_MODEL, device_id) |
| |
| |
| def GetAndroidDeviceInformation(device_id): |
| """Retrieves information from the connected Android device. |
| |
| Args: |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A tuple of DeviceInfo. |
| """ |
| device_info = _GetADBDeviceInfoValue(_ANDROID_BUILD_CHARACTERISTICS, |
| device_id) |
| device_class = step.PHONE |
| if step.TABLET in device_info: |
| device_class = step.TABLET |
| elif step.EMULATOR in device_info: |
| device_class = step.EMULATOR |
| name = _GetADBDeviceInfoValue(_ANDROID_DEVICE_NAME, device_id) |
| serial_number = device_id |
| version = _GetADBDeviceInfoValue(_ANDROID_DEVICE_VERSION, device_id) |
| build_type = GetAndroidBuildType(device_id) |
| return DeviceInfo(device_class, name, serial_number, version, build_type) |
| |
| |
| def SystemWebviewInfo(device_id): |
| """Gets system WebView info. |
| |
| Args: |
| device_id: A device id. |
| |
| Returns: |
| Map with keys: |
| - webview_provider_package |
| - webview_provider_version |
| """ |
| webview_info = {} |
| # For L and M devices 'webview_provider' is 'com.google.android.webview' |
| webview_provider_package = STANDALONE_SYSTEM_WEBVIEW_PACKAGE |
| if GetAndroidAPILevel(device_id) >= ANDROID_N_API_VERSION: |
| webview_provider_package = util.RunADBProcess( |
| ['shell', 'settings', 'get', 'global', 'webview_provider'], |
| device_id).strip() |
| webview_info['webview_provider_package'] = webview_provider_package |
| # Get the 1st(latest) package version |
| webview_info['webview_provider_version'] = util.GetPackageVersion( |
| webview_provider_package, device_id)[0] |
| |
| return webview_info |
| |
| |
| def _GetADBDeviceInfoValue(info_name, device_id): |
| """Retrieves a getprop value via adb. |
| |
| Args: |
| info_name: A string representing the desired Android device information. |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string result from the adb getprop command. |
| """ |
| return util.RunADBProcess(['shell', 'getprop', info_name], device_id).strip() |
| |
| |
| def _GetIDeviceInfoValue(info_name, device_id): |
| """Returns the ideviceinfo attribute's value for iOS devices. |
| |
| Args: |
| info_name: A string representing the name of the deviceinfo requested. |
| device_id: The device ID to getprop from. |
| |
| Returns: |
| A string for the ideviceinfo attribute's value. |
| """ |
| if device_id: |
| return subprocess.check_output( |
| ['ideviceinfo', '-u', device_id, '-k', info_name]).rstrip() |
| return subprocess.check_output(['ideviceinfo', '-k', info_name]).rstrip() |