1
1
# -*- coding: utf-8 -*-
2
- import re
3
2
import socket
4
3
import json
5
4
import time
6
5
import os
7
- import glob
6
+ import hashlib
8
7
import typing
9
- import subprocess
8
+ from typing import Optional
10
9
from datetime import datetime
11
10
from functools import cached_property
12
11
@@ -143,8 +142,7 @@ def invoke_captures(self, api: str, args: typing.List = []) -> HypiumResponse:
143
142
144
143
def start (self ):
145
144
logger .info ("Start HmClient connection" )
146
- self ._init_so_resource ()
147
- self ._restart_uitest_service ()
145
+ _UITestService (self .hdc ).init ()
148
146
149
147
self ._connect_sock ()
150
148
@@ -163,47 +161,79 @@ def release(self):
163
161
logger .error (f"An error occurred: { e } " )
164
162
165
163
def _create_hdriver (self ) -> DriverData :
166
- logger .debug ("create uitest driver" )
164
+ logger .debug ("Create uitest driver" )
167
165
resp : HypiumResponse = self .invoke ("Driver.create" ) # {"result":"Driver#0"}
168
166
hdriver : DriverData = DriverData (resp .result )
169
167
return hdriver
170
168
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 ]:
207
237
proc_pids = []
208
238
result = self .hdc .shell ("ps -ef" ).output .strip ()
209
239
lines = result .splitlines ()
@@ -215,23 +245,11 @@ def get_devicetest_proc_pid(self):
215
245
return proc_pids
216
246
217
247
def _kill_uitest_service (self ):
218
- for pid in self .get_devicetest_proc_pid ():
248
+ for pid in self ._get_uitest_pid ():
219
249
self .hdc .shell (f"kill -9 { pid } " )
220
250
logger .debug (f"Killed uitest process with PID { pid } " )
221
251
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