Ejemplo n.º 1
0
    def _run_server(self, server_name):
        '''运行系统测试桩
        '''
        if not self.adb.is_rooted():
            try:
                self.adb.start_service(
                    '%s/.service.HelperService' % server_name,
                    {'serviceName': server_name})
            except RuntimeError:
                logger.warn('start helper server failed')
                self.adb.start_activity('%s/.activity.StartServiceActivity' %
                                        server_name,
                                        extra={'serviceName': 'HelperService'},
                                        wait=False)
                time.sleep(1)
            return self._server_opend()

        timeout = 10
        time0 = time.time()
        while time.time() - time0 < timeout:
            try:
                ret = self.run_driver_cmd('runServer',
                                          server_name,
                                          root=self.adb.is_rooted(),
                                          retry_count=1,
                                          timeout=10)
                logger.debug('Run server %s' % ret)
                if 'service run success' in ret:
                    # wait for parent process exit
                    time.sleep(0.5)
                elif 'service is running' in ret:
                    pass
                elif 'java.lang.UnsatisfiedLinkError' in ret:
                    raise RuntimeError('启动系统测试桩进程失败:\n%s' % ret)
            except TimeoutError as e:
                logger.warn('Run server timeout: %s' % e)

            if self._server_opend(): return True
            time.sleep(1)
        return False
Ejemplo n.º 2
0
    def lock_keyguard(self):
        '''锁屏
        '''
        if self.is_keyguard_locked(): return True  # 已经是锁屏状态
        if self.adb.is_rooted():
            self.set_screen_lock_enable(True)
        if self.adb.get_sdk_version() >= 16:
            # 发送电源键
            self.send_key(KeyCode.KEYCODE_POWER)
            return True

        self._last_activity_before_lock = self._get_current_activity(
            True)  # 保存锁屏前的Activity
        logger.debug('锁屏前Activity为:%r' % self._last_activity_before_lock)
        ret = self._lock_keyguard()
        if not ret:
            logger.warn('lock keyguard failed')
            self.wake_screen(False)
            time.sleep(1)
            self.wake_screen(True)
            return self.is_keyguard_locked()
        return True
Ejemplo n.º 3
0
 def send_command(self, cmd_type, **kwds):
     '''发送命令
     '''
     curr_thread_id = threading.current_thread().ident
     self._wait_for_event(curr_thread_id, self._max_block_time)
     
     if cmd_type != EnumCommand.CmdHello: self._safe_init_driver()  # 确保测试桩连接正常
     
     result = self._client.send_command(cmd_type, **kwds)
     if result == None:
         pid = self._adb.get_pid(self._process['name'])
         if pid > 0 and pid != self._process['id']:
             # 新进程,需要重新注入
             logger.info('process %s id changed: %d %d' % (self._process['name'], self._process['id'], pid))
             self._is_init = False  # 需要重新初始化
             self._process['id'] = pid
             return self.send_command(cmd_type, **kwds)
         elif pid == 0:
             raise ProcessExitError('被测进程已退出,确认是否发生Crash')
         elif cmd_type != EnumCommand.CmdHello:
             # hello包不重试
             logger.debug('socket error, try to reconnect')
             for _ in range(3):
                 # 为防止由于设备短暂失联导致的连接断开,这里调一次adb forward
                 self._client = self._create_client()
                 result = self._client.send_command(cmd_type, **kwds)
                 if result != None: return result
             raise SocketError('Connect Failed')
         else:
             raise SocketError('Connect Failed')
     if 'Error' in result:
         if result['Error'] == u'控件已失效':
             raise ControlExpiredError(result['Error'])
         elif result['Error'] == u'控件类型错误':
             control_type = self.get_control_type(kwds['Control'])
             raise TypeError('%s,当前控件类型为:%s' % (result['Error'], control_type))
         else:
             raise AndroidSpyError(result['Error'])
     return result
Ejemplo n.º 4
0
 def add_monitor_task(self, task, last_time=0):
     '''添加监控任务
     '''
     if last_time > 0: last_time += time.time()
     self._monitor_task_list.append((task, last_time))
     logger.debug('add task: %s' % task.__name__)
