def stop_device_server(self, device_name: str): """ 停止设备的minitouch服务(不清除端口) @param {str} device_name - 设备名 """ # 为后台线程送停止的参数 self.devices[device_name]['stop_var'][0] = True # 获取minitouch进程id _pid = None _connection: MiniTouchConnection = self.devices[device_name].pop( 'connection', None) if _connection is not None: _pid = _connection.pid # 停止socket连接 _connection.disconnect() else: # 通过adb shell查找进程id try: _cmd_info = AdbTools.adb_run( self.adb_name, device_name, 'shell ps | %s %s' % ('findstr' if sys.platform == 'win32' else 'grep', self.devices[device_name]['minitouch_file']), shell_encoding=self.shell_encoding) # shell 31976 31974 2169772 6832 __skb_wait_for_more_packets 0 S minicap _pid = _cmd_info[0][_cmd_info[0].find(' '):].strip().split( ' ')[0] except: self.logger.warning( 'get device[%s] minitouch pid by adb error: %s' % (device_name, traceback.format_exc())) # 结束进程 if _pid is not None: AdbTools.adb_run(self.adb_name, device_name, 'shell kill %s' % _pid, shell_encoding=self.shell_encoding, ignore_error=True) # 等待线程结束 while self.devices[device_name]['server_thread'] is not None: time.sleep(0.1)
def get_screen_wm(cls, device_name: str, adb_name: str = 'adb', shell_encoding: str = None) -> tuple: """ 获取设备屏幕大小 @param {str} device_name - 设备名 @param {str} adb_name='adb' - adb命令名 @param {str} shell_encoding=None - shell的编码 @returns {tuple} - 设备屏幕大小,width, height """ _cmd_info = AdbTools.adb_run( adb_name, device_name, 'shell wm size', shell_encoding=shell_encoding ) _size_str = _cmd_info[0].split(':')[1].strip().split('x') return int(_size_str[0]), int(_size_str[1])
def _get_connected_devices(self) -> dict: """ 获取已经连接上且未展示的设备清单字典 @returns {dict} - 设备清单字典 { '设备名称': { ... }, ... } """ _adb = self.config_services.para['adb'] _devices = dict() _full_device_list = list() _cmd_info = AdbTools.adb_run(_adb, '', 'devices -l') for _str in _cmd_info: if not _str.startswith('List of'): # 找到设备连接号 _device_name = (_str[0:_str.find(' ')]).strip() if _device_name == '': # 非法数据或已连接,不处理 continue # 登记完整清单 _full_device_list.append(_device_name) if _device_name in self.devices.keys( ) and self.devices[_device_name]['status'] != 'error': # 设备已存在,不处理 continue # 获取设备信息 _devices[_device_name] = self._get_device_info(_device_name) # 检查是否有设备掉线 _current_devices = list(self.devices.keys()) for _device_name in _current_devices: if _device_name not in _full_device_list: # 设备已掉线 self.remove_unconnect_device(_device_name) # 返回结果字典 return _devices
def init_device_server(cls, device_name: str, shared_path: str, adb_name: str = 'adb', shell_encoding: str = None): """ 初始化设备上的服务文件 @param {str} device_name - 设备名 @param {str} shared_path - 预编译的minitouch文件所在路径,该路径下文件应按该目录结构存放: shared_path/stf_libs/{abi}/minitouch 其中{abi}为设备的cpu架构, 例如 arm64-v8a @param {str} adb_name='adb' - adb命令名 @param {str} shell_encoding=None - shell的编码 """ # 检查sdk版本和cpu架构 _cpu = AdbTools.adb_run(adb_name, device_name, 'shell getprop ro.product.cpu.abi', shell_encoding=shell_encoding)[0] _sdk = AdbTools.adb_run(adb_name, device_name, 'shell getprop ro.build.version.sdk', shell_encoding=shell_encoding)[0] # sdk小于16的版本要用nopie版本 _minitouch_file = 'minitouch' if int(_sdk) >= 16 else 'minitouch-nopie' if not AdbTools.adb_file_exists(adb_name, device_name, '/data/local/tmp/%s' % _minitouch_file, shell_encoding=shell_encoding): # 推送相应文件到设备 AdbTools.adb_run( adb_name, device_name, 'push %s /data/local/tmp' % os.path.join(shared_path, 'stf_libs', _cpu, _minitouch_file), shell_encoding=shell_encoding) # 授权 AdbTools.adb_run(adb_name, device_name, 'shell chmod 777 /data/local/tmp/%s' % _minitouch_file, shell_encoding=shell_encoding)
def start_device_server(self, device_name: str, show_size: tuple = None, canvas_size: tuple = None, orientation: int = 0, quality: int = 80) -> int: """ 启动设备的minicap服务 注:必须要先通过 init_device_server 对设备进行初始化处理 @param {str} device_name - 设备号 @param {tuple} show_size=None - 显示大小,(宽, 高),默认原生大小 @param {tuple} canvas_size=None - 画布大小,(宽, 高),默认原生大小 @param {int} orientation=0 - 手机旋转角度,支持 0 | 90 | 180 | 270 @param {int} quality=80 - 视频质量,可设置0-100,降低视频质量可提高性能 @param {dict} - 返回设备信息 """ # 获取该设备使用的端口 if device_name in self.devices.keys(): # 未回收端口,继续复用 _port = self.devices[device_name]['port'] else: # 新申请端口 _port = self.minicap_ports.pop(0) # 处理显示大小 _real_size = self.get_screen_wm( device_name, adb_name=self.adb_name, shell_encoding=self.shell_encoding ) _show_size = show_size if show_size is None: _show_size = copy.deepcopy(_real_size) else: _show_size = self.get_show_size( _real_size, _show_size ) # 处理画布大小 _canvas_size = canvas_size if canvas_size is None: _canvas_size = copy.deepcopy(_real_size) else: _canvas_size = self.get_show_size( _real_size, _canvas_size ) # 添加到设备清单 self.devices[device_name] = { 'port': _port, 'stop_var': [False, ], # 控制停止的参数 'real_size': _real_size, 'orientation': orientation, 'quality': quality, 'show_size': _show_size, 'canvas_size': _canvas_size, } # 执行处理 try: # 获取设备minicap版本 _sdk = AdbTools.adb_run( self.adb_name, device_name, 'shell getprop ro.build.version.sdk', shell_encoding=self.shell_encoding )[0] self.devices[device_name]['minicap_file'] = 'minicap' if int( _sdk) >= 16 else 'minicap-nopie' # 映射端口,映射前需要回收端口 AdbTools.adb_run( self.adb_name, device_name, 'forward --remove tcp:%d' % _port, shell_encoding=self.shell_encoding, ignore_error=True ) AdbTools.adb_run( self.adb_name, device_name, 'forward tcp:%d localabstract:minicap' % _port, shell_encoding=self.shell_encoding ) # 启动服务 self._start_device_server(device_name) # 等待设备启动并检查状态 time.sleep(self.start_wait_time) if self.devices[device_name].get('server_thread', None) is None: raise RuntimeError('server thread exited!') except: # 出现异常代表失败,将端口放回列表 self.stop_device_server(device_name) # 先尝试关闭服务 self.devices.pop(device_name, None) self.minicap_ports.append(_port) self.logger.error( 'start devices[%s] minicap server error: %s' % ( device_name, traceback.format_exc() ) ) raise return self.devices[device_name]
def start_device_server(self, device_name: str) -> int: """ 启动设备的minitouch服务 注:必须要先通过 init_device_server 对设备进行初始化处理 @param {str} device_name - 设备号 @param {int} - minitouch映射的监听端口 """ # 获取该设备使用的端口 if device_name in self.devices.keys(): # 未回收端口,继续复用 _port = self.devices[device_name]['port'] else: # 新申请端口 _port = self.minitouch_ports.pop(0) # 添加到设备清单 self.devices[device_name] = { 'port': _port, 'stop_var': [ False, ], # 控制停止的参数 } # 执行处理 try: # 获取设备minitouch版本 _sdk = AdbTools.adb_run(self.adb_name, device_name, 'shell getprop ro.build.version.sdk', shell_encoding=self.shell_encoding)[0] self.devices[device_name]['minitouch_file'] = 'minitouch' if int( _sdk) >= 16 else 'minitouch-nopie' # 映射端口,映射前需要回收端口 AdbTools.adb_run(self.adb_name, device_name, 'forward --remove tcp:%d' % _port, shell_encoding=self.shell_encoding, ignore_error=True) AdbTools.adb_run(self.adb_name, device_name, 'forward tcp:%d localabstract:minitouch' % _port, shell_encoding=self.shell_encoding) # 启动服务 self._start_device_server(device_name) # 等待设备启动并检查状态 time.sleep(self.start_wait_time) if self.devices[device_name].get('server_thread', None) is None: raise RuntimeError('server thread exited!') # 连接设备 self.devices[device_name]['connection'] = MiniTouchConnection( '127.0.0.1', self.devices[device_name]['port'], buffer_size=self.buffer_size, encoding=self.encoding, logger=self.logger) except: # 出现异常代表失败,将端口放回列表 self.stop_device_server(device_name) # 先尝试关闭服务 self.devices.pop(device_name, None) self.minitouch_ports.append(_port) self.logger.error('start devices[%s] minitouch server error: %s' % (device_name, traceback.format_exc())) raise return _port
def _get_device_info(self, device_name: str) -> dict: """ 获取设备信息 @param {str} device_name - 设备名称(注意需已连接adb) @returns {dict} - 设备信息字典, 注意如果没有连接上也能正常返回,只是相应key值不存在 { 'device_name': '', # 设备名称 'platform_name': 'Android', # 手机平台名 'platform_version': '', # 手机平台版本 'wlan_ip': '', # 手机连接的 wifi ip 'brand': '', # 手机的品牌 'model': '' # 手机的产品名称 } """ _device_info = {'device_name': device_name, 'platform_name': 'Android'} _adb = self.config_services.para['adb'] _shell_encoding = self.config_services.para['shell_encoding'] # 获取版本 _device_info['platform_version'] = '' try: _cmd_info = AdbTools.adb_run( _adb, device_name, 'shell getprop ro.build.version.release', shell_encoding=_shell_encoding) _device_info['platform_version'] = _cmd_info[0] except: pass # 获取手机厂商品牌 _device_info['brand'] = '' try: _cmd_info = AdbTools.adb_run(_adb, device_name, 'shell getprop ro.product.brand', shell_encoding=_shell_encoding) _device_info['brand'] = _cmd_info[0] except: pass # 获取手机产品名称 _device_info['model'] = '' try: _cmd_info = AdbTools.adb_run(_adb, device_name, 'shell getprop ro.product.model', shell_encoding=_shell_encoding) _device_info['model'] = _cmd_info[0] except: pass # 获取WIFI地址 _device_info['wlan_ip'] = '' try: _cmd_info = AdbTools.adb_run(_adb, device_name, 'shell ifconfig wlan0', shell_encoding=_shell_encoding) for _line in _cmd_info: _line = _line.strip() if _line.startswith('inet addr:'): _temp_len = len('inet addr:') _device_info['wlan_ip'] = _line[_temp_len:_line. find(' ', _temp_len)] break except: pass return _device_info