Beispiel #1
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
Beispiel #2
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
Beispiel #3
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)