1#!/usr/bin/env python3 2# 3# Copyright 2016 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of 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, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from acts.controllers.android_device import AndroidDevice 18from acts.controllers.utils_lib import host_utils 19import acts.controllers.native as native 20from subprocess import call 21 22import logging 23import time 24 25#TODO(tturney): Merge this into android device 26 27MOBLY_CONTROLLER_CONFIG_NAME = "NativeAndroidDevice" 28ACTS_CONTROLLER_REFERENCE_NAME = "native_android_devices" 29 30 31def create(configs): 32 logger = logging 33 ads = get_instances(configs) 34 for ad in ads: 35 try: 36 ad.get_droid() 37 except: 38 logger.exception("Failed to start sl4n on %s" % ad.serial) 39 return ads 40 41 42def destroy(ads): 43 pass 44 45 46def get_instances(serials, ): 47 """Create AndroidDevice instances from a list of serials. 48 49 Args: 50 serials: A list of android device serials. 51 logger: A logger to be passed to each instance. 52 53 Returns: 54 A list of AndroidDevice objects. 55 """ 56 results = [] 57 for s in serials: 58 results.append(NativeAndroidDevice(s)) 59 return results 60 61 62class NativeAndroidDeviceError(Exception): 63 pass 64 65 66class NativeAndroidDevice(AndroidDevice): 67 def __del__(self): 68 if self.h_port: 69 self.adb.forward("--remove tcp:%d" % self.h_port) 70 71 def get_droid(self, handle_event=True): 72 """Create an sl4n connection to the device. 73 74 Return the connection handler 'droid'. By default, another connection 75 on the same session is made for EventDispatcher, and the dispatcher is 76 returned to the caller as well. 77 If sl4n server is not started on the device, try to start it. 78 79 Args: 80 handle_event: True if this droid session will need to handle 81 events. 82 83 Returns: 84 droid: Android object useds to communicate with sl4n on the android 85 device. 86 ed: An optional EventDispatcher to organize events for this droid. 87 88 Examples: 89 Don't need event handling: 90 >>> ad = NativeAndroidDevice() 91 >>> droid = ad.get_droid(False) 92 93 Need event handling: 94 >>> ad = NativeAndroidDevice() 95 >>> droid, ed = ad.get_droid() 96 """ 97 if not self.h_port or not host_utils.is_port_available(self.h_port): 98 self.h_port = host_utils.get_available_host_port() 99 self.adb.tcp_forward(self.h_port, self.d_port) 100 pid = self.adb.shell("pidof -s sl4n", ignore_status=True) 101 while (pid): 102 self.adb.shell("kill {}".format(pid)) 103 pid = self.adb.shell("pidof -s sl4n", ignore_status=True) 104 call( 105 ["adb -s " + self.serial + " shell sh -c \"/system/bin/sl4n\" &"], 106 shell=True) 107 try: 108 time.sleep(3) 109 droid = self.start_new_session() 110 except: 111 droid = self.start_new_session() 112 return droid 113 114 def start_new_session(self): 115 """Start a new session in sl4n. 116 117 Also caches the droid in a dict with its uid being the key. 118 119 Returns: 120 An Android object used to communicate with sl4n on the android 121 device. 122 123 Raises: 124 sl4nException: Something is wrong with sl4n and it returned an 125 existing uid to a new session. 126 """ 127 droid = native.NativeAndroid(port=self.h_port) 128 droid.open() 129 if droid.uid in self._droid_sessions: 130 raise bt.SL4NException(("SL4N returned an existing uid for a " 131 "new session. Abort.")) 132 return droid 133 self._droid_sessions[droid.uid] = [droid] 134 return droid 135