Ejemplo n.º 5
0
    def _init_driver(self):
        """初始化测试桩
        """
        self._client = self._create_client()
        if self._client != None:
            # 字段赋值
            self._process["name"] = self._process_name
            self._process["id"] = 0  # process id may change
            if self.hello() != None:
                self._process["id"] = self._adb.get_pid(self._process_name)
                return

        timeout = 20
        time0 = time.time()
        proc_exist = False
        while time.time() - time0 < timeout:
            if not proc_exist:
                pid = self._adb.get_pid(self._process_name)
                if pid > 0:
                    proc_exist = True
                    self._process["name"] = self._process_name
                    self._process["id"] = pid
                    break

            time.sleep(1)

        if not proc_exist:
            raise RuntimeError("进程:%s 在%d秒内没有出现" %
                               (self._process_name, timeout))

        inject_file = "inject"
        if self._adb.is_app_process64(
                pid if self._adb.is_rooted() else self._process_name):
            # 64 bit process
            inject_file += "64"
        timeout = 30

        try:
            if self._adb.is_art():
                # Android 5.0上发现注入容易导致进程退出
                self._wait_for_cpu_low(20, 10)

            time0 = time.time()
            cmdline = "%s/%s %s" % (
                self._get_driver_root_path(),
                inject_file,
                self._process_name,
            )
            while time.time() - time0 < timeout:
                if self._adb.is_rooted():
                    ret = self._adb.run_shell_cmd(cmdline,
                                                  True,
                                                  timeout=120,
                                                  retry_count=1)
                else:
                    ret = self._adb.run_as(self._process_name,
                                           cmdline,
                                           timeout=120,
                                           retry_count=1)
                logger.debug("inject result: %s" % ret)
                if "not found" in ret:
                    raise QT4ADriverNotInstalled(
                        "QT4A driver damaged, please reinstall QT4A driver")
                if "Inject Success" in ret:
                    break
                elif "Operation not permitted" in ret:
                    # 可能是进程处于Trace状态
                    pid = self._adb.get_pid(self._process_name)
                    status = self._adb.get_process_status(pid)
                    tracer_pid = int(status["TracerPid"])
                    if tracer_pid > 0:
                        if int(status["PPid"]) == tracer_pid:
                            # 使用TRACEME方式防注入
                            raise Exception("应用使用了防注入逻辑,注入失败")
                        logger.warn("TracerPid is %d" % tracer_pid)
                        self._adb.kill_process(tracer_pid)
                elif "Function not implemented" in ret:
                    raise Exception(
                        "Please install repacked app on this device")
                time.sleep(1)

        except RuntimeError as e:
            logger.exception("%s\n%s" % (e, self._adb.run_shell_cmd("ps")))
            if self._adb.is_rooted():
                logger.info(self._adb.dump_stack(self._process_name))
            raise e
        timeout = 10
        time0 = time.time()
        while time.time() - time0 < timeout:
            if self._client == None:
                self._client = self._create_client()
            if self._client != None and self.hello() != None:
                return
            time.sleep(0.1)
        raise RuntimeError("连接测试桩超时")
