Ejemplo n.º 1
0
    def _setup_stream_server(self):
        """
        Setup stream server

        Returns:
            adb shell process, non-blocking stream reader and local port

        """
        localport, deviceport = self.adb.setup_forward(
            "localabstract:javacap_{}".format)
        deviceport = deviceport[len("localabstract:"):]
        # setup agent proc
        apkpath = self.adb.path_app(self.APP_PKG)
        cmds = [
            "CLASSPATH=" + apkpath, 'exec', 'app_process', '/system/bin',
            self.SCREENCAP_SERVICE, "--scale", "100", "--socket",
            "%s" % deviceport, "-lazy", "2>&1"
        ]
        proc = self.adb.start_shell(cmds)
        # check proc output
        nbsp = NonBlockingStreamReader(proc.stdout,
                                       print_output=True,
                                       name="javacap_sever")
        while True:
            line = nbsp.readline(timeout=5.0)
            if line is None:
                raise RuntimeError("javacap server setup timeout")
            if b"Capture server listening on" in line:
                break
            if b"Address already in use" in line:
                raise RuntimeError("javacap server setup error: %s" % line)
        return proc, nbsp, localport
Ejemplo n.º 2
0
    def setup_server(self):
        """
        Setup maxtouch server and adb forward

        Returns:
            server process

        """
        if self.server_proc:
            self.server_proc.kill()
            self.server_proc = None

        self.localport, deviceport = self.adb.setup_forward(
            "localabstract:maxpresent_{}".format)
        deviceport = deviceport[len("localabstract:"):]
        p = self.adb.start_shell(
            "app_process -Djava.class.path={0} /data/local/tmp com.netease.maxpresent.MaxPresent socket {1}"
            .format(self.path_in_android, deviceport))

        nbsp = NonBlockingStreamReader(p.stdout,
                                       name="airtouch_server",
                                       auto_kill=True)
        line = nbsp.readline(timeout=5.0)
        if line is None:
            kill_proc(p)
            raise RuntimeError("airtouch setup timeout")

        if p.poll() is not None:
            # server setup error, may be already setup by others
            # subprocess exit immediately
            kill_proc(p)
            raise RuntimeError("airtouch server quit immediately")
        self.server_proc = p
        return p
Ejemplo n.º 3
0
    def logcat(self, grep_str="", extra_args="", read_timeout=10):
        """
        Perform `adb shell logcat` command and search for given patterns

        Args:
            grep_str: pattern to filter from the logcat output
            extra_args: additional logcat arguments
            read_timeout: time interval to read the logcat, default is 10

        Yields:
            logcat lines containing filtered patterns

        Returns:
            None

        """
        cmds = "shell logcat"
        if extra_args:
            cmds += " " + extra_args
        if grep_str:
            cmds += " | grep " + grep_str
        logcat_proc = self.start_cmd(cmds)
        nbsp = NonBlockingStreamReader(logcat_proc.stdout, print_output=False)
        while True:
            line = nbsp.readline(read_timeout)
            if line is None:
                break
            else:
                yield line
        nbsp.kill()
        logcat_proc.kill()
        return
Ejemplo n.º 4
0
    def _setup_stream_server(self, lazy=False):
        """
        Setup minicap process on device

        Args:
            lazy: parameter `-l` is used when True

        Returns:
            adb shell process, non-blocking stream reader and local port

        """
        localport, deviceport = self.adb.setup_forward("localabstract:minicap_{}".format)
        deviceport = deviceport[len("localabstract:"):]
        other_opt = "-l" if lazy else ""
        params, display_info = self._get_params()
        proc = self.adb.start_shell(
            "%s -n '%s' -P %dx%d@%dx%d/%d %s 2>&1" %
            tuple([self.CMD, deviceport] + list(params) + [other_opt]),
        )
        nbsp = NonBlockingStreamReader(proc.stdout, print_output=True, name="minicap_server")
        while True:
            line = nbsp.readline(timeout=5.0)
            if line is None:
                raise RuntimeError("minicap server setup timeout")
            if b"Server start" in line:
                break

        if proc.poll() is not None:
            # minicap server setup error, may be already setup by others
            # subprocess exit immediately
            raise RuntimeError("minicap server quit immediately")

        reg_cleanup(proc.kill)
        self._stream_rotation = int(display_info["rotation"])
        return proc, nbsp, localport
