├── scripts ├── requirements.txt ├── agent.so ├── screen_recroding.py ├── hdc.py └── keycode.py ├── docs └── hdc.png ├── setup.cfg ├── .gitignore ├── LICENSE └── README.md /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | opencv-python-headless 2 | -------------------------------------------------------------------------------- /docs/hdc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codematrixer/awesome-hdc/HEAD/docs/hdc.png -------------------------------------------------------------------------------- /scripts/agent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codematrixer/awesome-hdc/HEAD/scripts/agent.so -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | exclude = tests/* 4 | max-complexity = 10 5 | ignore = 6 | W292, 7 | E501, 8 | F401, 9 | F841, 10 | F401, 11 | E126, 12 | W605, 13 | E402, 14 | F405, 15 | W292, 16 | # ambiguous variable name 'l'cornflakes(E741) 17 | E741, 18 | # do not use bare 'except'cornflakes(E722) 19 | E722, 20 | # 'from models.common import *' used; unable to detect undefined namescornflakes(F403) 21 | F403, 22 | # F812: list comprehension redefines ... 23 | F812, 24 | # H101: Use TODO(NAME) 25 | H101, 26 | # H202: assertRaises Exception too broad 27 | H202, 28 | # H233: Python 3.x incompatible use of print operator 29 | H233, 30 | # H301: one import per line 31 | H301, 32 | # H306: imports not in alphabetical order (time, os) 33 | H306, 34 | # H401: docstring should not start with a space 35 | H401, 36 | # H403: multi line docstrings should end on a new line 37 | H403, 38 | # H404: multi line docstring should start without a leading new line 39 | H404, 40 | # H405: multi line docstring summary not separated with an empty line 41 | H405, 42 | # H501: Do not use self.__dict__ for string formatting 43 | H501, 44 | # Function is too complex (C901) 45 | C901 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | 8 | # Distribution / packaging 9 | .Python 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | share/python-wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | *.mp4 28 | .DS_Store 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | .pybuilder/ 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | # For a library or package, you might want to ignore these files since the code is 88 | # intended to run in multiple environments; otherwise, check them in: 89 | # .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # poetry 99 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 100 | # This is especially recommended for binary packages to ensure reproducibility, and is more 101 | # commonly ignored for libraries. 102 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 103 | #poetry.lock 104 | 105 | # pdm 106 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 107 | #pdm.lock 108 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 109 | # in version control. 110 | # https://pdm.fming.dev/#use-with-ide 111 | .pdm.toml 112 | 113 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 114 | __pypackages__/ 115 | 116 | # Celery stuff 117 | celerybeat-schedule 118 | celerybeat.pid 119 | 120 | # SageMath parsed files 121 | *.sage.py 122 | 123 | # Environments 124 | .env 125 | .venv 126 | env/ 127 | venv/ 128 | ENV/ 129 | env.bak/ 130 | venv.bak/ 131 | 132 | # Spyder project settings 133 | .spyderproject 134 | .spyproject 135 | 136 | # Rope project settings 137 | .ropeproject 138 | 139 | # mkdocs documentation 140 | /site 141 | 142 | # mypy 143 | .mypy_cache/ 144 | .dmypy.json 145 | dmypy.json 146 | 147 | # Pyre type checker 148 | .pyre/ 149 | 150 | # pytype static type analyzer 151 | .pytype/ 152 | 153 | # Cython debug symbols 154 | cython_debug/ 155 | 156 | # PyCharm 157 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 158 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 159 | # and can be added to the global gitignore or merged into this file. For a more nuclear 160 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 161 | #.idea/ 162 | -------------------------------------------------------------------------------- /scripts/screen_recroding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import socket 4 | import json 5 | import time 6 | import os 7 | import typing 8 | import subprocess 9 | import atexit 10 | import hashlib 11 | import threading 12 | from queue import Queue 13 | from datetime import datetime 14 | 15 | import cv2 16 | import numpy as np 17 | 18 | from functools import cached_property 19 | 20 | from hdc import HdcWrapper 21 | 22 | 23 | ABC_RPC_PORT = 8012 24 | 25 | 26 | class HmScreenRecorder: 27 | """Record the screen.""" 28 | def __init__(self, serial: str): 29 | self.hdc = HdcWrapper(serial) 30 | self.sock = None 31 | self.jpeg_queue = Queue() 32 | self.threads: typing.List[threading.Thread] = [] 33 | self.stop_event = threading.Event() 34 | 35 | if not self.hdc.is_online(): 36 | raise RuntimeError(f"Device [{serial}] not found") 37 | 38 | # Register the instance method to be called at exit 39 | atexit.register(self._rm_local_port) 40 | 41 | @cached_property 42 | def local_port(self): 43 | return self.hdc.forward_port(ABC_RPC_PORT) 44 | 45 | def _rm_local_port(self): 46 | self.hdc.rm_forward(self.local_port, ABC_RPC_PORT) 47 | 48 | def _connect(self): 49 | """Create socket and connect to the RPC server.""" 50 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 51 | self.sock.settimeout(3) 52 | self.sock.connect((("127.0.0.1", self.local_port))) 53 | 54 | def _send_message(self, api: str, args: list): 55 | """Send an RPC message to the server.""" 56 | _msg = { 57 | "module": "com.ohos.devicetest.hypiumApiHelper", 58 | "method": "Captures", 59 | "params": { 60 | "api": api, 61 | "args": args 62 | }, 63 | "request_id": datetime.now().strftime("%Y%m%d%H%M%S%f") 64 | } 65 | msg = json.dumps(_msg, ensure_ascii=False, separators=(',', ':')) 66 | print(msg) 67 | self.sock.sendall(msg.encode('utf-8') + b'\n') 68 | 69 | def _recv_mesaage(self, buff_size: int = 1024, decode=False) -> typing.Union[bytearray, str]: 70 | try: 71 | relay = self.sock.recv(buff_size) 72 | if decode: 73 | relay = relay.decode() 74 | return relay 75 | except (socket.timeout, UnicodeDecodeError) as e: 76 | # socket.timeout 77 | # UnicodeDecodeError 78 | print(e) 79 | if decode: 80 | return '' 81 | return bytearray() 82 | 83 | def start(self, file_path: str): 84 | """ 85 | Starts screen recording. 86 | 87 | This method restarts the UI test service, establishes a connection with the RPC server, 88 | sends a message to start screen capturing, and begins the recording and video writing threads. 89 | 90 | Args: 91 | file_path (str): Path where the recorded video will be saved. 92 | 93 | Raises: 94 | RuntimeError: If the screen capture fails to start. 95 | """ 96 | self._init_so_resource() 97 | self._restart_uitest_service() 98 | 99 | self._connect() 100 | 101 | self._video_path = file_path 102 | self._send_message("startCaptureScreen", []) 103 | 104 | reply: str = self._recv_mesaage(1024, decode=True) 105 | if "true" in reply: 106 | record_th = threading.Thread(target=self._record_worker) 107 | writer_th = threading.Thread(target=self._video_writer) 108 | record_th.start() 109 | writer_th.start() 110 | self.threads.extend([record_th, writer_th]) 111 | else: 112 | raise RuntimeError("Failed to start hm screen capture.") 113 | 114 | def _record_worker(self): 115 | """Capture screen frames and save current frames.""" 116 | 117 | # JPEG start and end markers. 118 | start_flag = b'\xff\xd8' 119 | end_flag = b'\xff\xd9' 120 | buffer = bytearray() 121 | while not self.stop_event.is_set(): 122 | try: 123 | buffer += self._recv_mesaage(4096 * 1024) 124 | except Exception as e: 125 | print(f"Error receiving data: {e}") 126 | break 127 | 128 | start_idx = buffer.find(start_flag) 129 | end_idx = buffer.find(end_flag) 130 | while start_idx != -1 and end_idx != -1 and end_idx > start_idx: 131 | # Extract one JPEG image 132 | jpeg_image: bytearray = buffer[start_idx:end_idx + 2] 133 | self.jpeg_queue.put(jpeg_image) 134 | 135 | buffer = buffer[end_idx + 2:] 136 | 137 | # Search for the next JPEG image in the buffer 138 | start_idx = buffer.find(start_flag) 139 | end_idx = buffer.find(end_flag) 140 | 141 | def _video_writer(self): 142 | """Write frames to video file.""" 143 | cv2_instance = None 144 | while not self.stop_event.is_set(): 145 | if not self.jpeg_queue.empty(): 146 | jpeg_image = self.jpeg_queue.get(timeout=0.1) 147 | img = cv2.imdecode(np.frombuffer(jpeg_image, np.uint8), cv2.IMREAD_COLOR) 148 | if cv2_instance is None: 149 | height, width = img.shape[:2] 150 | fourcc = cv2.VideoWriter_fourcc(*'mp4v') 151 | cv2_instance = cv2.VideoWriter(self._video_path, fourcc, 10, (width, height)) 152 | 153 | cv2_instance.write(img) 154 | 155 | if cv2_instance: 156 | cv2_instance.release() 157 | 158 | def stop(self): 159 | """Stop screen recording.""" 160 | try: 161 | self.stop_event.set() 162 | for t in self.threads: 163 | t.join() 164 | 165 | if self.sock: 166 | self._send_message("stopCaptureScreen", []) 167 | self._recv_mesaage(1024, decode=True) 168 | self.sock.close() 169 | except Exception as e: 170 | print(f"An error occurred: {e}") 171 | 172 | def _init_so_resource(self): 173 | "Initialize the agent.so resource on the device." 174 | 175 | def __get_so_local_path() -> str: 176 | current_path = os.path.dirname(os.path.realpath(__file__)) 177 | return os.path.join(os.path.dirname(current_path), 'scripts', 'agent.so') 178 | 179 | def __check_device_so_file_exists() -> bool: 180 | """Check if the agent.so file exists on the device.""" 181 | command = "[ -f /data/local/tmp/agent.so ] && echo 'so exists' || echo 'so not exists'" 182 | result = self.hdc.shell(command).output.strip() 183 | return "so exists" in result 184 | 185 | def __get_remote_md5sum() -> str: 186 | """Get the MD5 checksum of the file on the device.""" 187 | command = "md5sum /data/local/tmp/agent.so" 188 | data = self.hdc.shell(command).output.strip() 189 | return data.split()[0] 190 | 191 | def __get_local_md5sum(f: str) -> str: 192 | """Calculate the MD5 checksum of a local file.""" 193 | hash_md5 = hashlib.md5() 194 | with open(f, "rb") as f: 195 | for chunk in iter(lambda: f.read(4096), b""): 196 | hash_md5.update(chunk) 197 | return hash_md5.hexdigest() 198 | 199 | local_path = __get_so_local_path() 200 | remote_path = "/data/local/tmp/agent.so" 201 | 202 | if __check_device_so_file_exists() and __get_local_md5sum(local_path) == __get_remote_md5sum(): 203 | return 204 | self.hdc.send_file(local_path, remote_path) 205 | 206 | def _restart_uitest_service(self): 207 | """ 208 | Restart the UITest daemon. Screen recording depends on this process. 209 | Note: 'hdc shell aa test' will also start a uitest daemon. 210 | $ hdc shell ps -ef |grep uitest 211 | shell 44306 1 25 11:03:37 ? 00:00:16 uitest start-daemon singleness 212 | shell 44416 1 2 11:03:42 ? 00:00:01 uitest start-daemon com.krunner.hm.atx@4x9@1" 213 | """ 214 | try: 215 | result = self.hdc.shell("ps -ef").output.strip() 216 | lines = result.splitlines() 217 | filtered_lines = [line for line in lines if 'uitest' in line and 'singleness' in line] 218 | 219 | for line in filtered_lines: 220 | if 'uitest start-daemon singleness' in line: 221 | parts = line.split() 222 | pid = parts[1] 223 | self.hdc.shell(f"kill -9 {pid}") 224 | print(f"Killed uitest process with PID {pid}") 225 | 226 | self.hdc.shell("uitest start-daemon singleness") 227 | time.sleep(.5) 228 | 229 | except subprocess.CalledProcessError as e: 230 | print(f"An error occurred: {e}") 231 | 232 | 233 | if __name__ == "__main__": 234 | recorder = HmScreenRecorder("FMR0223C13000649") 235 | recorder.start("test.mp4") 236 | input("Press Enter to stop...") 237 | recorder.stop() -------------------------------------------------------------------------------- /scripts/hdc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import tempfile 4 | import json 5 | import uuid 6 | import shlex 7 | import socket 8 | import re 9 | import subprocess 10 | from typing import Union, List 11 | from dataclasses import dataclass 12 | 13 | from keycode import KeyCode 14 | 15 | 16 | class _FreePort: 17 | def __init__(self): 18 | self._start = 10000 19 | self._end = 20000 20 | self._now = self._start - 1 21 | 22 | def get(self) -> int: 23 | while True: 24 | self._now += 1 25 | if self._now > self._end: 26 | self._now = self._start 27 | if not self.is_port_in_use(self._now): 28 | return self._now 29 | 30 | @staticmethod 31 | def is_port_in_use(port: int) -> bool: 32 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 33 | return s.connect_ex(('localhost', port)) == 0 34 | 35 | 36 | @dataclass 37 | class CommandResult: 38 | output: str 39 | error: str 40 | exit_code: int 41 | 42 | 43 | def _execute_command(cmdargs: Union[str, List[str]]) -> CommandResult: 44 | if isinstance(cmdargs, (list, tuple)): 45 | cmdline: str = ' '.join(list(map(shlex.quote, cmdargs))) 46 | elif isinstance(cmdargs, str): 47 | cmdline = cmdargs 48 | 49 | try: 50 | process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 51 | output, error = process.communicate() 52 | output = output.decode('utf-8') 53 | error = error.decode('utf-8') 54 | exit_code = process.returncode 55 | return CommandResult(output, error, exit_code) 56 | except Exception as e: 57 | return CommandResult("", str(e), -1) 58 | 59 | 60 | def list_devices() -> List[str]: 61 | devices = [] 62 | result = _execute_command('hdc list targets') 63 | if result.exit_code == 0 and result.output: 64 | lines = result.output.strip().split('\n') 65 | for line in lines: 66 | devices.append(line.strip()) 67 | return devices 68 | 69 | 70 | class HdcWrapper: 71 | def __init__(self, serial: str) -> None: 72 | self.serial = serial 73 | 74 | def is_online(self) -> bool: 75 | serials = list_devices() 76 | return True if self.serial in serials else False 77 | 78 | def forward_port(self, rport: int) -> int: 79 | lport: int = _FreePort().get() 80 | result = _execute_command(f"hdc -t {self.serial} fport tcp:{lport} tcp:{rport}") 81 | if result.exit_code != 0: 82 | raise RuntimeError("HDC forward port error", result.output) 83 | return lport 84 | 85 | def rm_forward(self, lport: int, rport: int) -> int: 86 | result = _execute_command(f"hdc -t {self.serial} fport rm tcp:{lport} tcp:{rport}") 87 | if result.exit_code != 0: 88 | raise RuntimeError("HDC rm forward error", result.output) 89 | return lport 90 | 91 | def list_fport(self) -> List: 92 | """ 93 | eg. ['tcp:10001 tcp:8012', 'tcp:10255 tcp:8012'] 94 | """ 95 | result = _execute_command(f"hdc -t {self.serial} fport ls") 96 | if result.exit_code != 0: 97 | raise RuntimeError("HDC forward list error", result.output) 98 | pattern = re.compile(r"tcp:\d+ tcp:\d+") 99 | return pattern.findall(result.output) 100 | 101 | def send_file(self, lpath: str, rpath: str): 102 | result = _execute_command(f"hdc -t {self.serial} file send {lpath} {rpath}") 103 | if result.exit_code != 0: 104 | raise RuntimeError("HDC send file error", result.output) 105 | return result 106 | 107 | def recv_file(self, rpath: str, lpath: str): 108 | result = _execute_command(f"hdc -t {self.serial} file recv {rpath} {lpath}") 109 | if result.exit_code != 0: 110 | raise RuntimeError("HDC receive file error", result.output) 111 | return result 112 | 113 | def shell(self, cmd: str, error_raise=True) -> CommandResult: 114 | result = _execute_command(f"hdc -t {self.serial} shell {cmd}") 115 | if result.error and error_raise: 116 | raise RuntimeError("HDC shell error", f"{cmd}\n{result.output}\n{result.error}") 117 | return result 118 | 119 | def uninstall(self, bundlename: str): 120 | result = _execute_command(f"hdc -t {self.serial} uninstall {bundlename}") 121 | if result.exit_code != 0: 122 | raise RuntimeError("HDC uninstall error", result.output) 123 | return result 124 | 125 | def install(self, apkpath: str): 126 | result = _execute_command(f"hdc -t {self.serial} install {apkpath}") 127 | if result.exit_code != 0: 128 | raise RuntimeError("HDC install error", result.output) 129 | return result 130 | 131 | def list_apps(self) -> List[str]: 132 | result = self.shell("bm dump -a") 133 | raw = result.output.split('\n') 134 | return [item.strip() for item in raw] 135 | 136 | def has_app(self, package_name: str) -> bool: 137 | data = self.shell("bm dump -a").output 138 | return True if package_name in data else False 139 | 140 | def start_app(self, package_name: str, ability_name: str): 141 | return self.shell(f"aa start -a {ability_name} -b {package_name}") 142 | 143 | def stop_app(self, package_name: str): 144 | return self.shell(f"aa force-stop {package_name}") 145 | 146 | def wakeup(self): 147 | self.shell("power-shell wakeup") 148 | 149 | def screen_state(self) -> str: 150 | """ 151 | ["INACTIVE", "SLEEP, AWAKE"] 152 | """ 153 | data = self.shell("hidumper -s PowerManagerService -a -s").output 154 | pattern = r"Current State:\s*(\w+)" 155 | match = re.search(pattern, data) 156 | 157 | return match.group(1) if match else None 158 | 159 | def wlan_ip(self) -> Union[str, None]: 160 | data = self.shell("ifconfig").output 161 | matches = re.findall(r'inet addr:(?!127)(\d+\.\d+\.\d+\.\d+)', data) 162 | return matches[0] if matches else None 163 | 164 | def __split_text(self, text: str) -> str: 165 | return text.split("\n")[0].strip() if text else None 166 | 167 | def sdk_version(self) -> str: 168 | data = self.shell("param get const.ohos.apiversion").output 169 | return self.__split_text(data) 170 | 171 | def sys_version(self) -> str: 172 | data = self.shell("param get const.product.software.version").output 173 | return self.__split_text(data) 174 | 175 | def model(self) -> str: 176 | data = self.shell("param get const.product.model").output 177 | return self.__split_text(data) 178 | 179 | def brand(self) -> str: 180 | data = self.shell("param get const.product.brand").output 181 | return self.__split_text(data) 182 | 183 | def product_name(self) -> str: 184 | data = self.shell("param get const.product.name").output 185 | return self.__split_text(data) 186 | 187 | def cpu_abi(self) -> str: 188 | data = self.shell("param get const.product.cpu.abilist").output 189 | return self.__split_text(data) 190 | 191 | def send_key(self, key_code: Union[KeyCode, int]) -> None: 192 | if isinstance(key_code, KeyCode): 193 | key_code = key_code.value 194 | self.shell(f"uitest uiInput keyEvent {key_code}") 195 | 196 | def go_home(self): 197 | self.send_key(KeyCode.HOME) 198 | 199 | def back(self): 200 | self.send_key(KeyCode.BACK) 201 | 202 | def click(self, x: int, y: int): 203 | self.shell(f"uitest uiInput click {x} {y}") 204 | 205 | def doubleClick(self, x: int, y: int): 206 | self.shell(f"uitest uiInput doubleClick {x} {y}") 207 | 208 | def longClick(self, x: int, y: int): 209 | self.shell(f"uitest uiInput longClick {x} {y}") 210 | 211 | def swipe(self, x1, y1, x2, y2, speed=1000): 212 | """ 213 | speed为滑动速率, 范围:200~40000, 不在范围内设为默认值为600, 单位: 像素点/秒 214 | """ 215 | self.shell(f"uitest uiInput swipe {x1} {y1} {x2} {y2} {speed}") 216 | 217 | def drag(self, x1, y1, x2, y2, speed=1000): 218 | """ 219 | speed为滑动速率, 范围:200~40000, 不在范围内设为默认值为600, 单位: 像素点/秒 220 | """ 221 | self.shell(f"uitest uiInput drag {x1} {y1} {x2} {y2} {speed}") 222 | 223 | def input_text(self, x: int, y: int, text: str): 224 | self.shell(f"uitest uiInput inputText {x} {y} {text}") 225 | 226 | def screenshot(self, path: str) -> str: 227 | _uuid = uuid.uuid4().hex 228 | _tmp_path = f"/data/local/tmp/_tmp_{_uuid}.jpeg" 229 | self.shell(f"snapshot_display -f {_tmp_path}") 230 | self.recv_file(_tmp_path, path) 231 | self.shell(f"rm -rf {_tmp_path}") # remove local path 232 | return path 233 | 234 | def dump_hierarchy(self) -> dict: 235 | _tmp_path = "/data/local/tmp/_tmp.json" 236 | self.shell(f"uitest dumpLayout -p {_tmp_path}") 237 | 238 | with tempfile.NamedTemporaryFile(delete=False, suffix=".json") as f: 239 | path = f.name 240 | self.recv_file(_tmp_path, path) 241 | 242 | try: 243 | with open(path, 'r') as file: 244 | data = json.load(file) 245 | except Exception as e: 246 | print(f"Error loading JSON file: {e}") 247 | data = {} 248 | 249 | return data 250 | 251 | 252 | if __name__ == "__main__": 253 | hdc = HdcWrapper("FMR0223C13000649") 254 | print(hdc.screen_state()) 255 | print(hdc.wlan_ip()) 256 | print(hdc.sdk_version()) 257 | print(hdc.sys_version()) 258 | print(hdc.model()) 259 | print(hdc.brand()) 260 | print(hdc.product_name()) 261 | print(hdc.cpu_abi()) 262 | print(hdc.list_apps()) 263 | print(hdc.has_app("com.samples.test.uitest")) -------------------------------------------------------------------------------- /scripts/keycode.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from enum import Enum 4 | 5 | 6 | class KeyCode(Enum): 7 | 8 | FN = 0 # 功能(Fn)键 9 | UNKNOWN = -1 # 未知按键 10 | HOME = 1 # 功能(Home)键 11 | BACK = 2 # 返回键 12 | MEDIA_PLAY_PAUSE = 10 # 多媒体键播放/暂停 13 | MEDIA_STOP = 11 # 多媒体键停止 14 | MEDIA_NEXT = 12 # 多媒体键下一首 15 | MEDIA_PREVIOUS = 13 # 多媒体键上一首 16 | MEDIA_REWIND = 14 # 多媒体键快退 17 | MEDIA_FAST_FORWARD = 15 # 多媒体键快进 18 | VOLUME_UP = 16 # 音量增加键 19 | VOLUME_DOWN = 17 # 音量减小键 20 | POWER = 18 # 电源键 21 | CAMERA = 19 # 拍照键 22 | VOLUME_MUTE = 22 # 扬声器静音键 23 | MUTE = 23 # 话筒静音键 24 | BRIGHTNESS_UP = 40 # 亮度调节按键调亮 25 | BRIGHTNESS_DOWN = 41 # 亮度调节按键调暗 26 | NUM_0 = 2000 # 按键’0’ 27 | NUM_1 = 2001 # 按键’1’ 28 | NUM_2 = 2002 # 按键’2’ 29 | NUM_3 = 2003 # 按键’3’ 30 | NUM_4 = 2004 # 按键’4’ 31 | NUM_5 = 2005 # 按键’5’ 32 | NUM_6 = 2006 # 按键’6’ 33 | NUM_7 = 2007 # 按键’7’ 34 | NUM_8 = 2008 # 按键’8’ 35 | NUM_9 = 2009 # 按键’9’ 36 | STAR = 2010 # 按键’*’ 37 | POUND = 2011 # 按键’#’ 38 | DPAD_UP = 2012 # 导航键向上 39 | DPAD_DOWN = 2013 # 导航键向下 40 | DPAD_LEFT = 2014 # 导航键向左 41 | DPAD_RIGHT = 2015 # 导航键向右 42 | DPAD_CENTER = 2016 # 导航键确定键 43 | A = 2017 # 按键’A’ 44 | B = 2018 # 按键’B’ 45 | C = 2019 # 按键’C’ 46 | D = 2020 # 按键’D’ 47 | E = 2021 # 按键’E’ 48 | F = 2022 # 按键’F’ 49 | G = 2023 # 按键’G’ 50 | H = 2024 # 按键’H’ 51 | I = 2025 # 按键’I’ 52 | J = 2026 # 按键’J’ 53 | K = 2027 # 按键’K’ 54 | L = 2028 # 按键’L’ 55 | M = 2029 # 按键’M’ 56 | N = 2030 # 按键’N’ 57 | O = 2031 # 按键’O’ 58 | P = 2032 # 按键’P’ 59 | Q = 2033 # 按键’Q’ 60 | R = 2034 # 按键’R’ 61 | S = 2035 # 按键’S’ 62 | T = 2036 # 按键’T’ 63 | U = 2037 # 按键’U’ 64 | V = 2038 # 按键’V’ 65 | W = 2039 # 按键’W’ 66 | X = 2040 # 按键’X’ 67 | Y = 2041 # 按键’Y’ 68 | Z = 2042 # 按键’Z’ 69 | COMMA = 2043 # 按键’,’ 70 | PERIOD = 2044 # 按键’.’ 71 | ALT_LEFT = 2045 # 左Alt键 72 | ALT_RIGHT = 2046 # 右Alt键 73 | SHIFT_LEFT = 2047 # 左Shift键 74 | SHIFT_RIGHT = 2048 # 右Shift键 75 | TAB = 2049 # Tab键 76 | SPACE = 2050 # 空格键 77 | SYM = 2051 # 符号修改器按键 78 | EXPLORER = 2052 # 浏览器功能键,此键用于启动浏览器应用程序。 79 | ENVELOPE = 2053 # 电子邮件功能键,此键用于启动电子邮件应用程序。 80 | ENTER = 2054 # 回车键 81 | DEL = 2055 # 退格键 82 | GRAVE = 2056 # 按键’`’ 83 | MINUS = 2057 # 按键’-’ 84 | EQUALS = 2058 # 按键’=’ 85 | LEFT_BRACKET = 2059 # 按键’[’ 86 | RIGHT_BRACKET = 2060 # 按键’]’ 87 | BACKSLASH = 2061 # 按键’\’ 88 | SEMICOLON = 2062 # 按键’;’ 89 | APOSTROPHE = 2063 # 按键’‘’(单引号) 90 | SLASH = 2064 # 按键’/’ 91 | AT = 2065 # 按键’@’ 92 | PLUS = 2066 # 按键’+’ 93 | MENU = 2067 # 菜单键 94 | PAGE_UP = 2068 # 向上翻页键 95 | PAGE_DOWN = 2069 # 向下翻页键 96 | ESCAPE = 2070 # ESC键 97 | FORWARD_DEL = 2071 # 删除键 98 | CTRL_LEFT = 2072 # 左Ctrl键 99 | CTRL_RIGHT = 2073 # 右Ctrl键 100 | CAPS_LOCK = 2074 # 大写锁定键 101 | SCROLL_LOCK = 2075 # 滚动锁定键 102 | META_LEFT = 2076 # 左元修改器键 103 | META_RIGHT = 2077 # 右元修改器键 104 | FUNCTION = 2078 # 功能键 105 | SYSRQ = 2079 # 系统请求/打印屏幕键 106 | BREAK = 2080 # Break/Pause键 107 | MOVE_HOME = 2081 # 光标移动到开始键 108 | MOVE_END = 2082 # 光标移动到末尾键 109 | INSERT = 2083 # 插入键 110 | FORWARD = 2084 # 前进键 111 | MEDIA_PLAY = 2085 # 多媒体键播放 112 | MEDIA_PAUSE = 2086 # 多媒体键暂停 113 | MEDIA_CLOSE = 2087 # 多媒体键关闭 114 | MEDIA_EJECT = 2088 # 多媒体键弹出 115 | MEDIA_RECORD = 2089 # 多媒体键录音 116 | F1 = 2090 # 按键’F1’ 117 | F2 = 2091 # 按键’F2’ 118 | F3 = 2092 # 按键’F3’ 119 | F4 = 2093 # 按键’F4’ 120 | F5 = 2094 # 按键’F5’ 121 | F6 = 2095 # 按键’F6’ 122 | F7 = 2096 # 按键’F7’ 123 | F8 = 2097 # 按键’F8’ 124 | F9 = 2098 # 按键’F9’ 125 | F10 = 2099 # 按键’F10’ 126 | F11 = 2100 # 按键’F11’ 127 | F12 = 2101 # 按键’F12’ 128 | NUM_LOCK = 2102 # 小键盘锁 129 | NUMPAD_0 = 2103 # 小键盘按键’0’ 130 | NUMPAD_1 = 2104 # 小键盘按键’1’ 131 | NUMPAD_2 = 2105 # 小键盘按键’2’ 132 | NUMPAD_3 = 2106 # 小键盘按键’3’ 133 | NUMPAD_4 = 2107 # 小键盘按键’4’ 134 | NUMPAD_5 = 2108 # 小键盘按键’5’ 135 | NUMPAD_6 = 2109 # 小键盘按键’6’ 136 | NUMPAD_7 = 2110 # 小键盘按键’7’ 137 | NUMPAD_8 = 2111 # 小键盘按键’8’ 138 | NUMPAD_9 = 2112 # 小键盘按键’9’ 139 | NUMPAD_DIVIDE = 2113 # 小键盘按键’/’ 140 | NUMPAD_MULTIPLY = 2114 # 小键盘按键’*’ 141 | NUMPAD_SUBTRACT = 2115 # 小键盘按键’-’ 142 | NUMPAD_ADD = 2116 # 小键盘按键’+’ 143 | NUMPAD_DOT = 2117 # 小键盘按键’.’ 144 | NUMPAD_COMMA = 2118 # 小键盘按键’,’ 145 | NUMPAD_ENTER = 2119 # 小键盘按键回车 146 | NUMPAD_EQUALS = 2120 # 小键盘按键’=’ 147 | NUMPAD_LEFT_PAREN = 2121 # 小键盘按键’(’ 148 | NUMPAD_RIGHT_PAREN = 2122 # 小键盘按键’)’ 149 | VIRTUAL_MULTITASK = 2210 # 虚拟多任务键 150 | SLEEP = 2600 # 睡眠键 151 | ZENKAKU_HANKAKU = 2601 # 日文全宽/半宽键 152 | ND = 2602 # 102nd按键 153 | RO = 2603 # 日文Ro键 154 | KATAKANA = 2604 # 日文片假名键 155 | HIRAGANA = 2605 # 日文平假名键 156 | HENKAN = 2606 # 日文转换键 157 | KATAKANA_HIRAGANA = 2607 # 日语片假名/平假名键 158 | MUHENKAN = 2608 # 日文非转换键 159 | LINEFEED = 2609 # 换行键 160 | MACRO = 2610 # 宏键 161 | NUMPAD_PLUSMINUS = 2611 # 数字键盘上的加号/减号键 162 | SCALE = 2612 # 扩展键 163 | HANGUEL = 2613 # 日文韩语键 164 | HANJA = 2614 # 日文汉语键 165 | YEN = 2615 # 日元键 166 | STOP = 2616 # 停止键 167 | AGAIN = 2617 # 重复键 168 | PROPS = 2618 # 道具键 169 | UNDO = 2619 # 撤消键 170 | COPY = 2620 # 复制键 171 | OPEN = 2621 # 打开键 172 | PASTE = 2622 # 粘贴键 173 | FIND = 2623 # 查找键 174 | CUT = 2624 # 剪切键 175 | HELP = 2625 # 帮助键 176 | CALC = 2626 # 计算器特殊功能键,用于启动计算器应用程序 177 | FILE = 2627 # 文件按键 178 | BOOKMARKS = 2628 # 书签键 179 | NEXT = 2629 # 下一个按键 180 | PLAYPAUSE = 2630 # 播放/暂停键 181 | PREVIOUS = 2631 # 上一个按键 182 | STOPCD = 2632 # CD停止键 183 | CONFIG = 2634 # 配置键 184 | REFRESH = 2635 # 刷新键 185 | EXIT = 2636 # 退出键 186 | EDIT = 2637 # 编辑键 187 | SCROLLUP = 2638 # 向上滚动键 188 | SCROLLDOWN = 2639 # 向下滚动键 189 | NEW = 2640 # 新建键 190 | REDO = 2641 # 恢复键 191 | CLOSE = 2642 # 关闭键 192 | PLAY = 2643 # 播放键 193 | BASSBOOST = 2644 # 低音增强键 194 | PRINT = 2645 # 打印键 195 | CHAT = 2646 # 聊天键 196 | FINANCE = 2647 # 金融键 197 | CANCEL = 2648 # 取消键 198 | KBDILLUM_TOGGLE = 2649 # 键盘灯光切换键 199 | KBDILLUM_DOWN = 2650 # 键盘灯光调亮键 200 | KBDILLUM_UP = 2651 # 键盘灯光调暗键 201 | SEND = 2652 # 发送键 202 | REPLY = 2653 # 答复键 203 | FORWARDMAIL = 2654 # 邮件转发键 204 | SAVE = 2655 # 保存键 205 | DOCUMENTS = 2656 # 文件键 206 | VIDEO_NEXT = 2657 # 下一个视频键 207 | VIDEO_PREV = 2658 # 上一个视频键 208 | BRIGHTNESS_CYCLE = 2659 # 背光渐变键 209 | BRIGHTNESS_ZERO = 2660 # 亮度调节为0键 210 | DISPLAY_OFF = 2661 # 显示关闭键 211 | BTN_MISC = 2662 # 游戏手柄上的各种按键 212 | GOTO = 2663 # 进入键 213 | INFO = 2664 # 信息查看键 214 | PROGRAM = 2665 # 程序键 215 | PVR = 2666 # 个人录像机(PVR)键 216 | SUBTITLE = 2667 # 字幕键 217 | FULL_SCREEN = 2668 # 全屏键 218 | KEYBOARD = 2669 # 键盘 219 | ASPECT_RATIO = 2670 # 屏幕纵横比调节键 220 | PC = 2671 # 端口控制键 221 | TV = 2672 # TV键 222 | TV2 = 2673 # TV键2 223 | VCR = 2674 # 录像机开启键 224 | VCR2 = 2675 # 录像机开启键2 225 | SAT = 2676 # SIM卡应用工具包(SAT)键 226 | CD = 2677 # CD键 227 | TAPE = 2678 # 磁带键 228 | TUNER = 2679 # 调谐器键 229 | PLAYER = 2680 # 播放器键 230 | DVD = 2681 # DVD键 231 | AUDIO = 2682 # 音频键 232 | VIDEO = 2683 # 视频键 233 | MEMO = 2684 # 备忘录键 234 | CALENDAR = 2685 # 日历键 235 | RED = 2686 # 红色指示器 236 | GREEN = 2687 # 绿色指示器 237 | YELLOW = 2688 # 黄色指示器 238 | BLUE = 2689 # 蓝色指示器 239 | CHANNELUP = 2690 # 频道向上键 240 | CHANNELDOWN = 2691 # 频道向下键 241 | LAST = 2692 # 末尾键 242 | RESTART = 2693 # 重启键 243 | SLOW = 2694 # 慢速键 244 | SHUFFLE = 2695 # 随机播放键 245 | VIDEOPHONE = 2696 # 可视电话键 246 | GAMES = 2697 # 游戏键 247 | ZOOMIN = 2698 # 放大键 248 | ZOOMOUT = 2699 # 缩小键 249 | ZOOMRESET = 2700 # 缩放重置键 250 | WORDPROCESSOR = 2701 # 文字处理键 251 | EDITOR = 2702 # 编辑器键 252 | SPREADSHEET = 2703 # 电子表格键 253 | GRAPHICSEDITOR = 2704 # 图形编辑器键 254 | PRESENTATION = 2705 # 演示文稿键 255 | DATABASE = 2706 # 数据库键标 256 | NEWS = 2707 # 新闻键 257 | VOICEMAIL = 2708 # 语音信箱 258 | ADDRESSBOOK = 2709 # 通讯簿 259 | MESSENGER = 2710 # 通信键 260 | BRIGHTNESS_TOGGLE = 2711 # 亮度切换键 261 | SPELLCHECK = 2712 # AL拼写检查 262 | COFFEE = 2713 # 终端锁/屏幕保护程序 263 | MEDIA_REPEAT = 2714 # 媒体循环键 264 | IMAGES = 2715 # 图像键 265 | BUTTONCONFIG = 2716 # 按键配置键 266 | TASKMANAGER = 2717 # 任务管理器 267 | JOURNAL = 2718 # 日志按键 268 | CONTROLPANEL = 2719 # 控制面板键 269 | APPSELECT = 2720 # 应用程序选择键 270 | SCREENSAVER = 2721 # 屏幕保护程序键 271 | ASSISTANT = 2722 # 辅助键 272 | KBD_LAYOUT_NEXT = 2723 # 下一个键盘布局键 273 | BRIGHTNESS_MIN = 2724 # 最小亮度键 274 | BRIGHTNESS_MAX = 2725 # 最大亮度键 275 | KBDINPUTASSIST_PREV = 2726 # 键盘输入Assist_Previous 276 | KBDINPUTASSIST_NEXT = 2727 # 键盘输入Assist_Next 277 | KBDINPUTASSIST_PREVGROUP = 2728 # 键盘输入Assist_Previous 278 | KBDINPUTASSIST_NEXTGROUP = 2729 # 键盘输入Assist_Next 279 | KBDINPUTASSIST_ACCEPT = 2730 # 键盘输入Assist_Accept 280 | KBDINPUTASSIST_CANCEL = 2731 # 键盘输入Assist_Cancel 281 | FRONT = 2800 # 挡风玻璃除雾器开关 282 | SETUP = 2801 # 设置键 283 | WAKE_UP = 2802 # 唤醒键 284 | SENDFILE = 2803 # 发送文件按键 285 | DELETEFILE = 2804 # 删除文件按键 286 | XFER = 2805 # 文件传输(XFER)按键 287 | PROG1 = 2806 # 程序键1 288 | PROG2 = 2807 # 程序键2 289 | MSDOS = 2808 # MS-DOS键(微软磁盘操作系统 290 | SCREENLOCK = 2809 # 屏幕锁定键 291 | DIRECTION_ROTATE_DISPLAY = 2810 # 方向旋转显示键 292 | CYCLEWINDOWS = 2811 # Windows循环键 293 | COMPUTER = 2812 # 按键 294 | EJECTCLOSECD = 2813 # 弹出CD键 295 | ISO = 2814 # ISO键 296 | MOVE = 2815 # 移动键 297 | F13 = 2816 # 按键’F13’ 298 | F14 = 2817 # 按键’F14’ 299 | F15 = 2818 # 按键’F15’ 300 | F16 = 2819 # 按键’F16’ 301 | F17 = 2820 # 按键’F17’ 302 | F18 = 2821 # 按键’F18’ 303 | F19 = 2822 # 按键’F19’ 304 | F20 = 2823 # 按键’F20’ 305 | F21 = 2824 # 按键’F21’ 306 | F22 = 2825 # 按键’F22’ 307 | F23 = 2826 # 按键’F23’ 308 | F24 = 2827 # 按键’F24’ 309 | PROG3 = 2828 # 程序键3 310 | PROG4 = 2829 # 程序键4 311 | DASHBOARD = 2830 # 仪表板 312 | SUSPEND = 2831 # 挂起键 313 | HP = 2832 # 高阶路径键 314 | SOUND = 2833 # 音量键 315 | QUESTION = 2834 # 疑问按键 316 | CONNECT = 2836 # 连接键 317 | SPORT = 2837 # 运动按键 318 | SHOP = 2838 # 商城键 319 | ALTERASE = 2839 # 交替键 320 | SWITCHVIDEOMODE = 2841 # 在可用视频之间循环输出(监视器/LCD/TV输出/等) 321 | BATTERY = 2842 # 电池按键 322 | BLUETOOTH = 2843 # 蓝牙按键 323 | WLAN = 2844 # 无线局域网 324 | UWB = 2845 # 超宽带(UWB) 325 | WWAN_WIMAX = 2846 # WWANWiMAX按键 326 | RFKILL = 2847 # 控制所有收音机的键 327 | CHANNEL = 3001 # 向上频道键 328 | BTN_0 = 3100 # 按键0 329 | BTN_1 = 3101 # 按键1 330 | BTN_2 = 3102 # 按键2 331 | BTN_3 = 3103 # 按键3 332 | BTN_4 = 3104 # 按键4 333 | BTN_5 = 3105 # 按键5 334 | BTN_6 = 3106 # 按键6 335 | BTN_7 = 3107 # 按键7 336 | BTN_8 = 3108 # 按键8 337 | BTN_9 = 3109 # 按键9 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | >由于鸿蒙生态还处于初期,官方提供的hdc命令还在不断修改中,部分命令会有变动。 2 | >如果文档没来得及更新,欢迎大家提PR和Issue补充指正,觉得有用的可以点 Star⭐️收藏。 3 | 4 | HDC(OpenHarmony Device Connector) 是为鸿蒙开发/测试人员提供的用于设备调试的命令行工具,类似Android端的ADB工具。 5 | 6 | HDC主要有三部分组成: 7 | 1. `hdc client`:运行于电脑上的客户端,用户可以在电脑命令终端(windows cmd/linux shell)下请求执行相应的hdc命令。 8 | 2. `hdc server`:作为后台进程也运行于电脑上,server管理client和设备端daemon之间通信包括连接的复用、数据通信包的收发,以及个别本地命令的直接处理。 9 | 3. `hdc daemon`:daemon部署于OpenHarmony设备端作为守护进程按需运行,负责处理来自client端请求。 10 | 11 | ![hdc](https://i.ibb.co/WHpLY3y/hdc.png) 12 | 13 | 14 | **Table of Contents** 15 | - [HDC安装](#hdc安装) 16 | - [基本用法](#基本用法) 17 | - [基本语法](#基本语法) 18 | - [设备连接管理](#设备连接管理) 19 | - [查看HDC版本](#查看hdc版本) 20 | - [启动/停止 HDC Server](#启动停止-hdc-server) 21 | - [查询设备列表](#查询设备列表) 22 | - [查询设备UDID](#查询设备udid) 23 | - [重启手机](#重启手机) 24 | - [查看设备信息](#查看设备信息) 25 | - [名称](#名称) 26 | - [Brand](#brand) 27 | - [Model](#model) 28 | - [系统版本](#系统版本) 29 | - [OS版本](#os版本) 30 | - [CPU架构](#cpu架构) 31 | - [分辩率](#分辩率) 32 | - [wlan IP](#wlan-ip) 33 | - [电量/温度](#电量温度) 34 | - [查看屏幕信息](#查看屏幕信息) 35 | - [查看屏幕旋转状态](#查看屏幕旋转状态) 36 | - [查看屏幕亮屏状态](#查看屏幕亮屏状态) 37 | - [点亮屏幕(唤醒)](#点亮屏幕唤醒) 38 | - [查看网络状态](#查看网络状态) 39 | - [应用管理](#应用管理) 40 | - [安装应用](#安装应用) 41 | - [卸载应用](#卸载应用) 42 | - [获取应用列表](#获取应用列表) 43 | - [启动应用](#启动应用) 44 | - [退出应用](#退出应用) 45 | - [获取应用版本](#获取应用版本) 46 | - [Dump应用信息](#dump应用信息) 47 | - [获取应用 Ability信息](#获取应用-ability信息) 48 | - [获取应用详情](#获取应用详情) 49 | - [清除应用数据](#清除应用数据) 50 | - [清除应用缓存](#清除应用缓存) 51 | - [清除应用数据](#清除应用数据-1) 52 | - [显示可调试应用列表](#显示可调试应用列表) 53 | - [端口转发](#端口转发) 54 | - [显示端口转发列表](#显示端口转发列表) 55 | - [本地端口转发到手机](#本地端口转发到手机) 56 | - [删除端口转发任务](#删除端口转发任务) 57 | - [无线调试](#无线调试) 58 | - [文件传输](#文件传输) 59 | - [从本地电脑发送文件至手机](#从本地电脑发送文件至手机) 60 | - [从手机拷贝文件至本地电脑](#从手机拷贝文件至本地电脑) 61 | - [UI模拟操作(点击滑动等)](#ui模拟操作点击滑动等) 62 | - [屏幕截图](#屏幕截图) 63 | - [屏幕录屏](#屏幕录屏) 64 | - [打开Scheme (URL)](#打开scheme-url) 65 | - [获取页面布局信息(控件树)](#获取页面布局信息控件树) 66 | - [录制用户操作](#录制用户操作) 67 | - [系统日志(log)](#系统日志log) 68 | - [导出日志](#导出日志) 69 | - [导出crash日志](#导出crash日志) 70 | - [hidumper工具](#hidumper工具) 71 | - [list system abilities](#list-system-abilities) 72 | - [RenderService](#renderservice) 73 | - [DisplayManagerService](#displaymanagerservice) 74 | - [PowerManagerService](#powermanagerservice) 75 | - [BatteryService](#batteryservice) 76 | - [NetConnManager](#netconnmanager) 77 | - [MemoryManagerService](#memorymanagerservice) 78 | - [StorageManager](#storagemanager) 79 | - [aa工具](#aa工具) 80 | - [start](#start) 81 | - [stop-service](#stop-service) 82 | - [force-stop](#force-stop) 83 | - [test](#test) 84 | - [attach](#attach) 85 | - [detach](#detach) 86 | - [appdebug](#appdebug) 87 | - [bm工具](#bm工具) 88 | - [install](#install) 89 | - [uninstall](#uninstall) 90 | - [dump](#dump) 91 | - [clean](#clean) 92 | - [enable](#enable) 93 | - [disable](#disable) 94 | - [get](#get) 95 | - [param工具](#param工具) 96 | - [Instrument Test](#instrument-test) 97 | - [性能工具](#性能工具) 98 | - [参考链接](#参考链接) 99 | 100 | 101 | 102 | # HDC安装 103 | - 下载 [Command Line Tools](https://developer.huawei.com/consumer/cn/download/) 并解压 104 | - `hdc`文件在`command-line-tools/sdk/default/openharmony/toolchains`目录下 105 | 106 | - 配置电脑环境变量,以macOS为例,在`~/.bash_profile` 或者 `~/.zshrc`文件中添加如下内容: 107 | ``` 108 | export HM_SDK_HOME="/Users/develop/command-line-tools/sdk/default" //请以sdk实际安装目录为准 109 | export PATH=$PATH:$HM_SDK_HOME/hms/toolchains:$HM_SDK_HOME/openharmony/toolchains 110 | export HDC_SERVER_PORT=7035 111 | ``` 112 | 也可以自行编译安装:参考鸿蒙官方gitee文档 113 | 114 | # 基本用法 115 | ## 基本语法 116 | ```shell 117 | hdc -t 118 | ``` 119 | 如果只有一个设备/模拟器连接时,可以省略掉`-t ` 这一部分,直接使用`hdc `。在多个设备/模拟器连接的情况下需要指定`-t` 参数, `connectKey`可以通过`hdc list targets`命令获取,对应Android里的`adb devices`获取的`serialNumber`。 120 | ```shell 121 | $ hdc list targets 122 | 123 | 127.0.0.1:5555 //:形式的connectKey ,一般为无线连接的设备或模拟器 124 | FMR0223C13000649 125 | ``` 126 | 127 | 128 | 比如给`FMR0223C13000649` 这个设备安装应用: 129 | ```shell 130 | $ hdc -t FMR0223C13000649 install entry-default-signed.hap 131 | 132 | [Info]App install path:/Users/develop/entry-default-signed.hap, queuesize:0, msg:install bundle successfully. 133 | AppMod finish 134 | ``` 135 | 136 | **注意事项** 137 | 138 | - 使用`hdc`,如果出现异常,可以尝试通过`hdc kill -r`命令杀掉并重启hdc服务。 139 | - 如果出现`hdc list targets`获取不到设备信息的情况,可以通过任务管理器查看是否有hdc进程存在。若进程存在,则通过`hdc kill -r`命令杀掉该进程。 140 | 141 | # 设备连接管理 142 | ## 查看HDC版本 143 | ```shell 144 | $ hdc -v 145 | 146 | Ver: 2.0.0a 147 | ``` 148 | 149 | 150 | ## 启动/停止 HDC Server 151 | 停止 152 | ```shell 153 | $ hdc kill 154 | 155 | Kill server finish 156 | ``` 157 | 158 | 重启 159 | ```shell 160 | $ hdc start -r 161 | ``` 162 | 163 | ## 查询设备列表 164 | ``` 165 | $ hdc list targets 166 | 167 | 127.0.0.1:5555 168 | FMR0223C13000649 169 | ``` 170 | 171 | `-v` 选项 显示详细信息 172 | ``` 173 | $ hdc list targets -v 174 | 175 | 127.0.0.1:5555 TCP Connected localhost 176 | FMR0223C13000649 USB Connected unknown... 177 | ``` 178 | 179 | 输出的内容第一列为设备的`connectKey`, 第二列是设备`连接方式`,第三列为设备`连接状态`,第四列暂时未知 180 | 181 | ## 查询设备UDID 182 | ```shell 183 | $ hdc shell bm get --udid 184 | 185 | udid of current device is : 186 | C46284C052AE01BBD2358FE44B279524B508FC959AAB5F4B0B74E42A06569B7E 187 | ``` 188 | 189 | 这个`udid`在用开发者账号打包时,需要添加这个`udid`到对应的`profile`文件中 190 | 191 | ## 重启手机 192 | ```shell 193 | $ hdc target boot 194 | 195 | ``` 196 | 197 | 198 | # 查看设备信息 199 | 200 | ## 名称 201 | ```shell 202 | $ hdc shell param get const.product.name 203 | 204 | HUAWEI Mate 60 Pro 205 | ``` 206 | ## Brand 207 | ```shell 208 | $ hdc shell param get const.product.brand 209 | 210 | HUAWEI 211 | ``` 212 | ## Model 213 | ```shell 214 | $ hdc shell param get const.product.model 215 | 216 | ALN-AL00 217 | ``` 218 | ## 系统版本 219 | ```shell 220 | $ hdc shell param get const.product.software.version 221 | 222 | ALN-AL00 5.0.0.22(SP35DEVC00E22R4P1log) 223 | ``` 224 | 225 | ## OS版本 226 | ```shell 227 | $ hdc shell param get const.ohos.apiversion 228 | 229 | 12 230 | ``` 231 | 232 | ## CPU架构 233 | ```shell 234 | $ hdc shell param get const.product.cpu.abilist 235 | 236 | arm64-v8a 237 | ``` 238 | ## 分辩率 239 | ```shell 240 | $ hdc shell hidumper -s RenderService -a screen 241 | 242 | 243 | -------------------------------[ability]------------------------------- 244 | 245 | 246 | ----------------------------------RenderService--------------------------------- 247 | -- ScreenInfo 248 | screen[0]: id=0, powerstatus=POWER_STATUS_OFF, backlight=51, screenType=EXTERNAL_TYPE, render size: 1260x2720, physical screen resolution: 1260x2720, isvirtual=false, skipFrameInterval_:1 249 | 250 | supportedMode[0]: 1260x2720, refreshrate=120 251 | supportedMode[1]: 1260x2720, refreshrate=90 252 | supportedMode[2]: 1260x2720, refreshrate=60 253 | supportedMode[3]: 1260x2720, refreshrate=30 254 | activeMode: 1260x2720, refreshrate=60 255 | capability: name=, phywidth=72, phyheight=156,supportlayers=12, virtualDispCount=0, propCount=0, type=DISP_INTF_HDMI, supportWriteBack=false 256 | ``` 257 | 258 | 执行上述命令后,解析返回内容,可以通过正则表达式提取`1260x2720` 259 | 260 | ## wlan IP 261 | ```shell 262 | $ hdc shell ifconfig 263 | 264 | lo Link encap:Local Loopback 265 | inet addr:127.0.0.1 Mask:255.0.0.0 266 | UP LOOPBACK RUNNING MTU:65536 Metric:1 267 | RX packets:99055 errors:0 dropped:0 overruns:0 frame:0 268 | TX packets:99055 errors:0 dropped:0 overruns:0 carrier:0 269 | collisions:0 txqueuelen:1000 270 | RX bytes:5889697 TX bytes:5889697 271 | 272 | wlan0 Link encap:Ethernet HWaddr ea:f9:7d:21:52:31 273 | inet addr:172.31.125.111 Bcast:172.31.125.255 Mask:255.255.254.0 274 | UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 275 | RX packets:1232924 errors:0 dropped:0 overruns:0 frame:0 276 | TX packets:2061202 errors:0 dropped:0 overruns:0 carrier:0 277 | collisions:0 txqueuelen:1000 278 | RX bytes:877179224 TX bytes:2570352818 279 | 280 | p2p0 Link encap:Ethernet HWaddr d2:0d:f7:cc:12:fb 281 | UP BROADCAST MULTICAST MTU:1500 Metric:1 282 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0 283 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 284 | collisions:0 txqueuelen:1000 285 | RX bytes:0 TX bytes:0 286 | 287 | chba0 Link encap:Ethernet HWaddr ec:11:05:fb:18:66 288 | UP BROADCAST MULTICAST MTU:1500 Metric:1 289 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0 290 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 291 | collisions:0 txqueuelen:1000 292 | RX bytes:0 TX bytes:0 293 | ``` 294 | 295 | 注意:这个命令在Beta3版本之前,会提示`Cannot open netlink socket: Permission denied`,需要升级系统。 296 | 297 | ## 电量/温度 298 | 299 | ```shell 300 | $ hdc shell hidumper -s BatteryService -a -i 301 | 302 | -------------------------------[ability]------------------------------- 303 | 304 | 305 | ----------------------------------BatteryService--------------------------------- 306 | Current time: 2024-05-30 12:08:37.419 307 | capacity: 100 308 | batteryLevel: 1 309 | chargingStatus: 3 310 | healthState: 1 311 | pluggedType: 1 312 | voltage: 4496732 313 | present: 1 314 | technology: Li-poly 315 | nowCurrent: 123 316 | currentAverage: 83 317 | totalEnergy: 5203 318 | remainingEnergy: 5207 319 | remainingChargeTime: 0 320 | temperature: 280 321 | chargeType: 1 322 | ``` 323 | 324 | ## 查看屏幕信息 325 | ```shell 326 | $ hdc shell hidumper -s DisplayManagerService -a -a 327 | 328 | -------------------------------[ability]------------------------------- 329 | 330 | 331 | ----------------------------------DisplayManagerService---------------------------------- 332 | -------------- DMS Multi User Info -------------- 333 | [oldScbPid:] 334 | [userId:] 100 335 | [ScbPid:] 4438 336 | ---------------- Screen ID: 0 ---------------- 337 | FoldStatus: UNKNOWN 338 | [SCREEN SESSION] 339 | Name: UNKNOWN 340 | RSScreenId: 0 341 | activeModes: 0, 1260, 2720, 120 342 | SourceMode: 0 343 | ScreenCombination: 0 344 | Orientation: 0 345 | Rotation: 0 346 | ScreenRequestedOrientation: 0 347 | [RS INFO] 348 | SupportedColorGamuts: 0, 4, 6 349 | ScreenColorGamut: 4 350 | GraphicPixelFormat: 0 351 | SupportedScreenHDRFormat: 2, 1, 3 352 | ScreenHDRFormat: 2 353 | SupportedColorSpaces: 0, 2294273, 2294278 354 | ScreenColorSpace: 2294273 355 | [CUTOUT INFO] 356 | WaterFall_L: 0, 0, 0, 0 357 | WaterFall_T: 0, 0, 0, 0 358 | WaterFall_R: 0, 0, 0, 0 359 | WaterFall_B: 0, 0, 0, 0 360 | BoundingRects: [494, 36, 273, 72] 361 | [SCREEN INFO] 362 | VirtualWidth: 387 363 | VirtualHeight: 836 364 | LastParentId: 18446744073709551615 365 | ParentId: 1 366 | IsScreenGroup: 0 367 | VirtualPixelRatio: 3.25 368 | Rotation: 0 369 | Orientation: 0 370 | SourceMode: 0 371 | ScreenType: 1 372 | [SCREEN PROPERTY] 373 | Rotation: 0 374 | Density: 3.25 375 | DensityInCurResolution: 3.25 376 | PhyWidth: 72 377 | PhyHeight: 156 378 | RefreshRate: 60 379 | VirtualPixelRatio: 3.25 380 | ScreenRotation: 0 381 | Orientation: 0 382 | DisplayOrientation: 0 383 | GetScreenType: 1 384 | ReqOrientation: 0 385 | DPI: 444.5, 442.871 386 | Offset: 0, 0 387 | Bounds: 0, 0, 1260, 2720, 388 | PhyBounds: 0, 0, 1260, 2720, 389 | AvailableArea 0, 0, 1260, 2720, 390 | DefaultDeviceRotationOffset 0 391 | ``` 392 | 393 | 执行上述命令后,解析返回内容,通过正则提取需要的信息,比如屏幕尺寸分辨率Bounds,VirtualWidth,VirtualHeight,PhyWidth,PhyHeight,ScreenRotation 394 | 395 | ## 查看屏幕旋转状态 396 | 397 | ```shell 398 | $ hdc shell hidumper -s DisplayManagerService -a -a 399 | ``` 400 | 通过上面的查看屏幕信息命令,通过正则提取ScreenRotation字段即可,ScreenRotation有四个值: 401 | - 0:未旋转 402 | - 90:顺时针旋转90度 403 | - 180:顺时针旋转180度 404 | - 270:顺时针旋转270度 405 | 406 | 备注:目前旋转状态只能查看,不支持设置 407 | 408 | ## 查看屏幕亮屏状态 409 | ```shell 410 | $ hdc shell hidumper -s PowerManagerService -a -s 411 | 412 | -------------------------------[ability]------------------------------- 413 | 414 | 415 | ----------------------------------PowerManagerService---------------------------------- 416 | POWER STATE DUMP: 417 | Current State: AWAKE Reason: 20 Time: 521085695 418 | ScreenOffTime: Timeout=600000ms 419 | DUMP DETAILS: 420 | Last Screen On: 521248337 421 | Last Screen Off: 467804783 422 | Last SuspendDevice: 0 423 | Last WakeupDevice: 464729447 424 | Last Refresh: 521248337 425 | DUMP EACH STATES: 426 | State: AWAKE Reason: POWER_KEY Time: 521085695 427 | Failure: INIT Reason: From: AWAKE Time: 0 428 | 429 | State: FREEZE Reason: INIT Time: 0 430 | Failure: INIT Reason: From: AWAKE Time: 0 431 | 432 | State: INACTIVE Reason: TIMEOUT Time: 467805109 433 | Failure: INIT Reason: From: AWAKE Time: 0 434 | 435 | State: STAND_BY Reason: INIT Time: 0 436 | Failure: INIT Reason: From: AWAKE Time: 0 437 | 438 | State: DOZE Reason: INIT Time: 0 439 | Failure: INIT Reason: From: AWAKE Time: 0 440 | 441 | State: SLEEP Reason: TIMEOUT Time: 467810120 442 | Failure: INIT Reason: From: AWAKE Time: 0 443 | 444 | State: HIBERNATE Reason: INIT Time: 0 445 | Failure: INIT Reason: From: AWAKE Time: 0 446 | 447 | State: SHUTDOWN Reason: INIT Time: 0 448 | Failure: INIT Reason: From: AWAKE Time: 0 449 | 450 | State: DIM Reason: TIMEOUT Time: 467797280 451 | Failure: TIMEOUT Reason: Blocked by running lock From: AWAKE Time: 447180354 452 | ``` 453 | 屏幕状态有这几种: 454 | - INACTIVE 455 | - SLEEP 456 | - AWAKE 457 | 458 | 459 | ## 点亮屏幕(唤醒) 460 | ```shell 461 | $ hdc shell power-shell wakeup 462 | 463 | WakeupDevice is called 464 | ``` 465 | 466 | ## 查看网络状态 467 | 468 | **联网状态** 469 | ```shell 470 | $ hdc shell hidumper -s NetConnManager 471 | 472 | -------------------------------[ability]------------------------------- 473 | 474 | 475 | ----------------------------------NetConnManager---------------------------------- 476 | Net connect Info: 477 | defaultNetSupplier_ is nullptr 478 | SupplierId: 479 | NetId: 0 480 | ConnStat: 0 481 | IsAvailable: 482 | IsRoaming: 0 483 | Strength: 0 484 | Frequency: 0 485 | LinkUpBandwidthKbps: 0 486 | LinkDownBandwidthKbps: 0 487 | Uid: 0 488 | Dns result Info: 489 | netId: 0 490 | totalReports: 2 491 | failReports: 2 492 | ``` 493 | 494 | **wifi信息** 495 | ```shell 496 | $ hdc shell hidumper -s WifiDevice 497 | 498 | -------------------------------[ability]------------------------------- 499 | 500 | 501 | ----------------------------------WifiDevice---------------------------------- 502 | WiFi active state: activated 503 | 504 | WiFi connection status: connected 505 | Connection.ssid: K-Lab 506 | Connection.bssid: cc:d0:**:**:**:e2 507 | Connection.rssi: -45 508 | Connection.band: 2.4GHz 509 | Connection.frequency: 2462 510 | Connection.linkSpeed: 156 511 | Connection.macAddress: ea:f9:**:**:**:31 512 | Connection.isHiddenSSID: false 513 | Connection.signalLevel: 4 514 | 515 | Country Code: CN 516 | ``` 517 | 518 | 519 | # 应用管理 520 | ## 安装应用 521 | ```shell 522 | $ hdc app install entry-default-signed.hap 523 | 524 | [Info]App install path:/Users/develop/entry-default-signed.hap, queuesize:0, msg:install bundle successfully. 525 | AppMod finish 526 | ``` 527 | 或者 528 | ```shell 529 | $ hdc install entry-default-signed.hap 530 | 531 | [Info]App install path:/Users/develop/entry-default-signed.hap, queuesize:0, msg:install bundle successfully. 532 | AppMod finish 533 | ``` 534 | 535 | 536 | ## 卸载应用 537 | ```shell 538 | $ hdc app uninstall com.kk.hmscrcpy 539 | 540 | [Info]App uninstall path:, queuesize:0, msg:uninstall bundle successfully. 541 | AppMod finish 542 | ``` 543 | 544 | 或者 545 | ```shell 546 | $ hdc uninstall com.kk.hmscrcpy 547 | 548 | [Info]App uninstall path:, queuesize:0, msg:uninstall bundle successfully. 549 | AppMod finish 550 | ``` 551 | 552 | 553 | ## 获取应用列表 554 | ```shell 555 | $ hdc shell bm dump -a 556 | 557 | ID: 100: 558 | com.huawei.associateassistant 559 | com.huawei.batterycare 560 | com.huawei.hmos.AutoRegService 561 | com.huawei.hmos.advisor 562 | com.huawei.hmos.advsecmode 563 | com.huawei.hmos.aibase 564 | com.huawei.hmos.aidataservice 565 | com.huawei.hmos.aidispatchservice 566 | com.huawei.hmos.ailife 567 | com.huawei.hmos.ailifesvc 568 | com.huawei.hmos.audioaccessorymanager 569 | com.huawei.hmos.authcredmgr 570 | ... 571 | ``` 572 | 573 | 574 | ## 启动应用 575 | 通过启动`Ability`来拉起`APP` 576 | ```shell 577 | hdc shell aa start -a {abilityName} -b {bundleName} 578 | 579 | ``` 580 | 581 | - 其中`bundleName`可以通过`hdc shell bm dump -a`获取 582 | 583 | - 其中`abilityName`可以通过如下命令获取(查看当前任务栈的ability信息) 584 | 585 | ```shell 586 | $ hdc shell aa dump -l # 运行命令前需要手动打开app 587 | 588 | User ID #100 589 | current mission lists:{ 590 | Mission ID #139 mission name #[#com.kuaishou.hmapp:kwai:EntryAbility] lockedState #0 mission affinity #[] 591 | AbilityRecord ID #55 592 | app name [com.kuaishou.hmapp] 593 | main name [EntryAbility] 594 | bundle name [com.kuaishou.hmapp] 595 | ability type [PAGE] 596 | state #FOREGROUND start time [152523] 597 | app state #FOREGROUND 598 | ready #1 window attached #0 launcher #0 599 | callee connections: 600 | isKeepAlive: false 601 | } 602 | ``` 603 | 里面的EntryAbility就是你要打开app的Ability名称 604 | 605 | ## 退出应用 606 | 强制退出应用 607 | ```shell 608 | hdc shell aa force-stop {bundleName} 609 | ``` 610 | 611 | - 其中`bundleName`可以通过`hdc shell bm dump -a`获取 612 | 613 | 614 | ## 获取应用版本 615 | ```shell 616 | $ hdc shell bm dump -n {bundleName} 617 | ``` 618 | 执行上述命令后,再解析json, 提取`versionName`字段即可 619 | 620 | 621 | ## Dump应用信息 622 | **aa dump** 623 | ```shell 624 | $ hdc shell aa dump -h 625 | 626 | usage: aa dump 627 | options list: 628 | -h, --help list available commands 629 | -a, --all dump all abilities 630 | -l, --mission-list dump mission list 631 | -i, --ability dump abilityRecordId 632 | -e, --extension dump elementName (FA: serviceAbilityRecords,Stage: ExtensionRecords) 633 | -p, --pending dump pendingWantRecordId 634 | -r, --process dump process 635 | -d, --data dump the data abilities 636 | -u, --userId userId 637 | -c, --client client 638 | -c, -u are auxiliary parameters and cannot be used alone 639 | ``` 640 | 641 | **bm dump** 642 | ```shell 643 | $ hdc shell bm dump -h 644 | 645 | usage: bm dump 646 | options list: 647 | -h, --help list available commands 648 | -a, --all list all bundles in system 649 | -n, --bundle-name list the bundle info by a bundle name 650 | -s, --shortcut-info list the shortcut info 651 | -d, --device-id specify a device id 652 | -u, --user-id specify a user id 653 | ``` 654 | 655 | ### 获取应用 Ability信息 656 | ```shell 657 | $ hdc shell aa dump -l //运行命令前需要手动打开app 658 | 659 | User ID #100 660 | current mission lists:{ 661 | Mission ID #139 mission name #[#com.kuaishou.hmapp:kwai:EntryAbility] lockedState #0 mission affinity #[] 662 | AbilityRecord ID #55 663 | app name [com.kuaishou.hmapp] 664 | main name [EntryAbility] 665 | bundle name [com.kuaishou.hmapp] 666 | ability type [PAGE] 667 | state #FOREGROUND start time [152523] 668 | app state #FOREGROUND 669 | ready #1 window attached #0 launcher #0 670 | callee connections: 671 | isKeepAlive: false 672 | } 673 | ``` 674 | 675 | 676 | ### 获取应用详情 677 | 678 | 查询该应用的详细信息 679 | 680 | ```shell 681 | $ hdc shell bm dump -n com.kuaishou.hmapp 682 | 683 | com.kuaishou.hmapp: 684 | { 685 | "appId": "com.kuaishou.hmapp_BIS88rItfUAk+V9Y4WZp2HgIZ/JeOgvEBkwgB/YyrKiwrWhje9Xn2F6Q7WKFVM22RdIR4vFsG14A7ombgQmIIxU=", 686 | "appIdentifier": "5765880207853819885", 687 | "appIndex": 0, 688 | "applicationInfo": { 689 | ... 690 | "applicationReservedFlag": 0, 691 | "arkNativeFileAbi": "", 692 | "arkNativeFilePath": "", 693 | "asanEnabled": false, 694 | "asanLogPath": "", 695 | "associatedWakeUp": false, 696 | "bundleName": "com.kuaishou.hmapp", 697 | "bundleType": 0, 698 | "cacheDir": "", 699 | "codePath": "/data/app/el1/bundle/public/com.kuaishou.hmapp", 700 | "compileSdkType": "HarmonyOS", 701 | "compileSdkVersion": "4.1.0.73", 702 | "cpuAbi": "arm64-v8a", 703 | "crowdtestDeadline": -1, 704 | "dataBaseDir": "/data/app/el2/database/com.kuaishou.hmapp", 705 | "dataDir": "", 706 | "debug": true, 707 | "description": "", 708 | "descriptionId": 0, 709 | "descriptionResource": { 710 | "bundleName": "com.kuaishou.hmapp", 711 | "id": 0, 712 | "moduleName": "kwai" 713 | }, 714 | "deviceId": "PHONE-001", 715 | "distributedNotificationEnabled": true, 716 | "enabled": true, 717 | "entityType": "unspecified", 718 | "entryDir": "", 719 | "entryModuleName": "", 720 | "fingerprint": "96C4B0B051421A56EC9117BC6E3CF093C428B6B6D59DA13205C29C9BDD39AE7C", 721 | ... 722 | "minCompatibleVersionCode": 999999, 723 | "moduleInfos": [ 724 | { 725 | "moduleName": "kwai", 726 | "moduleSourceDir": "", 727 | "preloads": [] 728 | } 729 | ], 730 | ... 731 | "userDataClearable": true, 732 | "vendor": "快手", 733 | "versionCode": 999999, 734 | "versionName": "12.2.40" 735 | }, 736 | "compatibleVersion": 40100011, 737 | "cpuAbi": "", 738 | "defPermissions": [], 739 | "description": "", 740 | "entryInstallationFree": false, 741 | "entryModuleName": "kwai", 742 | "gid": 20020014, 743 | "hapModuleInfos": [ 744 | ... 745 | ], 746 | "reqPermissions": [ 747 | "ohos.permission.ACCELEROMETER", 748 | "ohos.permission.GET_NETWORK_INFO", 749 | "ohos.permission.GET_WIFI_INFO", 750 | "ohos.permission.INTERNET", 751 | "ohos.permission.SET_NETWORK_INFO", 752 | "ohos.permission.STORE_PERSISTENT_DATA" 753 | ], 754 | ... 755 | "vendor": "快手", 756 | "versionCode": 999999, 757 | "versionName": "12.2.40" 758 | } 759 | ``` 760 | 通过这个命令可以获取到很多应用的关键信息,比如`reqPermissions`,`version`,`abilities`等等 761 | 762 | 763 | ## 清除应用数据 764 | ```shell 765 | $ hdc shell bm clean -h 766 | 767 | usage: bm clean 768 | options list: 769 | -h, --help list available commands 770 | -n, --bundle-name bundle name 771 | -c, --cache clean bundle cache files by bundle name 772 | -d, --data clean bundle data files by bundle name 773 | -u, --user-id specify a user id 774 | ``` 775 | 776 | 777 | ### 清除应用缓存 778 | ```shell 779 | $ hdc shell bm clean -n {bundleName} -c 780 | 781 | clean bundle cache files successfully. 782 | ``` 783 | 784 | 其中`bundleName`可以通过`hdc shell bm dump -a`获取, 比如`com.kuaishou.hmapp` 785 | 786 | ### 清除应用数据 787 | ```shell 788 | $ hdc shell bm clean -n {bundleName} -d 789 | ``` 790 | 791 | 792 | ## 显示可调试应用列表 793 | ```shell 794 | $ hdc jpid 795 | 796 | 2571 797 | 2633 798 | 2638 799 | 2658 800 | 2666 801 | 2691 802 | 2825 803 | 3310 804 | 3804 805 | 3977 806 | 30178 807 | 808 | $ hdc track-jpid 809 | 810 | 0000 811 | ``` 812 | - `jpid`显示可调试应用列表 813 | - `track-jpid`动态显示可调试应用列表。 814 | 815 | 816 | # 端口转发 817 | |命令| 说明| 818 | |---|---| 819 | |fport ls |展示全部“端口转发主机端口转发数据到设备侧端口”的转发任务| 820 | |fport local remote| 端口转发主机端口转发数据到设备侧端口| 821 | |fport rm local remote| 删除指定“端口转发主机端口转发数据到设备侧端口”的转发任务| 822 | |rport ls |展示全部“端口转发设备侧端口转发数据到主机端口”的转发任务| 823 | |rport local remote| 端口转发设备侧端口转发数据到主机端口| 824 | |rport rm local remote| 删除指定“端口转发设备侧端口转发数据到主机端口”的转发任务| 825 | 826 | ## 显示端口转发列表 827 | 展示电脑端口转发到手机端口的列表 828 | ```shell 829 | $ hdc fport ls 830 | 831 | FMR0223C13000649 tcp:7912 tcp:7912 [Forward] 832 | ``` 833 | 834 | ## 本地端口转发到手机 835 | 将本地电脑的`7913`端口转发到手机`7912`端口 836 | ```shell 837 | $ hdc fport tcp:7913 tcp:7912 838 | 839 | Forwardport result:OK 840 | ``` 841 | 842 | 这个命令非常实用,比如我再手机上实现了一个 `http`服务,没有这个命令前需要通过手机`ip:port`来访问,这就需要提前知道手机的`wlanIP`,执行这个命令后可以直接通过`localhost:localPort`来访问手机里的服务。 843 | 844 | 845 | ## 删除端口转发任务 846 | ```shell 847 | $ hdc fport rm tcp:7913 tcp:7912 848 | Remove forward ruler success, ruler:tcp:7913 tcp:7912 849 | 850 | $ hdc fport ls 851 | [Empty] 852 | ``` 853 | 854 | 同理,`rport`命令表示手机端口转发到电脑端口,我就不一一举例了. 855 | 856 | # 无线调试 857 | **方式一:通过手机ip进行连接** (这个方式需要手机和PC处于同一个局域网内) 858 | 1. 在手机上开启tcp端口 `hdc -t tmode port ` 859 | 2. 连接手机上的tcp端口 `hdc tconn :` 860 | 3. 关闭无线连接 `hdc -t tmode port close` 861 | 862 | 示例 863 | 864 | ```shell 865 | $ hdc -t FMR0223C13000649 tmode port 5555 866 | 867 | $ hdc tconn 172.31.124.84:5555 # 这个ip为手机的wlanIp 868 | Connect OK 869 | 870 | $ hdc list targets 871 | 172.31.124.84:5555 872 | FMR0223C13000649 873 | 874 | $ hdc -t 172.31.124.84:5555 tmode port close 875 | Set device run mode successful. 876 | ``` 877 | 878 | **方式二:通过PC的ip进行连接** (这个方式数据线不能拔掉) 879 | 1. 在手机上开启5555端口 `hdc -t tmode port ` 880 | 2. 将手机的端口转发到PC上 `hdc -t fport tcp: tcp:` 881 | 3. 连接PC上的端口 `hdc tconn 127.0.0.1:{host_port}` 882 | 4. 关闭无线连接 `hdc -t tmode port close` 883 | 884 | 示例 885 | 886 | ```shell 887 | $ hdc -t FMR0223C13000649 tmode port 5555 888 | 889 | $ hdc -t FMR0223C13000649 fport tcp:5556 tcp:5555 890 | Forwardport result:OK 891 | 892 | $ hdc tconn 127.0.0.1:5556 893 | Connect OK 894 | 895 | $ hdc list targets 896 | 127.0.0.1:5556 897 | FMR0223C13000649 898 | 899 | $ hdc -t FMR0223C13000649 tmode port close 900 | Set device run mode successful. 901 | ``` 902 | 903 | **!!注意!!** 方式二中,由于hdc服务只监听了127.0.0.1, 导致其他主机上无法访问,需要将端口再转发一下,可以用socat等工具进行转发 904 | ``` 905 | $ socat TCP-LISTEN:5557,fork TCP:localhost:5556 906 | ``` 907 | 908 | 然后在其他主机进行connect 909 | ``` 910 | $ hdc tconn :5557 911 | Connect OK 912 | ``` 913 | 914 | # 文件传输 915 | |命令| 说明| 916 | |--|--| 917 | |file send local remote| 从本地发送文件至远端设备| 918 | |file recv remote local| 从远端设备发送文件至本地| 919 | 920 | ## 从本地电脑发送文件至手机 921 | ```shell 922 | $ hdc file send ~/layout_407568854.json /data/local/tmp/layout_407568854.json 923 | 924 | FileTransfer finish, Size:71792, File count = 1, time:24ms rate:2991.33kB/s 925 | ``` 926 | 927 | 928 | ## 从手机拷贝文件至本地电脑 929 | ```shell 930 | $ hdc file recv /data/local/tmp/layout_407568854.json ~/layout_407568854.json 931 | 932 | [I][2024-05-28 20:15:45] HdcFile::TransferSummary success 933 | FileTransfer finish, Size:71792, File count = 1, time:12ms rate:5982.67kB/s 934 | ``` 935 | 936 | 937 | # UI模拟操作(点击滑动等) 938 | 支持操作类型:`点击` `双击` `长按` `慢滑` `快滑` `拖拽` `输入文字` `KeyEvent` 939 | | 配置参数名 | 配置参数含义 | 配置参数取值 | 示例 | 940 | |-------------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| 941 | | click | 模拟单击操作 | point_x (必选参数,点击x坐标点)
point_y (必选参数,点击y坐标点) | hdc shell uitest uiInput click point_x point_y | 942 | | doubleClick | 模拟双击操作 | point_x (必选参数,双击x坐标点)
point_y (必选参数,双击y坐标点) | hdc shell uitest uiInput doubleClick point_x point_y | 943 | | longClick | 模拟长按操作 | point_x (必选参数,长按x坐标点)
point_y (必选参数,长按y坐标点) | hdc shell uitest uiInput longClick point_x point_y | 944 | | fling | 模拟快滑操作 | from_x (必选参数,滑动起点x坐标)
from_y(必选参数,滑动起点y坐标)
to_x(必选参数,滑动终点x坐标)
to_y(必选参数,滑动终点y坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px) | hdc shell uitest uiInput fling from_x from_y to_x to_y swipeVelocityPps_ stepLength | 945 | | swipe | 模拟慢滑操作 | from_x (必选参数,滑动起点x坐标)
from_y(必选参数,滑动起点y坐标)
to_x(必选参数,滑动终点x坐标)
to_y(必选参数,滑动终点y坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s) | hdc shell uitest uiInput swipe from_x from_y to_x to_y swipeVelocityPps_ | 946 | | drag | 模拟拖拽操作 | from_x (必选参数,拖拽起点x坐标)
from_y(必选参数,拖拽起点y坐标)
to_x(必选参数,拖拽终点x坐标)
to_y(必选参数,拖拽终点y坐标)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s) | hdc shell uitest uiInput drag from_x from_y to_x to_y swipeVelocityPps_ | 947 | | dircFling | 模拟指定方向滑动操作 | direction (可选参数,滑动方向,可选值: [0,1,2,3], 滑动方向: [左,右,上,下],默认值: 0)
swipeVelocityPps_ (可选参数,滑动速度,取值范围: 200-40000, 默认值: 600, 单位: px/s)
stepLength(可选参数,滑动步长,默认值:滑动距离/50, 单位: px) | hdc shell uitest uiInput dircFling direction swipeVelocityPps_ stepLength | 948 | | inputText | 模拟输入框输入文本操作 | point_x (必选参数,输入框x坐标点)
point_y (必选参数,输入框y坐标点)
input(输入文本) | hdc shell uitest uiInput inputText point_x point_y text | 949 | | keyEvent | 模拟实体按键事件(如:键盘,电源键,返回上一级,返回桌面等),以及组合按键操作 | keyID (必选参数,实体按键对应ID)
keyID2 (可选参数,实体按键对应ID) | hdc shell uitest uiInput keyEvent keyID | 950 | 951 | **举例** 952 | ```shell 953 | //点击 954 | hdc shell uitest uiInput click 100 100 955 | 956 | //双击 957 | hdc shell uitest uiInput doubleClick 100 100 958 | 959 | //长按 960 | hdc shell uitest uiInput longClick 100 100 961 | 962 | //快滑 963 | hdc shell uitest uiInput fling 10 10 200 200 500 964 | 965 | //慢滑 966 | hdc shell uitest uiInput swipe 10 10 200 200 500 967 | 968 | //拖拽 969 | hdc shell uitest uiInput drag 10 10 100 100 500 970 | 971 | //左滑 972 | hdc shell uitest uiInput dircFling 0 500 973 | 974 | //右滑 975 | hdc shell uitest uiInput dircFling 1 600 976 | 977 | //上滑 978 | hdc shell uitest uiInput dircFling 2 979 | 980 | //下滑 981 | hdc shell uitest uiInput dircFling 3 982 | 983 | //输入框输入 984 | hdc shell uitest uiInput inputText 100 100 hello 985 | 986 | //返回主页 987 | hdc shell uitest uiInput keyEvent Home 988 | 989 | //返回上一步 990 | hdc shell uitest uiInput keyEvent Back 991 | 992 | //组合键粘贴操作 993 | hdc shell uitest uiInput keyEvent 2072 2038 994 | ``` 995 | 996 | 997 | `keyEvent`映射表可以参考这个文档:https://docs.openharmony.cn/pages/v4.1/en/application-dev/reference/apis-input-kit/js-apis-keycode.md 998 | 999 | 1000 | # 屏幕截图 1001 | hdc提供了两种截图命令 1002 | 1003 | 方式一 1004 | ```shell 1005 | $ hdc shell uitest screenCap 1006 | // 默认存储路径:/data/local/tmp,文件名:时间戳 + .png。 1007 | 1008 | $ hdc shell uitest screenCap -p /data/local/tmp/1.png 1009 | // 指定存储路径和文件名。 1010 | ``` 1011 | 1012 | 1013 | 【推荐】方式二 1014 | ```shell 1015 | $ hdc shell snapshot_display -f /data/local/tmp/2.jpeg 1016 | // 截图完成后可以通过 hdc file recv 命令导入到本地 1017 | ``` 1018 | 1019 | 方式二的截图性能效率远远高于方式一 1020 | 1021 | # 屏幕录屏 1022 | 相关hdc命令还未支持,官方在开发中。。。 1023 | 1024 | 我这边通过python脚本实现了录屏功能,使用方法如下 1025 | ```shell 1026 | cd awesome-hdc/scripts 1027 | pip3 install -r requirements.txt 1028 | 1029 | python3 screen_recroding.py 1030 | ``` 1031 | 1032 | # 打开Scheme (URL) 1033 | ```shell 1034 | $ hdc shell aa start -U http://www.baidu.com 1035 | start ability successfully. 1036 | 1037 | $ hdc shell aa start -U kwai://home 1038 | 1039 | ``` 1040 | 1041 | # 获取页面布局信息(控件树) 1042 | ```shell 1043 | $ hdc shell uitest dumpLayout -p {saveDumpPath} # 运行命令前需要手动打开app,进入对应页面 1044 | 1045 | DumpLayout saved to:/data/local/tmp/layout_407568854.json 1046 | ``` 1047 | - `-p`表示控件树保存的目录,如果不指定,则默认保存在手机的`/data/local/tmp`目录 1048 | `/data/local/tmp/layout_407568854.json`文件内容如下: 1049 | ```shell 1050 | { 1051 | "attributes": { 1052 | "accessibilityId": "", 1053 | "bounds": "[0,0][1260,2720]", 1054 | "checkable": "", 1055 | "checked": "", 1056 | "clickable": "", 1057 | "description": "", 1058 | "enabled": "", 1059 | "focused": "", 1060 | "hostWindowId": "", 1061 | "id": "", 1062 | "key": "", 1063 | "longClickable": "", 1064 | "origBounds": "", 1065 | "scrollable": "", 1066 | "selected": "", 1067 | "text": "", 1068 | "type": "" 1069 | }, 1070 | "children": [ 1071 | 1072 | ... 1073 | 1074 | ] 1075 | ``` 1076 | 1077 | 1078 | # 录制用户操作 1079 | 将当前界面操作记录到`/data/local/tmp/layout/record.csv`,结束录制操作使用`Ctrl+C`结束录制 1080 | ```shell 1081 | $ hdc shell uitest uiRecord record 1082 | 1083 | windowBounds : (0,0,1260,2720) 1084 | Current ForAbility :com.kuaishou.hmapp, EntryAbility 1085 | The result will be written in csv file at location: /data/local/tmp/layout/record.csv 1086 | Started Recording Successfully... 1087 | click , fingerNumber:1 , 1088 | finger1:click: at Point(x:557, y:1542) ; from Point(x:557, y:1542) to Point(x:557, y:1542) ; 1089 | click , fingerNumber:1 , 1090 | finger1:click: at Point(x:550, y:1638) ; from Point(x:550, y:1638) to Point(x:550, y:1638) ; 1091 | fling , fingerNumber:1 , 1092 | finger1:from Point(x:409, y:1916) to Point(x:370, y:1528) ; Off-hand speed:1415.42, Step length:34; 1093 | fling , fingerNumber:1 , 1094 | finger1:from Point(x:400, y:1886) to Point(x:389, y:1586) ; Off-hand speed:1995.97, Step length:31; 1095 | home , fingerNumber:1 , 1096 | finger1:from Widget(id: , type: Text, text: state: didAppear, 1097 | feedId: 5218827670987295481, 1098 | feedType: 3, 1099 | ServerExpTag: feed_photo|5218827670987295481|1499501607|1_u/2003373606202106162_bs54357, 1100 | ) ; to Point(x:615, y:2338) ; 1101 | ``` 1102 | 1103 | 支持两种方式查看数据: 1104 | - `uiRecord record`, 将事件的位置坐标写入文件 1105 | - `uiRecord read`, 将文件内容打印到控制台 1106 | 1107 | 录制完成后,再将`csv`文件拷贝到电脑上 1108 | ```shell 1109 | $ hdc file recv /data/local/tmp/layout/record.csv ~/record.csv 1110 | ``` 1111 | 1112 | `record`数据字段含义请参考如下示例数据 1113 | ```shell 1114 | { 1115 | "ABILITY": "com.ohos.launcher.MainAbility", // 前台应用界面 1116 | "BUNDLE": "com.ohos.launcher", // 操作应用 1117 | "CENTER_X": "", // 模拟捏合中心X, pinch事件 1118 | "CENTER_Y": "", // 模拟捏合中心Y, pinch事件 1119 | "EVENT_TYPE": "pointer", // 1120 | "LENGTH": "0", // 总体步长 1121 | "OP_TYPE": "click", //事件类型,当前支持点击、双击、长按、拖拽、捏合、滑动、抛滑动作录制 1122 | "VELO": "0.000000", // 离手速度 1123 | "direction.X": "0.000000",// 总体移动X方向 1124 | "direction.Y": "0.000000", // 总体移动Y方向 1125 | "duration": 33885000.0, // 手势操作持续时间 1126 | "fingerList": [{ 1127 | "LENGTH": "0", // 总体步长 1128 | "MAX_VEL": "40000", // 最大速度 1129 | "VELO": "0.000000", // 离手速度 1130 | "W1_BOUNDS": "{"bottom":361,"left":37,"right":118,"top":280}", // 起点控件bounds 1131 | "W1_HIER": "ROOT,3,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0", // 起点控件hierarchy 1132 | "W1_ID": "", // 起点控件id 1133 | "W1_Text": "", // 起点控件text 1134 | "W1_Type": "Image", // 起点控件类型 1135 | "W2_BOUNDS": "{"bottom":361,"left":37,"right":118,"top":280}", // 终点控件bounds 1136 | "W2_HIER": "ROOT,3,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0", // 终点控件hierarchy 1137 | "W2_ID": "", // 终点控件id 1138 | "W2_Text": "", // 终点控件text 1139 | "W2_Type": "Image", // 终点控件类型 1140 | "X2_POSI": "47", // 终点X 1141 | "X_POSI": "47", // 起点X 1142 | "Y2_POSI": "301", // 终点Y 1143 | "Y_POSI": "301", // 起点Y 1144 | "direction.X": "0.000000", // x方向移动量 1145 | "direction.Y": "0.000000" // Y方向移动量 1146 | }], 1147 | "fingerNumber": "1" //手指数量 1148 | } 1149 | ``` 1150 | 1151 | # 系统日志(log) 1152 | ```shell 1153 | $ hdc hilog -h 1154 | 1155 | Usage: 1156 | -h --help 1157 | Show all help information. 1158 | Show single help information with option: 1159 | query/clear/buffer/stats/persist/private/kmsg/flowcontrol/baselevel/domain/combo 1160 | Querying logs options: 1161 | No option performs a blocking read and keeps printing. 1162 | -x --exit 1163 | Performs a non-blocking read and exits when all logs in buffer are printed. 1164 | -a , --head= 1165 | Show n lines logs on head of buffer. 1166 | -z , --tail= 1167 | Show n lines logs on tail of buffer. 1168 | -t , --type= 1169 | Show specific type/types logs with format: type1,type2,type3 1170 | Don't show specific type/types logs with format: ^type1,type2,type3 1171 | Type coule be: app/core/init/kmsg, kmsg can't combine with others. 1172 | Default types are: app,core,init. 1173 | -L , --level= 1174 | Show specific level/levels logs with format: level1,level2,level3 1175 | Don't show specific level/levels logs with format: ^level1,level2,level3 1176 | Long and short level string are both accepted 1177 | Long level string coule be: DEBUG/INFO/WARN/ERROR/FATAL. 1178 | Short level string coule be: D/I/W/E/F. 1179 | Default levels are all levels. 1180 | -D , --domain= 1181 | Show specific domain/domains logs with format: domain1,domain2,doman3 1182 | Don't show specific domain/domains logs with format: ^domain1,domain2,doman3 1183 | Max domain count is 5. 1184 | See domain description at the end of this message. 1185 | -T , --tag= 1186 | Show specific tag/tags logs with format: tag1,tag2,tag3 1187 | Don't show specific tag/tags logs with format: ^tag1,tag2,tag3 1188 | Max tag count is 10. 1189 | -P , --pid= 1190 | Show specific pid/pids logs with format: pid1,pid2,pid3 1191 | Don't show specific domain/domains logs with format: ^pid1,pid2,pid3 1192 | Max pid count is 5. 1193 | -e , --regex= 1194 | Show the logs which match the regular expression . 1195 | -v , --format= 1196 | Show logs in different formats, options are: 1197 | color or colour display colorful logs by log level.i.e. 1198 | DEBUG INFO WARN ERROR FATAL 1199 | time format options are(single accepted): 1200 | time display local time, this is default. 1201 | epoch display the time from 1970/1/1. 1202 | monotonic display the cpu time from bootup. 1203 | time accuracy format options are(single accepted): 1204 | msec display time by millisecond, this is default. 1205 | usec display time by microsecond. 1206 | nsec display time by nanosecond. 1207 | year display the year when -v time is specified. 1208 | zone display the time zone when -v time is specified. 1209 | Different types of formats can be combined, such as: 1210 | -v color -v time -v msec -v year -v zone. 1211 | -r 1212 | Remove all logs in hilogd buffer, advanced option: 1213 | -t , --type= 1214 | Remove specific type/types logs in buffer with format: type1,type2,type3 1215 | Type coule be: app/core/init/kmsg. 1216 | Default types are: app,core 1217 | -g 1218 | Query hilogd buffer size, advanced option: 1219 | -t , --type= 1220 | Query specific type/types buffer size with format: type1,type2,type3 1221 | Type coule be: app/core/init/kmsg. 1222 | Default types are: app,core 1223 | -G , --buffer-size= 1224 | Set hilogd buffer size, could be number or number with unit. 1225 | Unit could be: B/K/M/G which represents Byte/Kilobyte/Megabyte/Gigabyte. 1226 | range: [64.0K,64.0K]. 1227 | Advanced option: 1228 | -t , --type= 1229 | Set specific type/types log buffer size with format: type1,type2,type3 1230 | Type coule be: app/core/init/kmsg. 1231 | Default types are: app,core 1232 | **It's a persistant configuration** 1233 | -s, --statistics 1234 | Query log statistic information. 1235 | Set param persist.sys.hilog.stats true to enable statistic. 1236 | Set param persist.sys.hilog.stats.tag true to enable statistic of log tag. 1237 | -S 1238 | Clear hilogd statistic information. 1239 | -w ,--write= 1240 | Log persistance task control, options are: 1241 | query query tasks informations 1242 | stop stop all tasks 1243 | start start one task 1244 | clear clear /data/log/hilog/hilog*.gz 1245 | Persistance task is used for saving logs in files. 1246 | The files are saved in directory: /data/log/hilog/ 1247 | Advanced options: 1248 | -f , --filename= 1249 | Set log file name, name should be valid of Linux FS. 1250 | -l , --length= 1251 | Set single log file size. could be number or number with unit. 1252 | Unit could be: B/K/M/G which represents Byte/Kilobyte/Megabyte/Gigabyte. 1253 | range: [64.0K, 512.0M]. 1254 | -n , --number 1255 | Set max log file numbers, log file rotate when files count over this number. 1256 | range: [2, 1000]. 1257 | -m ,--stream= 1258 | Set log file compressed algorithm, options are: 1259 | none write file with non-compressed logs. 1260 | zlib write file with zlib compressed logs. 1261 | -j , --jobid 1262 | Start/stop specific task of . 1263 | range: [10, 0xffffffff). 1264 | User can start task with options (t/L/D/T/P/e/v) as if using them when "Query logs" too. 1265 | **It's a persistant configuration** 1266 | -p , --privacy 1267 | Set HILOG api privacy formatter feature on or off. 1268 | **It's a temporary configuration, will be lost after reboot** 1269 | -k , --kmsg 1270 | Set hilogd storing kmsg log feature on or off 1271 | **It's a persistant configuration** 1272 | -Q 1273 | Set log flow-control feature on or off, options are: 1274 | pidon process flow control on 1275 | pidoff process flow control off 1276 | domainon domain flow control on 1277 | domainoff domain flow control off 1278 | **It's a temporary configuration, will be lost after reboot** 1279 | -b , --baselevel= 1280 | Set global loggable level to 1281 | Long and short level string are both accepted. 1282 | Long level string coule be: DEBUG/INFO/WARN/ERROR/FATAL/X. 1283 | Short level string coule be: D/I/W/E/F/X. 1284 | X means that loggable level is higher than the max level, no log could be printed. 1285 | Advanced options: 1286 | -D , --domain= 1287 | Set specific domain loggable level. 1288 | See domain description at the end of this message. 1289 | -T , --tag= 1290 | Set specific tag loggable level. 1291 | The priority is: tag level > domain level > global level. 1292 | **It's a temporary configuration, will be lost after reboot** 1293 | The first layer options can't be used in combination, ILLEGAL expamples: 1294 | hilog -S -s; hilog -w start -r; hilog -p on -k on -b D 1295 | 1296 | 1297 | Domain description: 1298 | Log type "core" & "init" are used for OS subsystems, the range is [0xd000000, 0xd0fffff] 1299 | Log type "app" is used for applications, the range is [0x0, 0xffff] 1300 | To reduce redundant info when printing logs, only last five hex numbers of domain are printed 1301 | So if user wants to use -D option to filter OS logs, user should add 0xD0 as prefix to the printed domain: 1302 | Exapmle: hilog -D 0xD0xxxxx 1303 | The xxxxx is the domain string printed in logs. 1304 | 1305 | 1306 | Dictionary description: 1307 | -d , --dictionary= 1308 | Set elf file path, name should be valid of Linux FS. 1309 | Rescan the elf file in the system to generate a full data dictionary file 1310 | 1311 | ``` 1312 | 1313 | # 导出日志 1314 | ```shell 1315 | $ hdc file recv data/log/hilog/ ./ 1316 | 1317 | ``` 1318 | # 导出crash日志 1319 | ```shell 1320 | hdc file recv data/log/faultlog/faultlogger/ ./ 1321 | 1322 | ``` 1323 | 1324 | # hidumper工具 1325 | ```shell 1326 | $ hdc shell hidumper -h 1327 | 1328 | usage: 1329 | -h |help text for the tool 1330 | -lc |a list of system information clusters 1331 | -ls |a list of system abilities 1332 | -c |all system information clusters 1333 | -c [base system] |system information clusters labeled "base" and "system" 1334 | -s |all system abilities 1335 | -s [SA0 SA1] |system abilities labeled "SA0" and "SA1" 1336 | -s [SA] -a ['-h'] |system ability labeled "SA" with arguments "-h" specified 1337 | -e |faultlogs of crash history 1338 | --net [pid] |dump network information; if pid is specified, dump traffic usage of specified pid 1339 | --storage [pid] |dump storage information; if pid is specified, dump /proc/pid/io 1340 | -p |processes information, include list and information of processes and threads 1341 | -p [pid] |dump threads under pid, includes smap, block channel, execute time, mountinfo 1342 | --cpuusage [pid] |dump cpu usage by processes and category; if PID is specified, dump category usage of specified pid 1343 | --cpufreq |dump real CPU frequency of each core 1344 | --mem [pid] |dump memory usage of total; dump memory usage of specified pid if pid was specified 1345 | --zip |compress output to /data/log/hidumper 1346 | --mem-smaps pid [-v] |display statistic in /proc/pid/smaps, use -v specify more details 1347 | --mem-jsheap pid [-T tid] [--gc] |triggerGC and dumpHeapSnapshot under pid and tid 1348 | ``` 1349 | 1350 | ## list system abilities 1351 | ```shell 1352 | $ hdc shell hidumper -ls 1353 | 1354 | System ability list: 1355 | SystemAbilityManager RenderService AbilityManagerService 1356 | DataObserverMgr UriPermissionMgr AccountMgr 1357 | BundleMgr FormMgr ApplicationManagerService 1358 | AccessibilityManagerService UserIdmService UserAuthService 1359 | AuthExecutorMgrService PinAuthService FaceAuthService 1360 | FingerprintAuthService WifiDevice WifiHotspot 1361 | WifiP2p WifiScan 1125 1362 | 1126 NetConnManager NetPolicyManager 1363 | NetStatsManager NetTetheringManager VPNManager 1364 | EthernetManager NetsysNative NetsysExtService 1365 | DistributedNet 1181 HiviewService 1366 | HiviewFaultLogger HiviewSysEventService 1204 1367 | XperfTraceService HiDumperService XpowerManager 1368 | HiDumperCpuService DistributedKvData ContinuationManagerService 1369 | ResourceSched BackgroundTaskManager WorkSchedule 1370 | ComponentSchedServer SocPerfService DeviceUsageStatistics 1371 | MemoryManagerService SuspendManager AbnormalEfficiencyManager 1372 | ConcurrentTaskService ResourceQuotaControl DeviceStandbyService 1373 | TaskHeartbeatMgrService 2901 DeviceStatusService 1374 | 2903 2904 2908 1375 | AudioDistributed PlayerDistributedService CameraService 1376 | AudioPolicyService AVSessionService AVCodecService 1377 | MediaKeySystemService MultimodalInput DistributedNotificationService 1378 | CommonEventService PowerManagerService BatteryService 1379 | ThermalService BatteryStatisticsService DisplayPowerManagerService 1380 | AccessTokenManagerService PrivacyManagerService KeystoreService 1381 | DeviceThreatDetectionService RiskAnalysisManagerService DataCollectManagerService 1382 | DlpCreService SensorService MiscDeviceService 1383 | PasteboardService TimeService InputMethodService 1384 | ScreenlockService WallpaperManagerService ParamWatcher 1385 | TelephonyCallManager TelephonyCellularCall TelephonyCellularData 1386 | TelephonySmsMms TelephonyStateRegistry TelephonyCoreService 1387 | 4011 TelephonyIms ModuleUpdateService 1388 | UsbService WindowManagerService DisplayManagerService 1389 | DSoftbus DeviceAuthService DeviceManagerService 1390 | StorageDaemon StorageManager HdfDeviceServiceManager 1391 | CloudFileDaemonService EcologicalRuleManager UiService 1392 | UiAppearanceService CaDaemon AssetService 1393 | 9527 65537 65570 1394 | 65728 65777 65830 1395 | 65850 65888 65904 1396 | 65926 65958 65962 1397 | 66070 66090 70633 1398 | ``` 1399 | 1400 | 获取到abilities后,就可以指定service获取相关的信息。 比如通过RenderService获取一些信息 1401 | ```shell 1402 | $ hdc shell hidumper -s RenderService 1403 | 1404 | -------------------------------[ability]------------------------------- 1405 | 1406 | 1407 | ----------------------------------RenderService--------------------------------- 1408 | ------Graphic2D--RenderSerice ------ 1409 | Usage: 1410 | h |help text for the tool 1411 | screen |dump all screen infomation in the system 1412 | surface |dump all surface information 1413 | composer fps |dump the fps info of composer 1414 | [surface name] fps |dump the fps info of surface 1415 | composer fpsClear |clear the fps info of composer 1416 | [windowname] fps |dump the fps info of window 1417 | [windowname] hitchs |dump the hitchs info of window 1418 | [surface name] fpsClear |clear the fps info of surface 1419 | nodeNotOnTree |dump nodeNotOnTree info 1420 | allSurfacesMem |dump surface mem info 1421 | RSTree |dump RSTree info 1422 | EventParamList |dump EventParamList info 1423 | allInfo |dump all info 1424 | dumpMem |dump Cache 1425 | trimMem cpu/gpu/shader |release Cache 1426 | surfacenode [id] |dump node info 1427 | fpsCount |dump the refresh rate counts info 1428 | clearFpsCount |clear the refresh rate counts info 1429 | ``` 1430 | 1431 | ## RenderService 1432 | **获取分辩率** 1433 | ```shell 1434 | $ hdc shell hidumper -s RenderService -a screen 1435 | 1436 | -------------------------------[ability]------------------------------- 1437 | 1438 | 1439 | ----------------------------------RenderService--------------------------------- 1440 | -- ScreenInfo 1441 | screen[0]: id=0, powerstatus=POWER_STATUS_OFF, backlight=21, screenType=EXTERNAL_TYPE, render size: 1260x2720, physical screen resolution: 1260x2720, isvirtual=false, skipFrameInterval_:1 1442 | 1443 | supportedMode[0]: 1260x2720, refreshrate=120 1444 | supportedMode[1]: 1260x2720, refreshrate=90 1445 | supportedMode[2]: 1260x2720, refreshrate=60 1446 | supportedMode[3]: 1260x2720, refreshrate=30 1447 | activeMode: 1260x2720, refreshrate=60 1448 | capability: name=, phywidth=72, phyheight=156,supportlayers=12, virtualDispCount=0, propCount=0, type=DISP_INTF_HDMI, supportWriteBack=false 1449 | ``` 1450 | 1451 | 1452 | **获取帧率** 1453 | 首先执行如下命令进入到shell环境 1454 | ```shell 1455 | $ hdc shell 1456 | ``` 1457 | 然后执行`hidumper [surface name] fps` , 例如`composer fps` 1458 | 1459 | ``` 1460 | $ hidumper -s RenderService -a "composer fps" 1461 | 1462 | -------------------------------[ability]------------------------------- 1463 | 1464 | 1465 | ----------------------------------RenderService--------------------------------- 1466 | 1467 | -- The recently fps records info of screens: 1468 | 1469 | The fps of screen [Id:0] is: 1470 | 107537646652857 1471 | 107537663200253 1472 | 107537679747128 1473 | 107537696352336 1474 | 107537712846086 1475 | 107537729390357 1476 | 107537745974211 1477 | 107537762468482 1478 | 107537779015357 1479 | 107537795561190 1480 | 107537812110148 1481 | 107537828651815 1482 | 107537845349732 1483 | ... 1484 | ``` 1485 | 1486 | ## DisplayManagerService 1487 | ```shell 1488 | $ hdc shell hidumper -s DisplayManagerService 1489 | 1490 | -------------------------------[ability]------------------------------- 1491 | 1492 | 1493 | ----------------------------------DisplayManagerService---------------------------------- 1494 | Usage: 1495 | -h |help text for the tool 1496 | -a |dump all screen information in the system 1497 | -z |switch to fold half status 1498 | -y |switch to expand status 1499 | -p |switch to fold status 1500 | -f |get to fold status 1501 | ``` 1502 | 1503 | 1504 | 1505 | ## PowerManagerService 1506 | ```shell 1507 | $ hdc shell hidumper -s PowerManagerService 1508 | 1509 | -------------------------------[ability]------------------------------- 1510 | 1511 | 1512 | ----------------------------------PowerManagerService---------------------------------- 1513 | Power manager dump options: 1514 | [-h] [-runninglock] 1515 | description of the cmd option: 1516 | -a: show dump info of all power modules. 1517 | -h: show this help. 1518 | -r: show the information of runninglock. 1519 | -s: show the information of power state machine. 1520 | -d: show power off dialog. 1521 | ``` 1522 | 1523 | 例如上文提到的获取屏幕状态 1524 | ```shell 1525 | $ hdc shell hidumper -s PowerManagerService -a -s 1526 | ``` 1527 | 1528 | ## BatteryService 1529 | ```shell 1530 | $ hdc shell hidumper -s BatteryService 1531 | 1532 | -------------------------------[ability]------------------------------- 1533 | 1534 | 1535 | ----------------------------------BatteryService---------------------------------- 1536 | Usage: 1537 | -h: dump help 1538 | -i: dump battery info 1539 | -u: unplug battery charging state 1540 | -r: reset battery state 1541 | --capacity : set battery capacity, the capacity range [0, 100] 1542 | --uevent : set battery uevent 1543 | ``` 1544 | 1545 | 例如上文提到的获取电量温度 1546 | ```shell 1547 | $ hdc shell hidumper -s BatteryService -a -i 1548 | ``` 1549 | 1550 | ## NetConnManager 1551 | 1552 | ```shell 1553 | $ hdc shell hidumper -s NetConnManager 1554 | 1555 | -------------------------------[ability]------------------------------- 1556 | 1557 | 1558 | ----------------------------------NetConnManager---------------------------------- 1559 | Net connect Info: 1560 | defaultNetSupplier_ is nullptr 1561 | SupplierId: 1562 | NetId: 0 1563 | ConnStat: 0 1564 | IsAvailable: 1565 | IsRoaming: 0 1566 | Strength: 0 1567 | Frequency: 0 1568 | LinkUpBandwidthKbps: 0 1569 | LinkDownBandwidthKbps: 0 1570 | Uid: 0 1571 | Dns result Info: 1572 | netId: 0 1573 | totalReports: 2 1574 | failReports: 2 1575 | ``` 1576 | 1577 | ## MemoryManagerService 1578 | ```shell 1579 | $ hdc shell hidumper -s MemoryManagerService 1580 | 1581 | -------------------------------[ability]------------------------------- 1582 | 1583 | 1584 | ----------------------------------MemoryManagerService---------------------------------- 1585 | Usage: 1586 | -h |help for memmgrservice dumper 1587 | -a |dump all info 1588 | -e |dump event observer 1589 | -r |dump reclaim info and adj 1590 | -c |dump config 1591 | -m |show malloc state 1592 | -minisys |show mini system information for each service 1593 | -s |show subscriber all the pid which can be reclaimed 1594 | -d {pid} {uid} {state} |trigger appstate change 1595 | 1596 | -t trigger memory onTrim: 1597 | -t 1 ---------------------- level_purgeable 1598 | -t 2 ---------------------- level_moderate 1599 | -t 3 ---------------------- level_low 1600 | -t 4 ---------------------- level_critical 1601 | 1602 | -f trigger purgeable memory Reclaim: 1603 | -f 1 --------------------- purg_heap all 1604 | -f 2 --------------------- purg_ashmem all 1605 | -f 3 --------------------- purg_subscriber all 1606 | -f 4 --------------------- purg all purgeable memory 1607 | -f 1 -id {uid} {size} ----- purg_heap by memCG and size(KB). if input uid is 0, reclaim system_lru 1608 | -f 2 -id {ashmId} {time} -- purg_ashmem by ashmId, which can get from /proc/purgeable_ashmem_trigger 1609 | -f 3 -id {pid} ------------ purg_subscriber by pid. if input pid is 0, recalim subscriber all 1610 | 1611 | Please check your command. 1612 | ``` 1613 | 1614 | 1615 | ## StorageManager 1616 | TODO 1617 | 1618 | 1619 | # aa工具 1620 | Ability assistant(Ability助手,简称为aa),是实现应用及测试用例启动功能的工具,为开发者提供基本的应用调试和测试能力,例如启动应用组件、强制停止进程、打印应用组件相关信息等。 1621 | 1622 | 1623 | ```shell 1624 | $ hdc shell aa help 1625 | usage: aa 1626 | These are common aa commands list: 1627 | help list available commands 1628 | start start ability with options 1629 | stop-service stop service with options 1630 | dump dump the ability info 1631 | force-stop force stop the process with bundle name 1632 | attach attach application to enter debug mdoe 1633 | detach detach application to exit debug mode 1634 | test start the test framework with options 1635 | appdebug set / cancel / get waiting debug status 1636 | ``` 1637 | 1638 | ## start 1639 | ## stop-service 1640 | ## force-stop 1641 | ## test 1642 | ## attach 1643 | ## detach 1644 | ## appdebug 1645 | 详细介绍请参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/aa-tool.md 1646 | 1647 | # bm工具 1648 | Bundle Manager(包管理工具,简称bm)是实现应用安装、卸载、更新、查询等功能的工具,bm为开发者提供基本的应用安装包的调试能力,例如:安装应用,卸载应用,查询安装包信息等。 1649 | ``` 1650 | $ hdc shell bm help 1651 | usage: bm 1652 | These are common bm commands list: 1653 | help list available commands 1654 | install install a bundle with options 1655 | uninstall uninstall a bundle with options 1656 | dump dump the bundle info 1657 | get obtain device udid 1658 | quickfix quick fix, including query and install 1659 | compile Compile the software package 1660 | dump-overlay dump overlay info of the specific overlay bundle 1661 | dump-target-overlay dump overlay info of the specific target bundle 1662 | dump-dependencies dump dependencies by given bundle name and module name 1663 | dump-shared dump inter-application shared library information by bundle name 1664 | clean clean the bundle data 1665 | ``` 1666 | 1667 | ## install 1668 | ## uninstall 1669 | ## dump 1670 | ## clean 1671 | ## enable 1672 | ## disable 1673 | ## get 1674 | 1675 | 详细介绍请参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/bm-tool.md 1676 | 1677 | # param工具 1678 | param是为开发人员提供用于操作系统参数的工具,该工具只支持标准系统。 1679 | ```shell 1680 | $ hdc shell param 1681 | Command list: 1682 | param ls [-r] [name] --display system parameter 1683 | param get [name] --get system parameter 1684 | param set name value --set system parameter 1685 | param wait name [value] [timeout] --wait system parameter 1686 | param dump [verbose] --dump system parameter 1687 | param shell [-p] [name] [-u] [username] [-g] [groupname] --shell system parameter 1688 | param save 1689 | ``` 1690 | 1691 | 详细介绍请参考文档:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/param-tool.md 1692 | 1693 | 1694 | # Instrument Test 1695 | 主要用来做APP 的UI自动化测试,将应用测试包安装到测试设备上,在cmd窗口中执行aa命令,完成对用例测试。 1696 | 1697 | `aa test`命令执行配置参数 1698 | 1699 | | 执行参数全写 | 执行参数缩写 | 执行参数含义 | 执行参数示例 | 1700 | |---------------|--------------|-------------------------------------------|-------------------------------------------------------------| 1701 | | --bundleName | -b | 应用 Bundle 名称 | -b com.test.example | 1702 | | --packageName | -p | 应用模块名,适用于 FA 模型应用 | -p com.test.example.entry | 1703 | | --moduleName | -m | 应用模块名,适用于 STAGE 模型应用 | -m entry | 1704 | | NA | -s | 特定参数,以 键值对方式传入 | -s unittest /ets/testrunner/OpenHarmonyTestRunner | 1705 | 1706 | 1707 | ```shell 1708 | $ hdc shell aa test -h 1709 | usage: aa test 1710 | options list: 1711 | -h, --help list available commands 1712 | -b -s unittest start the test framework with options 1713 | [-p ] the name of package with test-runner, required for the FA model 1714 | [-m ] the name of module with test-runner, required for the STAGE model 1715 | [-s class ] 1716 | [-s level ] 1717 | [-s size ] 1718 | [-s testType ] 1719 | [-s timeout ] 1720 | [-s ] 1721 | [-w ] 1722 | [-D] 1723 | ``` 1724 | 1725 | **举例** 1726 | ```shell 1727 | $ hdc shell aa test -b com.example.myapplication -m entry_test -s unittest /ets/testrunner/OpenHarmonyTestRunner -s class UiTestDemo timeout 15000 1728 | ``` 1729 | 查看测试结果 1730 | cmd模式执行过程,会打印如下相关日志信息。 1731 | ```shell 1732 | OHOS_REPORT_STATUS: class=testStop 1733 | OHOS_REPORT_STATUS: current=1 1734 | OHOS_REPORT_STATUS: id=JS 1735 | OHOS_REPORT_STATUS: numtests=447 1736 | OHOS_REPORT_STATUS: stream= 1737 | OHOS_REPORT_STATUS: test=stop_0 1738 | OHOS_REPORT_STATUS_CODE: 1 1739 | 1740 | OHOS_REPORT_STATUS: class=testStop 1741 | OHOS_REPORT_STATUS: current=1 1742 | OHOS_REPORT_STATUS: id=JS 1743 | OHOS_REPORT_STATUS: numtests=447 1744 | OHOS_REPORT_STATUS: stream= 1745 | OHOS_REPORT_STATUS: test=stop_0 1746 | OHOS_REPORT_STATUS_CODE: 0 1747 | OHOS_REPORT_STATUS: consuming=4 1748 | 1749 | OHOS_REPORT_RESULT: stream=Tests run: 447, Failure: 0, Error: 1, Pass: 201, Ignore: 245 1750 | OHOS_REPORT_CODE: 0 1751 | 1752 | OHOS_REPORT_RESULT: breakOnError model, Stopping whole test suite if one specific test case failed or error 1753 | OHOS_REPORT_STATUS: taskconsuming=16029 1754 | ``` 1755 | 1756 | # 性能工具 1757 | `SmartPerf`是一款基于系统开发的性能功耗测试工具,操作简单易用。工具可以检测性能、功耗相关指标,包括`FPS`、`CPU`、`GPU`、`RAM`、`Temp`等,通过量化的指标项了解应用性能状况。在开发过程中,使用的可能是有屏或无屏设备,对此`SmartPerf`提供了两种方式:分别是`SmartPerf-Device`和`SmartPerf-Daemon`。`SmartPerf-Device`适用于有屏设备,支持可视化操作。测试时是通过悬浮窗的开始和暂停来实时展示性能指标数据,保存后可生成数据报告,在报告中可分析各指标数据详情。`SmartPerf-Daemon`支持`shell命令行`方式,同时适用于有屏和无屏设备。 1758 | 1759 | - CPU:每秒读取一次设备节点下CPU大中小核的频点和各核使用率,衡量应用占用CPU资源的情况,占用过多的CPU资源会导致芯片发烫。 1760 | - GPU:每秒读取一次设备节点下GPU的频点和负载信息,衡量应用占用GPU资源的情况,当GPU占用过多时,会导致性能下降,应用程序的运行速度变慢。 1761 | - FPS:应用界面每秒刷新次数,衡量应用画面的流畅度,FPS越高表示图像流畅度越好,用户体验也越好。 1762 | - POWER:每秒读取一次设备节点下的电流及电压信息。 1763 | - TEMP:每秒读取一次设备节点下电池温度、系统芯片温度等信息。 1764 | - RAM:每秒读取一次应用进程的实际物理内存,衡量应用的内存占比情况。 1765 | - snapshot:每秒截取一张应用界面截图。 1766 | ```shell 1767 | $ hdc shell 1768 | 1769 | # SP_daemon 1770 | 1771 | // 查看daemon进程是否存在 1772 | # ps -ef | grep SP_daemon 1773 | root 1584 1 0 21:50:05 ? 00:00:00 SP_daemon 1774 | root 1595 1574 3 21:51:02 pts/0 00:00:00 grep SP_daemon 1775 | 1776 | ``` 1777 | 执行查看帮助命令 1778 | ```shell 1779 | # SP_daemon --help 1780 | OpenHarmony performance testing tool SmartPerf command-line version 1781 | Usage: SP_daemon [options] [arguments] 1782 | 1783 | options: 1784 | -N set the collection times(default value is 0) range[1,2147483647], for example: -N 10 1785 | -PKG set package name, must add, for example: -PKG ohos.samples.ecg 1786 | -c get device CPU frequency and CPU usage, process CPU usage and CPU load .. 1787 | -g get device GPU frequency and GPU load 1788 | -f get app refresh fps(frames per second) and fps jitters and refreshrate 1789 | -profilerfps get refresh fps and timestamp 1790 | -sections set collection time period(using with profilerfps) 1791 | -t get remaining battery power and temperature.. 1792 | -p get battery power consumption and voltage 1793 | -r get process memory and total memory 1794 | -snapshot get screen capture 1795 | -net get uplink and downlink traffic 1796 | -start collection start command 1797 | -stop collection stop command 1798 | -VIEW set layler, for example: -VIEW DisplayNode 1799 | -screen get screen resolution 1800 | -OUT set csv output path. 1801 | -d get device DDR information 1802 | -m get other memory 1803 | example: 1804 | SP_daemon -N 20 -c -g -t -p -r -m -net -snapshot -d 1805 | SP_daemon -N 20 -PKG ohos.samples.ecg -c -g -t -p -f -r -m -net -snapshot -d 1806 | SP_daemon -start -c 1807 | SP_daemon -stop 1808 | SP_daemon -screen 1809 | ``` 1810 | 1811 | 基于`hdc`命令行的`SmartPerf`性能工具使用详细文档参考这个:https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/application-test/smartperf-guidelines.md 1812 | 1813 | # 参考链接 1814 | - https://gitee.com/openharmony/developtools_hdc 1815 | - https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/ide-command-line-hdc-0000001237908229-V2#section116322265308 1816 | - https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/application-test/smartperf-guidelines.md 1817 | - https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/aa-tool.md 1818 | - https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/bm-tool.md 1819 | - https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/tools/param-tool.md 1820 | - https://github.com/mzlogin/awesome-adb 1821 | 1822 | 1823 | --------------------------------------------------------------------------------