Ejemplo n.º 6
0
    def _init_driver(self):
        '''初始化测试桩
        '''
        self._client = self._create_client()
        if self._client != None:
            # 字段赋值
            self._process['name'] = self._process_name
            self._process['id'] = 0  # process id may change
            if self.hello() != None:
                self._process['id'] = self._adb.get_pid(self._process_name)
                return

        timeout = 20
        time0 = time.time()
        proc_exist = False
        while time.time() - time0 < timeout:
            if not proc_exist:
                pid = self._adb.get_pid(self._process_name)
                if pid > 0:
                    proc_exist = True
                    self._process['name'] = self._process_name
                    self._process['id'] = pid
                    break

            time.sleep(1)

        if not proc_exist:
            raise RuntimeError('进程:%s 在%d秒内没有出现' %
                               (self._process_name, timeout))

        inject_file = 'inject'
        if self._adb.is_app_process64(
                pid if self._adb.is_rooted() else self._process_name):
            # 64 bit process
            inject_file += '64'
        timeout = 30

        try:
            if self._adb.is_art():
                # Android 5.0上发现注入容易导致进程退出
                self._wait_for_cpu_low(20, 10)

            time0 = time.time()
            cmdline = '%s/%s %s' % (self._get_driver_root_path(), inject_file,
                                    self._process_name)
            while time.time() - time0 < timeout:
                if self._adb.is_rooted():
                    ret = self._adb.run_shell_cmd(cmdline,
                                                  True,
                                                  timeout=120,
                                                  retry_count=1)
                else:
                    ret = self._adb.run_as(self._process_name,
                                           cmdline,
                                           timeout=120,
                                           retry_count=1)
                logger.debug('inject result: %s' % ret)
                if 'not found' in ret:
                    raise QT4ADriverNotInstalled(
                        'QT4A driver damaged, please reinstall QT4A driver')
                if 'Inject Success' in ret:
                    break
                elif 'Operation not permitted' in ret:
                    # 可能是进程处于Trace状态
                    pid = self._adb.get_pid(self._process_name)
                    status = self._adb.get_process_status(pid)
                    tracer_pid = int(status['TracerPid'])
                    if tracer_pid > 0:
                        if int(status['PPid']) == tracer_pid:
                            # 使用TRACEME方式防注入
                            raise Exception('应用使用了防注入逻辑,注入失败')
                        logger.warn('TracerPid is %d' % tracer_pid)
                        self._adb.kill_process(tracer_pid)
                time.sleep(1)

        except RuntimeError as e:
            logger.exception('%s\n%s' % (e, self._adb.run_shell_cmd('ps')))
            if self._adb.is_rooted():
                logger.info(self._adb.dump_stack(self._process_name))
            raise e
        timeout = 10
        time0 = time.time()
        while time.time() - time0 < timeout:
            if self._client == None:
                self._client = self._create_client()
            if self._client != None and self.hello() != None:
                return
            time.sleep(0.1)
        raise RuntimeError('连接测试桩超时')
Ejemplo n.º 7
0
    def run_server(self, server_name=''):
        '''运行测试桩进程,创建服务端
        '''
        if server_name == '': server_name = self.service_name
        from qt4a.androiddriver.androiddriver import AndroidDriver
        port = AndroidDriver.get_process_name_hash(server_name,
                                                   self.get_device_id())
        logger.info('[DeviceDriver] port is %d' % port)
        addr = '127.0.0.1'
        if not self._is_local_device: addr = self.adb.host_name
        if self._client: self._client.close()
        self._client = None

        time0 = time.time()
        timeout = 20
        kill_server = False

        server_type = 'localabstract'
        if self.adb.is_rooted() and self.adb.is_selinux_opened():
            # 创建TCP服务端
            server_name = str(self.service_port)
            server_type = 'tcp'

        while time.time() - time0 < timeout:
            if not kill_server and time.time() - time0 >= timeout // 2:
                # server进程存在问题,强杀
                self._kill_server()
                if self._client: self._client.close()
                self._client = None
                kill_server = True
            ret = self._run_server(server_name)
            logger.debug('[DeviceDriver] Server %s process created: %s' %
                         (server_name, ret))

            while port < 65536:
                self._client = self._create_client(addr, port)
                port_is_opened = AndroidSpyClient.server_opened(port)
                if not port_is_opened:
                    new_port = self.adb.forward(port, server_name, server_type)
                    if new_port != port:
                        self._client = self._create_client(addr, new_port)
                        logger.info('[AndroidDevice] new port=%d' % new_port)
                        port = new_port

                try:
                    hello_rsp = self.hello()
                    if hello_rsp == None:
                        if port_is_opened:
                            # 需要释放端口
                            ret = self.adb.remove_forward(port)
                            logger.info(
                                '[AndroidDevice] remove %d forward: %s' %
                                (port, ret))
                        break
                except RuntimeError:
                    port += 1
                    logger.info('[AndroidDevice] new port is %d' % port)
                    continue

                return self._client

        raise RuntimeError('连接系统测试桩超时')