Ejemplo n.º 5
0
    def setup_server(self):
        """
        Setup minitouch server and adb forward

        Returns:
            server process

        """
        if self.server_proc:
            self.server_proc.kill()
            self.server_proc = None

        self.localport, deviceport = self.adb.setup_forward(
            "localabstract:minitouch_{}".format)
        deviceport = deviceport[len("localabstract:"):]
        if self.input_event:
            p = self.adb.start_shell(
                "/data/local/tmp/minitouch -n '{0}' -d '{1}' 2>&1".format(
                    deviceport, self.input_event))
        else:
            p = self.adb.start_shell(
                "/data/local/tmp/minitouch -n '{0}' 2>&1".format(deviceport))
        nbsp = NonBlockingStreamReader(p.stdout,
                                       name="minitouch_server",
                                       auto_kill=True)
        while True:
            line = nbsp.readline(timeout=3.0)
            if line is None:
                kill_proc(p)
                self.adb.close_proc_pipe(p)
                raise RuntimeError("minitouch setup timeout")

            line = line.decode(get_std_encoding(sys.stdout))

            # 识别出setup成功的log,并匹配出max_x, max_y
            m = re.search(
                "Type \w touch device .+ \((\d+)x(\d+) with \d+ contacts\) detected on .+ \(.+\)",
                line)
            if m:
                self.max_x, self.max_y = int(m.group(1)), int(m.group(2))
                break
            else:
                self.max_x = 32768
                self.max_y = 32768
        # nbsp.kill() # 保留,不杀了,后面还会继续读取并pirnt
        if p.poll() is not None:
            # server setup error, may be already setup by others
            # subprocess exit immediately
            kill_proc(p)
            raise RuntimeError("minitouch server quit immediately")
        self.server_proc = p
        reg_cleanup(kill_proc, self.server_proc)
        return p
Ejemplo n.º 6
0
 def setup(self):
     cmd = [self.executable, "--udid", self.udid, "--port", str(self.port), "--resolution", self.resolution]
     proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
     nbsp = NonBlockingStreamReader(proc.stdout, print_output=True, name="minicap_sever")
     while True:
         line = nbsp.readline(timeout=10.0)
         if line is None:
             raise RuntimeError("minicap setup error")
         if b"== Banner ==" in line:
             break
     if proc.poll() is not None:
         logging.warn("Minicap server already started, use old one")
     self.server_proc = proc
Ejemplo n.º 7
0
    def start_recording(self, max_time=1800, bit_rate=None):
        """
        Start screen recording

        Args:
            max_time: maximum screen recording time, default is 1800
            bit_rate: bit rate value, 450000-8000000, default is None(6000000)

        Raises:
            RuntimeError: if any error occurs while setup the recording

        Returns:
            None if recording did not start, otherwise True

        """
        if getattr(self, "recording_proc", None):
            raise AirtestError("recording_proc has already started")
        pkg_path = self.adb.path_app(YOSEMITE_PACKAGE)
        max_time_param = "-Dduration=%d" % max_time if max_time else ""
        # The higher the bitrate, the clearer the video, the default value is 6000000
        bit_rate_param = "-Dbitrate=%d" % bit_rate if bit_rate else ""
        # The video size is square, compatible with horizontal and vertical screens
        p = self.adb.start_shell(
            'CLASSPATH=%s exec app_process %s %s /system/bin %s.Recorder --start-record'
            % (pkg_path, max_time_param, bit_rate_param, YOSEMITE_PACKAGE))
        nbsp = NonBlockingStreamReader(p.stdout,
                                       name="start_recording_" + str(id(self)))
        # 进程p必须要保留到stop_recording执行时、或是退出前才进行清理,否则会导致录屏进程提前终止
        reg_cleanup(kill_proc, p)
        while True:
            line = nbsp.readline(timeout=5)
            if line is None:
                nbsp.kill()
                kill_proc(p)
                raise RuntimeError("start recording error")
            if six.PY3:
                line = line.decode("utf-8")
            # 如果上次录屏被强制中断,可能会导致无法开始下一次录屏,额外发一个停止录屏指令
            if re.search("Record has already started", line):
                self.stop_recording(is_interrupted=True)
                continue
            m = re.match(
                "start result: Record start success! File path:(.*\.mp4)",
                line.strip())
            if m:
                output = m.group(1)
                self.recording_proc = p
                self.recording_file = output
                nbsp.kill()
                return True
