1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16 17import logging 18 19import mobly.controllers.android_device_lib.sl4a_client as sl4a_client 20from mobly.controllers.android_device import AndroidDevice 21from mobly.controllers.android_device_lib.adb import AdbError 22from mobly.controllers.android_device_lib.jsonrpc_client_base import AppRestoreConnectionError 23from mobly.controllers.android_device_lib.services.sl4a_service import Sl4aService 24 25 26class FakeFuture: 27 """ 28 A fake Future object to override default mobly behavior 29 """ 30 31 def set_result(self, result): 32 logging.debug("Setting fake result {}".format(result)) 33 34 35def setup_sl4a(device: AndroidDevice, server_port: int, forwarded_port: int): 36 """ 37 A method that setups up SL4A instance on mobly 38 :param device: an AndroidDevice instance 39 :param server_port: Preferred server port used by SL4A on Android device 40 :param forwarded_port: Preferred server port number forwarded from Android to 41 the host PC via adb for SL4A connections 42 :return: None 43 """ 44 sl4a_client._DEVICE_SIDE_PORT = server_port 45 sl4a_client._APP_START_WAIT_TIME = 0.5 46 if device.sl4a is not None: 47 device.log.error("SL4A is not none when registering") 48 device.services.register('sl4a', Sl4aService, start_service=False) 49 # Start the SL4A service and event dispatcher 50 try: 51 device.sl4a.start() 52 except AppRestoreConnectionError as exp: 53 device.log.debug("AppRestoreConnectionError {}".format(exp)) 54 # Pause the dispatcher, but do not stop the service 55 try: 56 device.sl4a.pause() 57 except AdbError as exp: 58 device.log.debug("Failed to pause() {}".format(exp)) 59 sl4a_client._APP_START_WAIT_TIME = 2 * 60 60 # Restart the service with a new host port 61 device.sl4a.restore_app_connection(port=forwarded_port) 62 63 64def teardown_sl4a(device: AndroidDevice): 65 """ 66 A method to tear down SL4A interface on mobly 67 :param device: an AndroidDevice instance that already contains SL4a 68 :return: None 69 """ 70 if device.sl4a.is_alive: 71 # Both self.dut.sl4a and self.dut.sl4a.ed._sl4a are Sl4aClient instances 72 # If we do not set host_port to None here, host_poart will be removed twice from Android 73 # The 2nd removal will trigger and exception that spam the test result 74 # TODO: Resolve this issue in mobly 75 device.log.info("Clearing host_port to prevent mobly crash {}".format(device.sl4a._sl4a_client.host_port)) 76 device.sl4a._sl4a_client.host_port = None 77 # Moreover concurrent.Future.set_result() should never be called from thread that is 78 # waiting for the future. However, mobly calls it and cause InvalidStateError when it 79 # tries to do that after the thread pool has stopped, overriding it here 80 # TODO: Resolve this issue in mobly 81 try: 82 device.sl4a.ed.poller = FakeFuture() 83 except Exception as e: 84 print(e) 85 try: 86 # Guarded by is_alive internally 87 device.sl4a.stop() 88 except AdbError as exp: 89 device.log.warning("Failed top stop()".format(exp)) 90