Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 43 additions & 11 deletions uiautomator2/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@
import atexit
import datetime
import hashlib
import json
import logging
import os
import threading
import time
import logging
import json
from http.client import HTTPConnection
from pathlib import Path
from typing import Any, Dict, Optional, Union

import adbutils
import requests

from uiautomator2.exceptions import HTTPTimeoutError, RPCInvalidError, RPCStackOverflowError, UiAutomationNotConnectedError, HTTPError, LaunchUiAutomationError, UiObjectNotFoundError, RPCUnknownError, APKSignatureError, AccessibilityServiceAlreadyRegisteredError
from uiautomator2.abstract import AbstractUiautomatorServer
from uiautomator2.exceptions import AccessibilityServiceAlreadyRegisteredError, APKSignatureError, HTTPError, \
HTTPTimeoutError, LaunchUiAutomationError, RPCInvalidError, RPCStackOverflowError, RPCUnknownError, \
UiAutomationNotConnectedError, UiObjectNotFoundError
from uiautomator2.utils import is_version_compatiable
from uiautomator2.version import __apk_version__


logger = logging.getLogger(__name__)

class MockAdbProcess:
Expand Down Expand Up @@ -84,18 +86,33 @@
return self.content.decode("utf-8", errors="ignore")


class AdbHTTPConnection(HTTPConnection):
def __init__(self, device: adbutils.AdbDevice, port=9008):
super().__init__("localhost", port)
self.__device = device
self.__port = port

Check warning on line 93 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L91-L93

Added lines #L91 - L93 were not covered by tests

def connect(self):
self.sock = self.__device.create_connection(adbutils.Network.TCP, self.__port)

Check warning on line 96 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L96

Added line #L96 was not covered by tests

def __enter__(self) -> HTTPConnection:
return self

Check warning on line 99 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L99

Added line #L99 was not covered by tests

def __exit__(self, exc_type, exc_value, traceback):
self.close()

Check warning on line 102 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L102

Added line #L102 was not covered by tests


def _http_request(dev: adbutils.AdbDevice, method: str, path: str, data: Dict[str, Any] = None, timeout=10, print_request: bool = False) -> HTTPResponse:
"""Send http request to uiautomator2 server"""
try:
logger.debug("http request %s %s %s", method, path, data)
lport = dev.forward_port(9008)
logger.debug("forward tcp:%d -> tcp:9008", lport)

# https://stackoverflow.com/questions/2386299/running-sites-on-localhost-is-extremely-slow
# so here use 127.0.0.1 instead of localhost
url = f"http://127.0.0.1:{lport}{path}"
if print_request:
start_time = datetime.datetime.now()
current_time = start_time.strftime("%H:%M:%S.%f")[:-3]
url = f"http://127.0.0.1:9008{path}"

Check warning on line 115 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L115

Added line #L115 was not covered by tests
fields = [current_time, f"$ curl -X {method}", url]
if data:
fields.append(f"-d '{json.dumps(data)}'")
Expand All @@ -108,11 +125,26 @@
# https://blog.csdn.net/fcp12138/article/details/80436644
headers = {
'User-Agent': 'uiautomator2',
'Accept-Encoding': ''
'Accept-Encoding': '',
'Content-Type': 'application/json'
}
r = requests.request(method, url, json=data, timeout=timeout, headers=headers)
r.raise_for_status()
response = HTTPResponse(r.content)
conn = AdbHTTPConnection(dev, port=9008)
conn.timeout = timeout
try:

Check warning on line 133 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L131-L133

Added lines #L131 - L133 were not covered by tests
if not data:
conn.request(method, path, headers=headers)

Check warning on line 135 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L135

Added line #L135 was not covered by tests
else:
conn.request(method, path, json.dumps(data), headers=headers)

Check warning on line 137 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L137

Added line #L137 was not covered by tests
except adbutils.AdbError as e:
Copy link

Copilot AI Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be beneficial to log the exception details (e.g., using logger.error) before raising HTTPError for easier debugging of adb-related failures.

Suggested change
except adbutils.AdbError as e:
except adbutils.AdbError as e:
logger.error("AdbError occurred while making HTTP request through adb: %s", str(e))

Copilot uses AI. Check for mistakes.
raise HTTPError(f"Unable to make http request through adb")
_response = conn.getresponse()
content = bytearray()

Check warning on line 141 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L140-L141

Added lines #L140 - L141 were not covered by tests
while chunk := _response.read(4096):
content.extend(chunk)

Check warning on line 143 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L143

Added line #L143 was not covered by tests
if _response.status != 200:
raise HTTPError(f"HTTP request failed: {_response.status} {_response.reason}")
response = HTTPResponse(content)

Check warning on line 146 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L145-L146

Added lines #L145 - L146 were not covered by tests

if print_request:
end_time = datetime.datetime.now()
current_time = end_time.strftime("%H:%M:%S.%f")[:-3]
Expand Down
Loading