Ejemplo n.º 8
0
    def start_recording(self, max_time=1800, bit_rate=None, vertical=None):
        """
        Start screen recording

        Args:
            max_time: maximum rate value, default is 1800
            bit_rate: bit rate value, default is None
            vertical: vertical parameters, default is None

        Raises:
            RuntimeError: if any error occurs while setup the recording

        Returns:
            None if recording did not start, otherwise True

        """
        if getattr(self, "recording_proc", None):
            raise AirtestError("recording_proc has already started")
        pkg_path = self.adb.path_app(YOSEMITE_PACKAGE)
        max_time_param = "-Dduration=%d" % max_time if max_time else ""
        bit_rate_param = "-Dbitrate=%d" % bit_rate if bit_rate else ""
        if vertical is None:
            vertical_param = ""
        else:
            vertical_param = "-Dvertical=true" if vertical else "-Dvertical=false"
        p = self.adb.start_shell(
            'CLASSPATH=%s exec app_process %s %s %s /system/bin %s.Recorder --start-record'
            % (pkg_path, max_time_param, bit_rate_param, vertical_param,
               YOSEMITE_PACKAGE))
        nbsp = NonBlockingStreamReader(p.stdout)
        while True:
            line = nbsp.readline(timeout=5).strip()
            if six.PY3:
                line = line.decode("utf-8")
            if line is None:
                raise RuntimeError("recording setup error")
            m = re.match(
                "start result: Record start success! File path:(.*\.mp4)",
                line.strip())
            if m:
                output = m.group(1)
                self.recording_proc = p
                self.recording_file = output
                return True
Ejemplo n.º 9
0
    def start_recording(self, max_time=1800, bit_rate=None):
        """
        Start screen recording

        Args:
            max_time: maximum screen recording time, default is 1800
            bit_rate: bit rate value, default is None(6000000)

        Raises:
            RuntimeError: if any error occurs while setup the recording

        Returns:
            None if recording did not start, otherwise True

        """
        if getattr(self, "recording_proc", None):
            raise AirtestError("recording_proc has already started")
        pkg_path = self.adb.path_app(YOSEMITE_PACKAGE)
        max_time_param = "-Dduration=%d" % max_time if max_time else ""
        # The higher the bitrate, the clearer the video, the default value is 6000000
        bit_rate_param = "-Dbitrate=%d" % bit_rate if bit_rate else ""
        # The video size is square, compatible with horizontal and vertical screens
        p = self.adb.start_shell(
            'CLASSPATH=%s exec app_process %s %s /system/bin %s.Recorder --start-record'
            % (pkg_path, max_time_param, bit_rate_param, YOSEMITE_PACKAGE))
        nbsp = NonBlockingStreamReader(p.stdout)
        while True:
            line = nbsp.readline(timeout=5)
            if line is None:
                raise RuntimeError("start recording error")
            if six.PY3:
                line = line.decode("utf-8")
            m = re.match(
                "start result: Record start success! File path:(.*\.mp4)",
                line.strip())
            if m:
                output = m.group(1)
                self.recording_proc = p
                self.recording_file = output
                return True
