11# -*- coding: utf-8 -*-
2- import re
32import socket
43import json
54import time
65import os
7- import glob
6+ import hashlib
87import typing
9- import subprocess
8+ from typing import Optional
109from datetime import datetime
1110from functools import cached_property
1211
@@ -143,8 +142,7 @@ def invoke_captures(self, api: str, args: typing.List = []) -> HypiumResponse:
143142
144143 def start (self ):
145144 logger .info ("Start HmClient connection" )
146- self ._init_so_resource ()
147- self ._restart_uitest_service ()
145+ _UITestService (self .hdc ).init ()
148146
149147 self ._connect_sock ()
150148
@@ -163,47 +161,79 @@ def release(self):
163161 logger .error (f"An error occurred: { e } " )
164162
165163 def _create_hdriver (self ) -> DriverData :
166- logger .debug ("create uitest driver" )
164+ logger .debug ("Create uitest driver" )
167165 resp : HypiumResponse = self .invoke ("Driver.create" ) # {"result":"Driver#0"}
168166 hdriver : DriverData = DriverData (resp .result )
169167 return hdriver
170168
171- def _init_so_resource (self ):
172- "Initialize the agent.so resource on the device."
173-
174- file_postfix = ".so"
175- device_agent_path = "/data/local/tmp/agent.so"
176- arch_info = self .hdc .shell ("file /system/bin/uitest" ).output .strip ()
177- if "x86_64" in arch_info :
178- file_postfix = ".x86_64_so"
179- local_path = ""
180- local_ver = "0.0.0"
181- for agent_file in glob .glob (os .path .join (ASSETS_PATH , "uitest_agent*so" )):
182- file_name = os .path .split (agent_file )[1 ]
183- if not agent_file .endswith (file_postfix ):
184- continue
185- matcher = re .search (r'\d{1,3}[.]\d{1,3}[.]\d{1,3}' , file_name )
186- if not matcher :
187- continue
188- ver = matcher .group ()[0 ]
189- if ver .split ('.' ) > local_ver .split ('.' ):
190- local_ver , local_path = ver , agent_file
191- device_ver_info = self .hdc .shell (f"cat { device_agent_path } | grep -a UITEST_AGENT_LIBRARY" ).output .strip ()
192- matcher = re .search (r'\d{1,3}[.]\d{1,3}[.]\d{1,3}' , device_ver_info )
193- device_ver = matcher .group (0 ) if matcher else "0.0.0"
194- logger .debug (f"local agent version { local_ver } , device agent version { device_ver } " )
195- if device_ver .split ('.' ) < local_ver .split ('.' ):
196- logger .debug (f"start update agent, path is { local_path } " )
197- self ._kill_uitest_service ()
198- for file in AGENT_CLEAR_PATH :
199- self .hdc .shell (f"rm /data/local/tmp/{ file } *" )
200- self .hdc .send_file (local_path , device_agent_path )
201- self .hdc .shell (f"chmod +x { device_agent_path } " )
202- logger .debug ("Update agent finish." )
203- else :
204- logger .debug ("Device agent is up to date!" )
205-
206- def get_devicetest_proc_pid (self ):
169+
170+ class _UITestService :
171+ def __init__ (self , hdc : HdcWrapper ):
172+ """Initialize the UITestService class."""
173+ self .hdc = hdc
174+
175+ def init (self ):
176+ """
177+ Initialize the UITest service:
178+ 1. Ensure agent.so is set up on the device.
179+ 2. Start the UITest daemon.
180+
181+ Note: 'hdc shell aa test' will also start a uitest daemon.
182+ $ hdc shell ps -ef |grep uitest
183+ shell 44306 1 25 11:03:37 ? 00:00:16 uitest start-daemon singleness
184+ shell 44416 1 2 11:03:42 ? 00:00:01 uitest start-daemon com.hmtest.uitest@4x9@1"
185+ """
186+
187+ logger .debug ("Initializing UITest service" )
188+ local_path = self ._get_local_agent_path ()
189+ remote_path = "/data/local/tmp/agent.so"
190+
191+ self ._kill_uitest_service () # Stop the service if running
192+ self ._setup_device_agent (local_path , remote_path )
193+ self ._start_uitest_daemon ()
194+ time .sleep (0.5 )
195+
196+ def _get_local_agent_path (self ) -> str :
197+ """Return the local path of the agent file."""
198+ target_agent = "uitest_agent_v1.1.0.so"
199+ return os .path .join (os .path .dirname (os .path .realpath (__file__ )), "assets" , target_agent )
200+
201+ def _get_remote_md5sum (self , file_path : str ) -> Optional [str ]:
202+ """Get the MD5 checksum of a remote file."""
203+ command = f"md5sum { file_path } "
204+ output = self .hdc .shell (command ).output .strip ()
205+ return output .split ()[0 ] if output else None
206+
207+ def _get_local_md5sum (self , file_path : str ) -> str :
208+ """Get the MD5 checksum of a local file."""
209+ hash_md5 = hashlib .md5 ()
210+ with open (file_path , "rb" ) as f :
211+ for chunk in iter (lambda : f .read (4096 ), b"" ):
212+ hash_md5 .update (chunk )
213+ return hash_md5 .hexdigest ()
214+
215+ def _is_remote_file_exists (self , file_path : str ) -> bool :
216+ """Check if a file exists on the device."""
217+ command = f"[ -f { file_path } ] && echo 'exists' || echo 'not exists'"
218+ result = self .hdc .shell (command ).output .strip ()
219+ return "exists" in result
220+
221+ def _setup_device_agent (self , local_path : str , remote_path : str ):
222+ """Ensure the remote agent file is correctly set up."""
223+ if self ._is_remote_file_exists (remote_path ):
224+ local_md5 = self ._get_local_md5sum (local_path )
225+ remote_md5 = self ._get_remote_md5sum (remote_path )
226+ if local_md5 == remote_md5 :
227+ logger .debug ("Remote agent file is up-to-date" )
228+ self .hdc .shell (f"chmod +x { remote_path } " )
229+ return
230+ self .hdc .shell (f"rm { remote_path } " )
231+
232+ self .hdc .send_file (local_path , remote_path )
233+ self .hdc .shell (f"chmod +x { remote_path } " )
234+ logger .debug ("Updated remote agent file" )
235+
236+ def _get_uitest_pid (self ) -> typing .List [str ]:
207237 proc_pids = []
208238 result = self .hdc .shell ("ps -ef" ).output .strip ()
209239 lines = result .splitlines ()
@@ -215,23 +245,11 @@ def get_devicetest_proc_pid(self):
215245 return proc_pids
216246
217247 def _kill_uitest_service (self ):
218- for pid in self .get_devicetest_proc_pid ():
248+ for pid in self ._get_uitest_pid ():
219249 self .hdc .shell (f"kill -9 { pid } " )
220250 logger .debug (f"Killed uitest process with PID { pid } " )
221251
222- def _restart_uitest_service (self ):
223- """
224- Restart the UITest daemon.
225-
226- Note: 'hdc shell aa test' will also start a uitest daemon.
227- $ hdc shell ps -ef |grep uitest
228- shell 44306 1 25 11:03:37 ? 00:00:16 uitest start-daemon singleness
229- shell 44416 1 2 11:03:42 ? 00:00:01 uitest start-daemon com.hmtest.uitest@4x9@1"
230- """
231- try :
232- self ._kill_uitest_service ()
233- self .hdc .shell ("uitest start-daemon singleness" )
234- time .sleep (.5 )
235-
236- except subprocess .CalledProcessError as e :
237- logger .error (f"An error occurred: { e } " )
252+ def _start_uitest_daemon (self ):
253+ """Start the UITest daemon."""
254+ self .hdc .shell ("uitest start-daemon singleness" )
255+ logger .debug ("Started UITest daemon" )
0 commit comments