Skip to content

Commit

Permalink
use u2.jar instead of test apk
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Jul 8, 2024
1 parent 9b44181 commit fff8784
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 90 deletions.
1 change: 0 additions & 1 deletion uiautomator2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import logging
import os
import re
import string
import time
import warnings
from functools import cached_property
Expand Down
4 changes: 2 additions & 2 deletions uiautomator2/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ def cmd_init(args):
if serial:
d = u2.connect(serial)
logger.debug("install apk to %s", d.serial)
d._setup_apks()
d._setup_jar()

Check warning on line 26 in uiautomator2/__main__.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/__main__.py#L26

Added line #L26 was not covered by tests
else:
for dev in adbutils.adb.iter_device():
d = u2.connect(dev)
logger.debug("install apk to %s", d.serial)
d._setup_apks()
d._setup_jar()

Check warning on line 31 in uiautomator2/__main__.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/__main__.py#L31

Added line #L31 was not covered by tests


def cmd_purge(args):
Expand Down
116 changes: 29 additions & 87 deletions uiautomator2/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"""

import atexit
import re
import threading
import time
import logging
Expand Down Expand Up @@ -63,11 +62,9 @@ def kill(self):

def launch_uiautomator(dev: adbutils.AdbDevice) -> MockAdbProcess:
"""Launch uiautomator2 server on device"""
logger.debug("launch uiautomator")
dev.shell("am force-stop com.github.uiautomator")
dev.shell("am start -n com.github.uiautomator/.ToastActivity")
# use command to see if uiautomator is running: ps -A | grep uiautomator
conn = dev.shell("am instrument -w -r -e debug false -e class com.github.uiautomator.stub.Stub com.github.uiautomator.test/androidx.test.runner.AndroidJUnitRunner", stream=True)
command = "CLASSPATH=/data/local/tmp/u2.jar app_process / com.wetest.uia2.Main"
logger.debug("launch uiautomator with cmd: %s", command)
conn = dev.shell("CLASSPATH=/data/local/tmp/u2.jar app_process / com.wetest.uia2.Main", stream=True)

Check warning on line 67 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L65-L67

Added lines #L65 - L67 were not covered by tests
process = MockAdbProcess(conn)
return process

Expand Down Expand Up @@ -160,7 +157,7 @@ def __init__(self, dev: adbutils.AdbDevice) -> None:
self._process = None
self._lock = threading.Lock()
self._debug = False
self.start_uiautomator(_silent=True)
self.start_uiautomator()

Check warning on line 160 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L160

Added line #L160 was not covered by tests
atexit.register(self.stop_uiautomator, wait=False)

@property
Expand All @@ -171,117 +168,62 @@ def debug(self) -> bool:
def debug(self, value: bool):
self._debug = bool(value)

def start_uiautomator(self, _silent: bool = False):
try:
self._do_start_uiautomator(silent=_silent)
except APKSignatureError as e:
logger.debug("APkSignatureError: %s", e)
self._dev.uninstall("com.github.uiautomator")
self._dev.uninstall("com.github.uiautomator.test")
self._do_start_uiautomator(silent=_silent)

def _do_start_uiautomator(self, silent: bool):
def start_uiautomator(self):
"""
Start uiautomator2 server
Raises:
LaunchUiautomatorError: uiautomator2 server not ready
"""
with self._lock:
self._setup_apks()
self._setup_jar()

Check warning on line 179 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L179

Added line #L179 was not covered by tests
if self._process:
if self._process.pool() is not None:
self._process = None
if not self._check_alive():
self._process = launch_uiautomator(self._dev)
self._wait_ready(show_float_window=not silent)
self._wait_ready()

Check warning on line 185 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L185

Added line #L185 was not covered by tests

def _setup_apks(self):
def _setup_jar(self):
assets_dir = Path(__file__).parent / "assets"
main_apk = assets_dir / "app-uiautomator.apk"
test_apk = assets_dir / "app-uiautomator-test.apk"

logger.debug("use apk_version: %s", __apk_version__)
# install apk when not installed or version not match, dev version always keep
main_apk_info = self._dev.app_info("com.github.uiautomator")
if main_apk_info is None:
self._install_apk(main_apk)
elif main_apk_info.version_name != __apk_version__:
if re.match(r"([\d.]+)\-(\d+)\-\w+", main_apk_info.version_name) or "dirty" in main_apk_info.version_name:
logger.debug("skip version check for %s", main_apk_info.version_name)
elif is_version_compatiable(__apk_version__, main_apk_info.version_name):
logger.debug("apk version compatiable, expect %s, actual %s", __apk_version__, main_apk_info.version_name)
else:
logger.debug("apk version not ok, expect %s, actual %s", __apk_version__, main_apk_info.version_name)
self._dev.uninstall("com.github.uiautomator")
self._dev.uninstall("com.github.uiautomator.test")
self._install_apk(main_apk)
self._install_apk(test_apk)

if self._dev.app_info("com.github.uiautomator.test") is None:
self._install_apk(test_apk)

def _install_apk(self, apk_path: Path):
logger.debug("Install %s", apk_path)
self._dev.shell("mkdir -p /data/local/tmp/u2")
target_path = "/data/local/tmp/u2/" + apk_path.name
self._dev.push(apk_path, target_path)
# -r: replace
# -t: allow test packages
# -d: allow version code downgrade
self._dev.shell(['pm', 'install', '-r', '-t', '-d', target_path])
jar_path = assets_dir / "u2.jar"

Check warning on line 189 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L189

Added line #L189 was not covered by tests
# TODO: check if jar is up-to-date
self._dev.push(jar_path, "/data/local/tmp/u2.jar")

Check warning on line 191 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L191

Added line #L191 was not covered by tests

def _wait_instrument_ready(self, timeout: float):
"""wait until "INSTRUMENTATION_STATUS_CODE: 1" show up"""
deadline = time.time() + timeout
while time.time() < deadline:
output = self._process.output.decode("utf-8", errors="ignore")
if "does not have a signature matching the target" in output:
raise APKSignatureError("app-uiautomator.apk does not have a signature matching the target")
if "INSTRUMENTATION_STATUS: Error=" in output:
error_message = output[output.find("INSTRUMENTATION_STATUS: Error="):].splitlines()[0]
raise LaunchUiAutomationError(error_message, output)
if "INSTRUMENTATION_STATUS_CODE:" in output:
status_code = int(re.search(r"INSTRUMENTATION_STATUS_CODE: (-?\d+)", output).group(1))
if status_code == 1: # success
logger.debug("am instrument success, status_code: %d", status_code)
return
raise LaunchUiAutomationError("am instrument error", f'CODE:{status_code}', output)
if self._process.pool() is not None:
raise LaunchUiAutomationError("am instrument quit", output)
time.sleep(.5)
raise LaunchUiAutomationError("am instrument launch timeout", f"{timeout}s", output)
def _wait_ready(self, launch_timeout=30):
"""Wait until uiautomator2 server is ready"""
self._wait_app_process_ready(launch_timeout)

Check warning on line 195 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L195

Added line #L195 was not covered by tests

def _wait_stub_ready(self, timeout: float):
def _wait_app_process_ready(self, timeout: float):
"""
ERROR1:
[server] INFO: [UiAutomator2Server] Starting Server
java.lang.IllegalStateException: UiAutomationService android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy@5deffd5already registered!
NORMAL:
[server] INFO: [UiAutomator2Server] Starting Server
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
"""
deadline = time.time() + timeout
while time.time() < deadline:
output = self._process.output.decode("utf-8", errors="ignore")
if "already registered" in output:
raise AccessibilityServiceAlreadyRegisteredError("Possibly another UiAutomation service is running, you may find it output by \"adb shell ps -u shell\"",)
if self._process.pool() is not None:
raise LaunchUiAutomationError("uiautomator2 server quit", output)
raise LaunchUiAutomationError("u2.jar server quit", output)

Check warning on line 215 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L215

Added line #L215 was not covered by tests
if self._check_alive():
return
raise LaunchUiAutomationError("uiautomator2 server not ready")
time.sleep(.5)
raise LaunchUiAutomationError("u2.jar server not ready")

Check warning on line 219 in uiautomator2/core.py

View check run for this annotation

Codecov / codecov/patch

uiautomator2/core.py#L218-L219

Added lines #L218 - L219 were not covered by tests

def _check_alive(self) -> bool:
try:
response = _http_request(self._dev, "GET", "/ping")
return response.content == b"pong"
except HTTPError:
return False

def _wait_ready(self, launch_timeout=30, service_timeout=30, show_float_window: bool = True):
"""Wait until uiautomator2 server is ready"""
# wait am instrument start
self._wait_instrument_ready(launch_timeout)
self._dev.shell("am startservice -a com.github.uiautomator.ACTION_START")
if show_float_window:
# launch a toast window to make sure uiautomator is alive
logger.debug("show float window")
self._dev.shell("am start -n com.github.uiautomator/.ToastActivity -e showFloatWindow true")
self._wait_stub_ready(service_timeout)
time.sleep(1) # wait ATX goto background

def stop_uiautomator(self, wait=True):
with self._lock:
Expand Down

0 comments on commit fff8784

Please sign in to comment.