pymobiledevice3 4.14.6__py3-none-any.whl → 7.0.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. misc/plist_sniffer.py +15 -15
  2. misc/remotexpc_sniffer.py +29 -28
  3. misc/understanding_idevice_protocol_layers.md +15 -10
  4. pymobiledevice3/__main__.py +317 -127
  5. pymobiledevice3/_version.py +22 -4
  6. pymobiledevice3/bonjour.py +358 -113
  7. pymobiledevice3/ca.py +253 -16
  8. pymobiledevice3/cli/activation.py +31 -23
  9. pymobiledevice3/cli/afc.py +49 -40
  10. pymobiledevice3/cli/amfi.py +16 -21
  11. pymobiledevice3/cli/apps.py +87 -42
  12. pymobiledevice3/cli/backup.py +160 -90
  13. pymobiledevice3/cli/bonjour.py +44 -40
  14. pymobiledevice3/cli/cli_common.py +204 -198
  15. pymobiledevice3/cli/companion_proxy.py +14 -14
  16. pymobiledevice3/cli/crash.py +105 -56
  17. pymobiledevice3/cli/developer/__init__.py +62 -0
  18. pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
  19. pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
  20. pymobiledevice3/cli/developer/arbitration.py +50 -0
  21. pymobiledevice3/cli/developer/condition.py +33 -0
  22. pymobiledevice3/cli/developer/core_device.py +294 -0
  23. pymobiledevice3/cli/developer/debugserver.py +244 -0
  24. pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
  25. pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
  26. pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
  27. pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
  28. pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
  29. pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
  30. pymobiledevice3/cli/developer/simulate_location.py +51 -0
  31. pymobiledevice3/cli/diagnostics/__init__.py +75 -0
  32. pymobiledevice3/cli/diagnostics/battery.py +47 -0
  33. pymobiledevice3/cli/idam.py +42 -0
  34. pymobiledevice3/cli/lockdown.py +108 -103
  35. pymobiledevice3/cli/mounter.py +158 -99
  36. pymobiledevice3/cli/notification.py +38 -26
  37. pymobiledevice3/cli/pcap.py +45 -24
  38. pymobiledevice3/cli/power_assertion.py +18 -17
  39. pymobiledevice3/cli/processes.py +17 -23
  40. pymobiledevice3/cli/profile.py +165 -109
  41. pymobiledevice3/cli/provision.py +35 -34
  42. pymobiledevice3/cli/remote.py +217 -129
  43. pymobiledevice3/cli/restore.py +159 -143
  44. pymobiledevice3/cli/springboard.py +63 -53
  45. pymobiledevice3/cli/syslog.py +193 -86
  46. pymobiledevice3/cli/usbmux.py +73 -33
  47. pymobiledevice3/cli/version.py +5 -7
  48. pymobiledevice3/cli/webinspector.py +376 -214
  49. pymobiledevice3/common.py +3 -1
  50. pymobiledevice3/exceptions.py +182 -58
  51. pymobiledevice3/irecv.py +52 -53
  52. pymobiledevice3/irecv_devices.py +1489 -464
  53. pymobiledevice3/lockdown.py +473 -275
  54. pymobiledevice3/lockdown_service_provider.py +15 -8
  55. pymobiledevice3/osu/os_utils.py +27 -9
  56. pymobiledevice3/osu/posix_util.py +34 -15
  57. pymobiledevice3/osu/win_util.py +14 -8
  58. pymobiledevice3/pair_records.py +102 -21
  59. pymobiledevice3/remote/common.py +8 -4
  60. pymobiledevice3/remote/core_device/app_service.py +94 -67
  61. pymobiledevice3/remote/core_device/core_device_service.py +17 -14
  62. pymobiledevice3/remote/core_device/device_info.py +5 -5
  63. pymobiledevice3/remote/core_device/diagnostics_service.py +19 -4
  64. pymobiledevice3/remote/core_device/file_service.py +53 -23
  65. pymobiledevice3/remote/remote_service_discovery.py +79 -45
  66. pymobiledevice3/remote/remotexpc.py +73 -44
  67. pymobiledevice3/remote/tunnel_service.py +442 -317
  68. pymobiledevice3/remote/utils.py +14 -13
  69. pymobiledevice3/remote/xpc_message.py +145 -125
  70. pymobiledevice3/resources/dsc_uuid_map.py +19 -19
  71. pymobiledevice3/resources/firmware_notifications.py +20 -16
  72. pymobiledevice3/resources/notifications.txt +144 -0
  73. pymobiledevice3/restore/asr.py +27 -27
  74. pymobiledevice3/restore/base_restore.py +110 -21
  75. pymobiledevice3/restore/consts.py +87 -66
  76. pymobiledevice3/restore/device.py +59 -12
  77. pymobiledevice3/restore/fdr.py +46 -48
  78. pymobiledevice3/restore/ftab.py +19 -19
  79. pymobiledevice3/restore/img4.py +163 -0
  80. pymobiledevice3/restore/mbn.py +587 -0
  81. pymobiledevice3/restore/recovery.py +151 -151
  82. pymobiledevice3/restore/restore.py +562 -544
  83. pymobiledevice3/restore/restore_options.py +131 -110
  84. pymobiledevice3/restore/restored_client.py +51 -31
  85. pymobiledevice3/restore/tss.py +385 -267
  86. pymobiledevice3/service_connection.py +252 -59
  87. pymobiledevice3/services/accessibilityaudit.py +202 -120
  88. pymobiledevice3/services/afc.py +962 -365
  89. pymobiledevice3/services/amfi.py +24 -30
  90. pymobiledevice3/services/companion.py +23 -19
  91. pymobiledevice3/services/crash_reports.py +71 -47
  92. pymobiledevice3/services/debugserver_applist.py +3 -3
  93. pymobiledevice3/services/device_arbitration.py +8 -8
  94. pymobiledevice3/services/device_link.py +101 -79
  95. pymobiledevice3/services/diagnostics.py +973 -967
  96. pymobiledevice3/services/dtfetchsymbols.py +8 -8
  97. pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
  98. pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
  99. pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
  100. pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
  101. pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
  102. pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
  103. pymobiledevice3/services/dvt/instruments/device_info.py +20 -11
  104. pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
  105. pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
  106. pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
  107. pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
  108. pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
  109. pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
  110. pymobiledevice3/services/dvt/instruments/process_control.py +35 -10
  111. pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
  112. pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
  113. pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
  114. pymobiledevice3/services/file_relay.py +10 -10
  115. pymobiledevice3/services/heartbeat.py +9 -8
  116. pymobiledevice3/services/house_arrest.py +16 -15
  117. pymobiledevice3/services/idam.py +20 -0
  118. pymobiledevice3/services/installation_proxy.py +173 -81
  119. pymobiledevice3/services/lockdown_service.py +20 -10
  120. pymobiledevice3/services/misagent.py +22 -19
  121. pymobiledevice3/services/mobile_activation.py +147 -64
  122. pymobiledevice3/services/mobile_config.py +331 -294
  123. pymobiledevice3/services/mobile_image_mounter.py +141 -113
  124. pymobiledevice3/services/mobilebackup2.py +203 -145
  125. pymobiledevice3/services/notification_proxy.py +11 -11
  126. pymobiledevice3/services/os_trace.py +134 -74
  127. pymobiledevice3/services/pcapd.py +314 -302
  128. pymobiledevice3/services/power_assertion.py +10 -9
  129. pymobiledevice3/services/preboard.py +4 -4
  130. pymobiledevice3/services/remote_fetch_symbols.py +21 -14
  131. pymobiledevice3/services/remote_server.py +176 -146
  132. pymobiledevice3/services/restore_service.py +16 -16
  133. pymobiledevice3/services/screenshot.py +15 -12
  134. pymobiledevice3/services/simulate_location.py +7 -7
  135. pymobiledevice3/services/springboard.py +15 -15
  136. pymobiledevice3/services/syslog.py +5 -5
  137. pymobiledevice3/services/web_protocol/alert.py +11 -11
  138. pymobiledevice3/services/web_protocol/automation_session.py +251 -239
  139. pymobiledevice3/services/web_protocol/cdp_screencast.py +46 -37
  140. pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
  141. pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
  142. pymobiledevice3/services/web_protocol/driver.py +114 -111
  143. pymobiledevice3/services/web_protocol/element.py +124 -111
  144. pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
  145. pymobiledevice3/services/web_protocol/selenium_api.py +49 -49
  146. pymobiledevice3/services/web_protocol/session_protocol.py +18 -12
  147. pymobiledevice3/services/web_protocol/switch_to.py +30 -27
  148. pymobiledevice3/services/webinspector.py +189 -155
  149. pymobiledevice3/tcp_forwarder.py +87 -69
  150. pymobiledevice3/tunneld/__init__.py +0 -0
  151. pymobiledevice3/tunneld/api.py +63 -0
  152. pymobiledevice3/tunneld/server.py +603 -0
  153. pymobiledevice3/usbmux.py +198 -147
  154. pymobiledevice3/utils.py +14 -11
  155. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +55 -28
  156. pymobiledevice3-7.0.6.dist-info/RECORD +188 -0
  157. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +1 -1
  158. pymobiledevice3/cli/developer.py +0 -1215
  159. pymobiledevice3/cli/diagnostics.py +0 -99
  160. pymobiledevice3/tunneld.py +0 -524
  161. pymobiledevice3-4.14.6.dist-info/RECORD +0 -168
  162. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
  163. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info/licenses}/LICENSE +0 -0
  164. {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ from pymobiledevice3.services.remote_server import MessageAux
7
7
 
8
8
 
9
9
  class DeviceInfo:
10
- IDENTIFIER = 'com.apple.instruments.server.services.deviceinfo'
10
+ IDENTIFIER = "com.apple.instruments.server.services.deviceinfo"
11
11
 
12
12
  def __init__(self, dvt):
13
13
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -41,33 +41,42 @@ class DeviceInfo:
41
41
  result = self._channel.receive_plist()
42
42
  assert isinstance(result, list)
43
43
  for process in result:
44
- if 'startDate' in process:
45
- process['startDate'] = datetime.fromtimestamp(process['startDate'])
44
+ if "startDate" in process:
45
+ process["startDate"] = datetime.fromtimestamp(process["startDate"])
46
46
  return result
47
47
 
48
+ def is_running_pid(self, pid: int) -> bool:
49
+ """
50
+ check if pid is running
51
+ :param pid: process identifier
52
+ :return: whether if it is running or not
53
+ """
54
+ self._channel.isRunningPid_(MessageAux().append_obj(pid))
55
+ return self._channel.receive_plist()
56
+
48
57
  def system_information(self):
49
- return self.request_information('systemInformation')
58
+ return self.request_information("systemInformation")
50
59
 
51
60
  def hardware_information(self):
52
- return self.request_information('hardwareInformation')
61
+ return self.request_information("hardwareInformation")
53
62
 
54
63
  def network_information(self):
55
- return self.request_information('networkInformation')
64
+ return self.request_information("networkInformation")
56
65
 
57
66
  def mach_time_info(self):
58
- return self.request_information('machTimeInfo')
67
+ return self.request_information("machTimeInfo")
59
68
 
60
69
  def mach_kernel_name(self) -> str:
61
- return self.request_information('machKernelName')
70
+ return self.request_information("machKernelName")
62
71
 
63
72
  def kpep_database(self) -> typing.Optional[dict]:
64
- kpep_database = self.request_information('kpepDatabase')
73
+ kpep_database = self.request_information("kpepDatabase")
65
74
  if kpep_database is not None:
66
75
  return plistlib.loads(kpep_database)
67
76
 
68
77
  def trace_codes(self):
69
- codes_file = self.request_information('traceCodesFile')
70
- return {int(k, 16): v for k, v in map(lambda line: line.split(), codes_file.splitlines())}
78
+ codes_file = self.request_information("traceCodesFile")
79
+ return {int(k, 16): v for k, v in (line.split() for line in codes_file.splitlines())}
71
80
 
72
81
  def request_information(self, selector_name):
73
82
  self._channel[selector_name]()
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
2
2
 
3
3
 
4
4
  class EnergyMonitor:
5
- IDENTIFIER = 'com.apple.xcode.debug-gauge-data-providers.Energy'
5
+ IDENTIFIER = "com.apple.xcode.debug-gauge-data-providers.Energy"
6
6
 
7
7
  def __init__(self, dvt, pid_list: list):
8
8
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
2
2
 
3
3
 
4
4
  class Graphics:
5
- IDENTIFIER = 'com.apple.instruments.server.services.graphics.opengl'
5
+ IDENTIFIER = "com.apple.instruments.server.services.graphics.opengl"
6
6
 
7
7
  def __init__(self, dvt):
8
8
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -3,7 +3,7 @@ from pymobiledevice3.services.remote_server import MessageAux
3
3
 
4
4
 
5
5
  class LocationSimulation(LocationSimulationBase):
6
- IDENTIFIER = 'com.apple.instruments.server.services.LocationSimulation'
6
+ IDENTIFIER = "com.apple.instruments.server.services.LocationSimulation"
7
7
 
8
8
  def __init__(self, dvt):
9
9
  super().__init__()
@@ -29,15 +29,15 @@ class LocationSimulationBase:
29
29
  for point in segment.points:
30
30
  if last_time is not None:
31
31
  duration = (point.time - last_time).total_seconds()
32
- if duration >= 0:
33
- if not disable_sleep:
34
-
35
- if timing_randomness_range:
36
- gpx_timing_noise = random.randint(-timing_randomness_range, timing_randomness_range) / 1000
37
- duration += gpx_timing_noise
38
-
39
- self.logger.info(f'waiting for {duration:.3f}s')
40
- time.sleep(duration)
32
+ if duration >= 0 and not disable_sleep:
33
+ if timing_randomness_range:
34
+ gpx_timing_noise = (
35
+ random.randint(-timing_randomness_range, timing_randomness_range) / 1000
36
+ )
37
+ duration += gpx_timing_noise
38
+
39
+ self.logger.info(f"waiting for {duration:.3f}s")
40
+ time.sleep(duration)
41
41
  last_time = point.time
42
- self.logger.info(f'set location to {point.latitude} {point.longitude}')
42
+ self.logger.info(f"set location to {point.latitude} {point.longitude}")
43
43
  self.set(point.latitude, point.longitude)
@@ -11,21 +11,21 @@ class IpAddressAdapter(Adapter):
11
11
 
12
12
 
13
13
  address_t = Struct(
14
- 'len' / Int8ul,
15
- 'family' / Int8ul,
16
- 'port' / Int16ub,
17
- 'data' / Switch(this.len, {
18
- 0x1c: Struct(
19
- 'flow_info' / Int32ul,
20
- 'address' / IpAddressAdapter(Bytes(16)),
21
- 'scope_id' / Int32ul,
22
- ),
23
- 0x10: Struct(
24
- 'address' / IpAddressAdapter(Bytes(4)),
25
- '_zero' / Bytes(8)
26
- )
27
- })
28
-
14
+ "len" / Int8ul,
15
+ "family" / Int8ul,
16
+ "port" / Int16ub,
17
+ "data"
18
+ / Switch(
19
+ this.len,
20
+ {
21
+ 0x1C: Struct(
22
+ "flow_info" / Int32ul,
23
+ "address" / IpAddressAdapter(Bytes(16)),
24
+ "scope_id" / Int32ul,
25
+ ),
26
+ 0x10: Struct("address" / IpAddressAdapter(Bytes(4)), "_zero" / Bytes(8)),
27
+ },
28
+ ),
29
29
  )
30
30
 
31
31
  MESSAGE_TYPE_INTERFACE_DETECTION = 0
@@ -67,7 +67,7 @@ class ConnectionUpdateEvent:
67
67
 
68
68
 
69
69
  class NetworkMonitor:
70
- IDENTIFIER = 'com.apple.instruments.server.services.networking'
70
+ IDENTIFIER = "com.apple.instruments.server.services.networking"
71
71
 
72
72
  def __init__(self, dvt):
73
73
  self.logger = logging.getLogger(__name__)
@@ -98,5 +98,5 @@ class NetworkMonitor:
98
98
  elif message[0] == MESSAGE_TYPE_CONNECTION_UPDATE:
99
99
  event = ConnectionUpdateEvent(*message[1])
100
100
  else:
101
- self.logger.warning(f'unsupported event type: {message[0]}')
101
+ self.logger.warning(f"unsupported event type: {message[0]}")
102
102
  yield event
@@ -2,7 +2,7 @@ from pymobiledevice3.services.remote_server import MessageAux
2
2
 
3
3
 
4
4
  class Notifications:
5
- IDENTIFIER = 'com.apple.instruments.server.services.mobilenotifications'
5
+ IDENTIFIER = "com.apple.instruments.server.services.mobilenotifications"
6
6
 
7
7
  def __init__(self, dvt):
8
8
  self._dvt = dvt
@@ -2,6 +2,7 @@ import dataclasses
2
2
  import typing
3
3
  from typing import Optional
4
4
 
5
+ from pymobiledevice3.exceptions import DisableMemoryLimitError
5
6
  from pymobiledevice3.osu.os_utils import get_os_utils
6
7
  from pymobiledevice3.services.dvt.dvt_secure_socket_proxy import DvtSecureSocketProxyService
7
8
  from pymobiledevice3.services.remote_server import MessageAux
@@ -16,7 +17,7 @@ class OutputReceivedEvent:
16
17
  message: str
17
18
 
18
19
  @classmethod
19
- def create(cls, message) -> 'OutputReceivedEvent':
20
+ def create(cls, message) -> "OutputReceivedEvent":
20
21
  try:
21
22
  date = OSUTIL.parse_timestamp(message[2].value)
22
23
  except (ValueError, OSError):
@@ -26,7 +27,7 @@ class OutputReceivedEvent:
26
27
 
27
28
 
28
29
  class ProcessControl:
29
- IDENTIFIER = 'com.apple.instruments.server.services.processcontrol'
30
+ IDENTIFIER = "com.apple.instruments.server.services.processcontrol"
30
31
 
31
32
  def __init__(self, dvt: DvtSecureSocketProxyService):
32
33
  self._channel = dvt.make_channel(self.IDENTIFIER)
@@ -40,6 +41,15 @@ class ProcessControl:
40
41
  self._channel.sendSignal_toPid_(MessageAux().append_obj(sig).append_obj(pid), expects_reply=True)
41
42
  return self._channel.receive_plist()
42
43
 
44
+ def disable_memory_limit_for_pid(self, pid: int) -> None:
45
+ """
46
+ Waive memory limit for a given pid
47
+ :param pid: process id.
48
+ """
49
+ self._channel.requestDisableMemoryLimitsForPid_(MessageAux().append_int(pid), expects_reply=True)
50
+ if not self._channel.receive_plist():
51
+ raise DisableMemoryLimitError()
52
+
43
53
  def kill(self, pid: int):
44
54
  """
45
55
  Kill a process.
@@ -48,11 +58,20 @@ class ProcessControl:
48
58
  self._channel.killPid_(MessageAux().append_obj(pid), expects_reply=False)
49
59
 
50
60
  def process_identifier_for_bundle_identifier(self, app_bundle_identifier: str) -> int:
51
- self._channel.processIdentifierForBundleIdentifier_(MessageAux().append_obj(app_bundle_identifier), expects_reply=True)
61
+ self._channel.processIdentifierForBundleIdentifier_(
62
+ MessageAux().append_obj(app_bundle_identifier), expects_reply=True
63
+ )
52
64
  return self._channel.receive_plist()
53
65
 
54
- def launch(self, bundle_id: str, arguments=None, kill_existing: bool = True, start_suspended: bool = False,
55
- environment: Optional[dict] = None, extra_options: Optional[dict] = None) -> int:
66
+ def launch(
67
+ self,
68
+ bundle_id: str,
69
+ arguments=None,
70
+ kill_existing: bool = True,
71
+ start_suspended: bool = False,
72
+ environment: Optional[dict] = None,
73
+ extra_options: Optional[dict] = None,
74
+ ) -> int:
56
75
  """
57
76
  Launch a process.
58
77
  :param bundle_id: Bundle id of the process.
@@ -66,13 +85,19 @@ class ProcessControl:
66
85
  arguments = [] if arguments is None else arguments
67
86
  environment = {} if environment is None else environment
68
87
  options = {
69
- 'StartSuspendedKey': start_suspended,
70
- 'KillExisting': kill_existing,
88
+ "StartSuspendedKey": start_suspended,
89
+ "KillExisting": kill_existing,
71
90
  }
72
91
  if extra_options:
73
92
  options.update(extra_options)
74
- args = MessageAux().append_obj('').append_obj(bundle_id).append_obj(environment).append_obj(
75
- arguments).append_obj(options)
93
+ args = (
94
+ MessageAux()
95
+ .append_obj("")
96
+ .append_obj(bundle_id)
97
+ .append_obj(environment)
98
+ .append_obj(arguments)
99
+ .append_obj(options)
100
+ )
76
101
  self._channel.launchSuspendedProcessWithDevicePath_bundleIdentifier_environment_arguments_options_(args)
77
102
  result = self._channel.receive_plist()
78
103
  assert result
@@ -80,5 +105,5 @@ class ProcessControl:
80
105
 
81
106
  def __iter__(self) -> typing.Generator[OutputReceivedEvent, None, None]:
82
107
  key, value = self._channel.receive_key_value()
83
- if key == 'outputReceived:fromProcess:atTime:':
108
+ if key == "outputReceived:fromProcess:atTime:":
84
109
  yield OutputReceivedEvent.create(value)
@@ -2,12 +2,12 @@ from pymobiledevice3.services.dvt.dvt_secure_socket_proxy import DvtSecureSocket
2
2
 
3
3
 
4
4
  class Screenshot:
5
- IDENTIFIER = 'com.apple.instruments.server.services.screenshot'
5
+ IDENTIFIER = "com.apple.instruments.server.services.screenshot"
6
6
 
7
7
  def __init__(self, dvt: DvtSecureSocketProxyService):
8
8
  self._channel = dvt.make_channel(self.IDENTIFIER)
9
9
 
10
10
  def get_screenshot(self) -> bytes:
11
- """ get device screenshot """
11
+ """get device screenshot"""
12
12
  self._channel.takeScreenshot(expects_reply=True)
13
13
  return self._channel.receive_plist()
@@ -5,25 +5,25 @@ from pymobiledevice3.services.remote_server import Tap
5
5
 
6
6
 
7
7
  class Sysmontap(Tap):
8
- IDENTIFIER = 'com.apple.instruments.server.services.sysmontap'
8
+ IDENTIFIER = "com.apple.instruments.server.services.sysmontap"
9
9
 
10
10
  def __init__(self, dvt):
11
11
  self._device_info = DeviceInfo(dvt)
12
12
 
13
- process_attributes = list(self._device_info.request_information('sysmonProcessAttributes'))
14
- system_attributes = list(self._device_info.request_information('sysmonSystemAttributes'))
13
+ process_attributes = list(self._device_info.request_information("sysmonProcessAttributes"))
14
+ system_attributes = list(self._device_info.request_information("sysmonSystemAttributes"))
15
15
 
16
- self.process_attributes_cls = dataclasses.make_dataclass('SysmonProcessAttributes', process_attributes)
17
- self.system_attributes_cls = dataclasses.make_dataclass('SysmonSystemAttributes', system_attributes)
16
+ self.process_attributes_cls = dataclasses.make_dataclass("SysmonProcessAttributes", process_attributes)
17
+ self.system_attributes_cls = dataclasses.make_dataclass("SysmonSystemAttributes", system_attributes)
18
18
 
19
19
  config = {
20
- 'ur': 500, # Output frequency ms
21
- 'bm': 0,
22
- 'procAttrs': process_attributes,
23
- 'sysAttrs': system_attributes,
24
- 'cpuUsage': True,
25
- 'physFootprint': True, # memory value
26
- 'sampleInterval': 500000000
20
+ "ur": 500, # Output frequency ms
21
+ "bm": 0,
22
+ "procAttrs": process_attributes,
23
+ "sysAttrs": system_attributes,
24
+ "cpuUsage": True,
25
+ "physFootprint": True, # memory value
26
+ "sampleInterval": 500000000,
27
27
  }
28
28
 
29
29
  super().__init__(dvt, self.IDENTIFIER, config)
@@ -34,13 +34,13 @@ class Sysmontap(Tap):
34
34
 
35
35
  def iter_processes(self):
36
36
  for row in self:
37
- if 'Processes' not in row:
37
+ if "Processes" not in row:
38
38
  continue
39
39
 
40
40
  entries = []
41
41
 
42
- processes = row['Processes'].items()
43
- for pid, process_info in processes:
42
+ processes = row["Processes"].items()
43
+ for _pid, process_info in processes:
44
44
  entry = dataclasses.asdict(self.process_attributes_cls(*process_info))
45
45
  entries.append(entry)
46
46
 
@@ -13,8 +13,16 @@ from pymobiledevice3.services.dvt.dvt_testmanaged_proxy import DvtTestmanagedPro
13
13
  from pymobiledevice3.services.dvt.instruments.process_control import ProcessControl
14
14
  from pymobiledevice3.services.house_arrest import HouseArrestService
15
15
  from pymobiledevice3.services.installation_proxy import InstallationProxyService
16
- from pymobiledevice3.services.remote_server import NSURL, NSUUID, Channel, ChannelFragmenter, MessageAux, \
17
- XCTestConfiguration, dtx_message_header_struct, dtx_message_payload_header_struct
16
+ from pymobiledevice3.services.remote_server import (
17
+ NSURL,
18
+ NSUUID,
19
+ Channel,
20
+ ChannelFragmenter,
21
+ MessageAux,
22
+ XCTestConfiguration,
23
+ dtx_message_header_struct,
24
+ dtx_message_payload_header_struct,
25
+ )
18
26
 
19
27
  logger = logging.getLogger(__name__)
20
28
 
@@ -52,9 +60,7 @@ class XCUITestService:
52
60
  self.setup_xcuitest(bundle_id, xctest_path, xctest_configuration)
53
61
  dvt1, chan1, dvt2, chan2 = self.init_ide_channels(session_identifier)
54
62
 
55
- pid = self.launch_test_app(
56
- app_info, bundle_id, xctest_path, test_runner_env, test_runner_args
57
- )
63
+ pid = self.launch_test_app(app_info, bundle_id, xctest_path, test_runner_env, test_runner_args)
58
64
  logger.info("Runner started with pid:%d, waiting for testBundleReady", pid)
59
65
 
60
66
  time.sleep(1)
@@ -95,24 +101,18 @@ class XCUITestService:
95
101
  # - _XCT_didFinishExecutingTestPlan
96
102
  logger.info("unhandled %s %r", key, value)
97
103
 
98
- def send_response_capabilities(
99
- self, dvt: DvtTestmanagedProxyService, chan: Channel, cur_message: int
100
- ):
101
- pheader = dtx_message_payload_header_struct.build(
102
- dict(flags=3, auxiliaryLength=0, totalLength=0)
103
- )
104
- mheader = dtx_message_header_struct.build(
105
- dict(
106
- cb=dtx_message_header_struct.sizeof(),
107
- fragmentId=0,
108
- fragmentCount=1,
109
- length=dtx_message_payload_header_struct.sizeof(),
110
- identifier=cur_message,
111
- conversationIndex=1,
112
- channelCode=chan,
113
- expectsReply=int(0),
114
- )
115
- )
104
+ def send_response_capabilities(self, dvt: DvtTestmanagedProxyService, chan: Channel, cur_message: int):
105
+ pheader = dtx_message_payload_header_struct.build({"flags": 3, "auxiliaryLength": 0, "totalLength": 0})
106
+ mheader = dtx_message_header_struct.build({
107
+ "cb": dtx_message_header_struct.sizeof(),
108
+ "fragmentId": 0,
109
+ "fragmentCount": 1,
110
+ "length": dtx_message_payload_header_struct.sizeof(),
111
+ "identifier": cur_message,
112
+ "conversationIndex": 1,
113
+ "channelCode": chan,
114
+ "expectsReply": (0),
115
+ })
116
116
  msg = mheader + pheader
117
117
  dvt.service.sendall(msg)
118
118
 
@@ -160,9 +160,7 @@ class XCUITestService:
160
160
  xctest_configuration: XCTestConfiguration,
161
161
  ):