Ejemplo n.º 10
0
class RotationWatcher(object):
    """
    RotationWatcher class
    """

    def __init__(self, adb, ori_method=ORI_METHOD.MINICAP):
        self.adb = adb
        self.ow_proc = None
        self.nbsp = None
        self.ow_callback = []
        self.ori_method = ori_method
        self._t = None
        self._t_kill_event = threading.Event()
        self.current_orientation = None
        self.path_in_android = "/data/local/tmp/" + os.path.basename(ROTATIONWATCHER_JAR)
        reg_cleanup(self.teardown)

    @on_method_ready('start')
    def get_ready(self):
        pass

    def install(self):
        """
        Install the RotationWatcher package

        Returns:
            None

        """
        try:
            exists_file = self.adb.file_size(self.path_in_android)
        except:
            pass
        else:
            local_minitouch_size = int(os.path.getsize(ROTATIONWATCHER_JAR))
            if exists_file and exists_file == local_minitouch_size:
                LOGGING.debug("install_rotationwatcher skipped")
                return
            self.uninstall()

        self.adb.push(ROTATIONWATCHER_JAR, self.path_in_android)
        self.adb.shell("chmod 755 %s" % self.path_in_android)
        LOGGING.info("install rotationwacher finished")

    def uninstall(self):
        """
        Uninstall the RotationWatcher package

        Returns:
            None

        """
        self.adb.raw_shell("rm %s" % self.path_in_android)

    def setup_server(self):
        """
        Setup rotation wacher server

        Returns:
            server process

        """
        self.install()
        if self.ow_proc:
            self.ow_proc.kill()
            self.ow_proc = None

        p = self.adb.start_shell(
            "app_process -Djava.class.path={0} /data/local/tmp com.example.rotationwatcher.Main".format(
                self.path_in_android))
        self.nbsp = NonBlockingStreamReader(p.stdout, name="rotation_server", auto_kill=True)

        if p.poll() is not None:
            # server setup error, may be already setup by others
            # subprocess exit immediately
            raise RuntimeError("rotation watcher server quit immediately")
        self.ow_proc = p
        return p

    def teardown(self):
        self._t_kill_event.set()
        if self.ow_proc:
            self.ow_proc.kill()
            # close io.Buffer
            self.ow_proc.communicate()
        if self.nbsp:
            self.nbsp.kill()

    def start(self):
        """
        Start the RotationWatcher daemon thread

        Returns:
            initial orientation

        """
        if self.ori_method == ORI_METHOD.MINICAP:
            try:
                self.setup_server()
            except:
                # install or setup failed
                LOGGING.error(traceback.format_exc())
                LOGGING.error("RotationWatcher setup failed, use ADBORI instead.")
                self.ori_method = ORI_METHOD.ADB

        def _refresh_by_ow():
            # 在产生旋转时,nbsp读取到的内容为b"90\r\n",平时读到的是空数据None,进程结束时读到的是b""
            line = self.nbsp.readline()
            if line is not None:
                if line == b"":
                    self.teardown()
                    if LOGGING is not None:  # may be None atexit
                        LOGGING.debug("orientationWatcher has ended")
                    else:
                        print("orientationWatcher has ended")
                    return None

                ori = int(int(line) / 90)
                return ori
            # 每隔1秒读取一次
            time.sleep(1)

        def _refresh_by_adb():
            ori = self.adb.getDisplayOrientation()
            return ori

        def _run(kill_event):
            while not kill_event.is_set():
                if self.ori_method == ORI_METHOD.ADB:
                    ori = _refresh_by_adb()
                    if self.current_orientation == ori:
                        time.sleep(3)
                        continue
                else:
                    ori = _refresh_by_ow()
                if ori is None:
                    # 以前ori=None是进程结束,现在屏幕方向不变时会返回None
                    continue
                LOGGING.info('update orientation %s->%s' % (self.current_orientation, ori))
                self.current_orientation = ori
                if is_exiting():
                    self.teardown()
                for cb in self.ow_callback:
                    try:
                        cb(ori)
                    except:
                        LOGGING.error("cb: %s error" % cb)
                        traceback.print_exc()

        self.current_orientation = _refresh_by_ow() if self.ori_method != ORI_METHOD.ADB else _refresh_by_adb()

        self._t = threading.Thread(target=_run, args=(self._t_kill_event, ), name="rotationwatcher")
        self._t.daemon = True
        self._t.start()

        return self.current_orientation

    def reg_callback(self, ow_callback):
        """

        Args:
            ow_callback:

        Returns:

        """
        """方向变化的时候的回调函数,参数一定是ori,如果断掉了,ori传None"""
        if ow_callback not in self.ow_callback:
            self.ow_callback.append(ow_callback)