emulator.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import subprocess
  2. import time
  3. from model.custom_struct import EmulatorInfo
  4. from tools.utils import Utils
  5. class Emulator:
  6. def __init__(self, path):
  7. self.system_type = None
  8. self.emulator_type = None
  9. self.path = path
  10. def start(self, index: int) -> None:
  11. pass
  12. def close(self, index: int) -> None:
  13. pass
  14. def close_all(self):
  15. pass
  16. def add(self, name: str):
  17. pass
  18. def remove(self, index: int):
  19. pass
  20. def rename(self, index: int, name: str):
  21. pass
  22. def restore(self, index: int, backup_file: str):
  23. pass
  24. def get_info(self, index: int) -> EmulatorInfo:
  25. pass
  26. def get_list(self) -> list[EmulatorInfo]:
  27. pass
  28. def is_started(self, index) -> bool:
  29. pass
  30. @staticmethod
  31. def get_device_ip_by_index(index: int) -> str:
  32. pass
  33. @staticmethod
  34. def get_index_by_device_ip(device_ip: str) -> int:
  35. pass
  36. def is_exists(self, index: int) -> bool:
  37. pass
  38. def is_running(self, index: int) -> bool:
  39. pass
  40. def modify(self,**kwargs):
  41. pass
  42. def _execute_cmd(self, cmd: str, timeout=100) -> str:
  43. """
  44. 运行控制台命令。
  45. :param cmd: 要执行的命令。
  46. :param timeout: 超时时间(秒)。
  47. :return: 控制台输出。
  48. """
  49. # 拼接命令
  50. full_cmd = f'"{self.path}{cmd}'
  51. #logger.debug(f"cmd: {full_cmd}")
  52. try:
  53. result = subprocess.run(full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True,
  54. timeout=timeout)
  55. if result.returncode >= 0:
  56. return result.stdout
  57. else:
  58. raise RuntimeError(f"命令执行失败。错误信息: {result.stderr}")
  59. except subprocess.TimeoutExpired:
  60. raise RuntimeError(f"命令执行超时。超时时间: {timeout} 秒")
  61. except Exception as e:
  62. raise RuntimeError(f"执行命令时发生错误: {full_cmd}. 错误: {e}")
  63. def read_emulator_file(self, index: int, file_path: str) -> str:
  64. """
  65. 读取模拟器文本文件
  66. :param index: 模拟器索引
  67. :param file_path:模拟器文件路径
  68. :return:
  69. """
  70. return self.shell(index, f'cat {file_path}')
  71. def write_emulator_file(self, index: int, file_path: str, content: str) -> bool:
  72. """
  73. 写入模拟器文本文件
  74. :param index: 模拟器索引
  75. :param file_path:模拟器文件路径
  76. :param content: 写入内容
  77. :return:
  78. """
  79. return self.shell(index, f"echo '{content}' > {file_path}") == ''
  80. def start_and_confirm(self, index: int) -> (bool,EmulatorInfo | str):
  81. try:
  82. self.start(index)
  83. time.sleep(10)
  84. timer = int(time.time())
  85. while True:
  86. if int(time.time()) - timer > 90:
  87. return False ,f'start emulator {index}: Timeout'
  88. started, emulator_info = self.is_started(index)
  89. if started:
  90. return True, emulator_info
  91. time.sleep(5)
  92. except Exception as e:
  93. return False ,f'start emulator {index} error: {e}'
  94. def close_and_confirm(self, index: int) -> (bool,str):
  95. try:
  96. timer = int(time.time())
  97. while True:
  98. self.close(index)
  99. time.sleep(3)
  100. if int(time.time()) - timer > 30:
  101. return False,f'closing emulator {index}: Timeout'
  102. if self.get_info(index).pid == -1:
  103. return True,None
  104. time.sleep(1)
  105. except Exception as e:
  106. return False , f'An error occurred while closing emulator {index}: {e}'
  107. def start_app(self, index: int, package_name: str):
  108. pass
  109. def set_share_dir(self, index: int, share_dir: str, dir_type: int | None) -> bool:
  110. pass
  111. def get_share_dir(self, index: int) -> str:
  112. pass
  113. def get_config(self,index: int, key: str) -> str:
  114. pass
  115. def shell(self, index: int, cmd: str) -> str:
  116. pass
  117. def open_url(self, index: int, url: str):
  118. self.shell(index, f'am start -a android.intent.action.VIEW -d {url}')
  119. def get_manufacturer(self,index:int):
  120. pass
  121. def get_model(self,index:int):
  122. pass
  123. def get_android_version(self,index:int):
  124. pass
  125. def get_android_id(self, index:int):
  126. pass
  127. def get_IMEI(self, index:int):
  128. pass
  129. def get_IMSI(self, index:int):
  130. pass
  131. def get_mac(self, index:int):
  132. pass
  133. def get_sim_serial(self, index:int):
  134. pass
  135. def get_phone_number(self, index:int):
  136. pass
  137. def get_ip(self, index:int):
  138. pass
  139. def get_net_ip(self, index: int):
  140. url = 'http://sjyh.kfzs.com/api/app/shuyou/game_task/getIp'
  141. return self.shell(index, f'curl {url}')
  142. def get_idle_emulator(self) -> int:
  143. """
  144. 获取空闲模拟器的索引,如果没有符合条件的模拟器,则新建一个并等待。
  145. :return: 模拟器索引 (int)
  146. """
  147. if not self.is_exists(0):
  148. self.add('ld-0')
  149. time.sleep(1)
  150. while True:
  151. emulator_list = self.get_list()
  152. for emu in emulator_list:
  153. # 跳过无效的模拟器索引或正在运行的模拟器
  154. if emu.index == 0 or self.is_running(emu.index):
  155. continue
  156. # 如果是 'ys' 类型的模拟器,检查系统类型是否匹配
  157. if self.emulator_type == 'ys' and int(
  158. self.get_config(emu.index, 'system_type')) != self.system_type:
  159. continue
  160. return emu.index
  161. time.sleep(1)
  162. #没有找到空闲模拟器,添加新的模拟器
  163. self.add(f'new-{len(emulator_list)}')
  164. time.sleep(1)
  165. @staticmethod
  166. def set_emulator_position(emulator_hwnd: int, pos_index: int, screen_width=1920, screen_height=1080, width=312,
  167. height=516,
  168. retries=5):
  169. """设置模拟器位置"""
  170. max_column = int(screen_width / width)
  171. in_column = ((pos_index - 1) % max_column) + 1
  172. in_row = int((pos_index - 1) / max_column) + 1
  173. x = int(width * (in_column - 1))
  174. y = int(height * (in_row - 1))
  175. # Utils.set_window_position_and_size(emulator_hwnd, x, y, width, height)
  176. time.sleep(2)
  177. for _ in range(retries):
  178. current_x, current_y, current_width, current_height = Utils.get_window_position_and_size(emulator_hwnd)
  179. if current_x == x and current_y == y and current_width == width and current_height == height:
  180. return True
  181. time.sleep(2)
  182. # Utils.set_window_position_and_size(emulator_hwnd, x, y, width, height)
  183. raise Exception(f"Failed to set window position and size after {retries} retries.")