162
162
  """push xctestconfiguration to app VendDocuments"""
163
- with HouseArrestService(
164
- lockdown=self.service_provider, bundle_id=bundle_id, documents_only=False
165
- ) as afc:
163
+ with HouseArrestService(lockdown=self.service_provider, bundle_id=bundle_id, documents_only=False) as afc:
166
164
  for name in afc.listdir("/tmp"):
167
165
  if name.endswith(".xctestconfiguration"):
168
166
  logger.debug("remove /tmp/%s", name)
@@ -197,7 +195,7 @@ class XCUITestService:
197
195
  if isinstance(reply, bool) and reply is True:
198
196
  logger.info("authorizing test session for pid %d successful %r", pid, reply)
199
197
  else:
200
- raise RuntimeError("Failed to authorize test process id: %s" % reply)
198
+ raise RuntimeError(f"Failed to authorize test process id: {reply}")
201
199
 
202
200
  def launch_test_app(
203
201
  self,
@@ -212,9 +210,7 @@ class XCUITestService:
212
210
  exec_name = app_info["CFBundleExecutable"]
213
211
  # # logger.info('CFBundleExecutable: %s', exec_name)
214
212
  # # CFBundleName always endswith -Runner
215
- assert exec_name.endswith("-Runner"), (
216
- "Invalid CFBundleExecutable: %s" % exec_name
217
- )
213
+ assert exec_name.endswith("-Runner"), f"Invalid CFBundleExecutable: {exec_name}"
218
214
  target_name = exec_name[: -len("-Runner")]
219
215
 
220
216
  app_env = {
@@ -226,7 +222,7 @@ class XCUITestService:
226
222
  "NSUnbufferedIO": "YES",
227
223
  "SQLITE_ENABLE_THREAD_ASSERTIONS": "1",
228
224
  "WDA_PRODUCT_BUNDLE_IDENTIFIER": "",
229
- "XCTestBundlePath": f'{app_info["Path"]}/PlugIns/{target_name}.xctest',
225
+ "XCTestBundlePath": f"{app_info['Path']}/PlugIns/{target_name}.xctest",
230
226
  "XCTestConfigurationFilePath": app_container + xctest_path,
231
227
  "XCODE_DBG_XPC_EXCLUSIONS": "com.apple.dt.xctestSymbolicator",
232
228
  # the following maybe no needed
@@ -238,9 +234,7 @@ class XCUITestService:
238
234
  app_env.update(test_runner_env)
239
235
 
240
236
  if self.product_major_version >= 11:
241
- app_env[
242
- "DYLD_INSERT_LIBRARIES"
243
- ] = "/Developer/usr/lib/libMainThreadChecker.dylib"
237
+ app_env["DYLD_INSERT_LIBRARIES"] = "/Developer/usr/lib/libMainThreadChecker.dylib"
244
238
  app_env["OS_ACTIVITY_DT_MODE"] = "YES"
245
239
 
246
240
  app_args = [
@@ -276,28 +270,24 @@ def get_app_info(service_provider: LockdownClient, bundle_id: str) -> dict[str,
276
270
  def generate_xctestconfiguration(
277
271
  app_info: dict,
278
272
  session_identifier: NSUUID,
279
- target_app_bundle_id: str = None,
273
+ target_app_bundle_id: Optional[str] = None,
280
274
  target_app_env: Optional[dict] = None,
281
275
  target_app_args: Optional[list] = None,
282
276
  tests_to_run: Optional[list] = None,
283
277
  ) -> XCTestConfiguration:
284
278
  exec_name: str = app_info["CFBundleExecutable"]
285
- assert exec_name.endswith("-Runner"), "Invalid CFBundleExecutable: %s" % exec_name
279
+ assert exec_name.endswith("-Runner"), f"Invalid CFBundleExecutable: {exec_name}"
286
280
  config_name = exec_name[: -len("-Runner")]
287
281
 
288
- return XCTestConfiguration(
289
- {
290
- "testBundleURL": NSURL(
291
- None, f'file://{app_info["Path"]}/PlugIns/{config_name}.xctest'
292
- ),
293
- "sessionIdentifier": session_identifier,
294
- "targetApplicationBundleID": target_app_bundle_id,
295
- "targetApplicationEnvironment": target_app_env or {},
296
- "targetApplicationArguments": target_app_args or [],
297
- "testsToRun": tests_to_run or set(),
298
- "testsMustRunOnMainThread": True,
299
- "reportResultsToIDE": True,
300
- "reportActivities": True,
301
- "automationFrameworkPath": "/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
302
- }
303
- )
282
+ return XCTestConfiguration({
283
+ "testBundleURL": NSURL(None, f"file://{app_info['Path']}/PlugIns/{config_name}.xctest"),
284
+ "sessionIdentifier": session_identifier,
285
+ "targetApplicationBundleID": target_app_bundle_id,
286
+ "targetApplicationEnvironment": target_app_env or {},
287
+ "targetApplicationArguments": target_app_args or [],
288
+ "testsToRun": tests_to_run or set(),
289
+ "testsMustRunOnMainThread": True,
290
+ "reportResultsToIDE": True,
291
+ "reportActivities": True,
292
+ "automationFrameworkPath": "/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
293
+ })
@@ -1,7 +1,7 @@
1
1
  from pymobiledevice3.lockdown import LockdownClient
2
2
  from pymobiledevice3.services.lockdown_service import LockdownService
3
3
 
4
- SRCFILES = '''Baseband
4
+ SRCFILES = """Baseband
5
5
  CrashReporter
6
6
  MobileAsset
7
7
  VARFS
@@ -19,30 +19,30 @@ NANDDebugInfo
19
19
  SystemConfiguration
20
20
  Ubiquity
21
21
  tmp
22
- WirelessAutomation'''
22
+ WirelessAutomation"""
23
23
 
24
24
 
25
25
  class FileRelayService(LockdownService):
26
- SERVICE_NAME = 'com.apple.mobile.file_relay'
26
+ SERVICE_NAME = "com.apple.mobile.file_relay"
27
27
 
28
28
  def __init__(self, lockdown: LockdownClient):
29
29
  super().__init__(lockdown, self.SERVICE_NAME)
30
30
  self.packet_num = 0
31
31
 
32
32
  def stop_session(self):
33
- self.logger.info('Disconecting...')
33
+ self.logger.info("Disconecting...")
34
34
  self.service.close()
35
35
 
36
36
  def request_sources(self, sources=None):
37
37
  if sources is None:
38
- sources = ['UserDatabases']
39
- self.service.send_plist({'Sources': sources})
38
+ sources = ["UserDatabases"]
39
+ self.service.send_plist({"Sources": sources})
40
40
  while 1:
41
41
  res = self.service.recv_plist()
42
42
  if res:
43
- s = res.get('Status')
44
- if s == 'Acknowledged':
45
- z = ''
43
+ s = res.get("Status")
44
+ if s == "Acknowledged":
45
+ z = ""
46
46
  while True:
47
47
  x = self.service.recv()
48
48
  if not x:
@@ -50,6 +50,6 @@ class FileRelayService(LockdownService):
50
50
  z += x
51
51
  return z
52
52
  else:
53
- print(res.get('Error'))
53
+ print(res.get("Error"))
54
54
  break
55
55
  return None
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  import logging
3
3
  import time
4
+ from typing import Optional
4
5
 
5
6
  from pymobiledevice3.lockdown import LockdownClient
6
7
  from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
@@ -8,10 +9,11 @@ from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
8
9
 
9
10
  class HeartbeatService:
10
11
  """
11
- Use to keep an active connection with lockdowd
12
+ Use to keep an active connection with lockdownd
12
13
  """
13
- SERVICE_NAME = 'com.apple.mobile.heartbeat'
14
- RSD_SERVICE_NAME = 'com.apple.mobile.heartbeat.shim.remote'
14
+
15
+ SERVICE_NAME = "com.apple.mobile.heartbeat"
16
+ RSD_SERVICE_NAME = "com.apple.mobile.heartbeat.shim.remote"
15
17
 
16
18
  def __init__(self, lockdown: LockdownServiceProvider):
17
19
  self.logger = logging.getLogger(__name__)
@@ -22,7 +24,7 @@ class HeartbeatService:
22
24
  else:
23
25
  self.service_name = self.RSD_SERVICE_NAME
24
26
 
25
- def start(self, interval: float = None) -> None:
27
+ def start(self, interval: Optional[float] = None) -> None:
26
28
  start = time.time()
27
29
  service = self.lockdown.start_lockdown_service(self.service_name)
28
30
 
@@ -30,8 +32,7 @@ class HeartbeatService:
30
32
  response = service.recv_plist()
31
33
  self.logger.debug(response)
32
34
 
33
- if interval is not None:
34
- if time.time() >= start + interval:
35
- break
35
+ if interval is not None and time.time() >= start + interval:
36
+ break
36
37
 
37
- service.send_plist({'Command': 'Polo'})
38
+ service.send_plist({"Command": "Polo"})