pymobiledevice3 4.27.0__py3-none-any.whl → 5.1.2__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.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +123 -98
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +351 -117
- pymobiledevice3/ca.py +32 -24
- pymobiledevice3/cli/activation.py +7 -7
- pymobiledevice3/cli/afc.py +19 -19
- pymobiledevice3/cli/amfi.py +4 -4
- pymobiledevice3/cli/apps.py +51 -39
- pymobiledevice3/cli/backup.py +58 -32
- pymobiledevice3/cli/bonjour.py +27 -20
- pymobiledevice3/cli/cli_common.py +112 -81
- pymobiledevice3/cli/companion_proxy.py +4 -4
- pymobiledevice3/cli/completions.py +10 -10
- pymobiledevice3/cli/crash.py +37 -31
- pymobiledevice3/cli/developer.py +601 -519
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +82 -72
- pymobiledevice3/cli/mounter.py +84 -67
- pymobiledevice3/cli/notification.py +10 -10
- pymobiledevice3/cli/pcap.py +19 -14
- pymobiledevice3/cli/power_assertion.py +12 -10
- pymobiledevice3/cli/processes.py +10 -10
- pymobiledevice3/cli/profile.py +88 -77
- pymobiledevice3/cli/provision.py +17 -17
- pymobiledevice3/cli/remote.py +188 -111
- pymobiledevice3/cli/restore.py +43 -40
- pymobiledevice3/cli/springboard.py +30 -28
- pymobiledevice3/cli/syslog.py +85 -58
- pymobiledevice3/cli/usbmux.py +21 -20
- pymobiledevice3/cli/version.py +3 -2
- pymobiledevice3/cli/webinspector.py +156 -78
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +400 -251
- pymobiledevice3/lockdown_service_provider.py +5 -7
- pymobiledevice3/osu/os_utils.py +18 -9
- pymobiledevice3/osu/posix_util.py +28 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +19 -19
- pymobiledevice3/remote/common.py +4 -4
- pymobiledevice3/remote/core_device/app_service.py +94 -67
- pymobiledevice3/remote/core_device/core_device_service.py +17 -14
- pymobiledevice3/remote/core_device/device_info.py +5 -5
- pymobiledevice3/remote/core_device/diagnostics_service.py +10 -8
- pymobiledevice3/remote/core_device/file_service.py +47 -33
- pymobiledevice3/remote/remote_service_discovery.py +53 -35
- pymobiledevice3/remote/remotexpc.py +64 -42
- pymobiledevice3/remote/tunnel_service.py +383 -297
- pymobiledevice3/remote/utils.py +14 -13
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +16 -16
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +90 -47
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +11 -11
- pymobiledevice3/restore/fdr.py +46 -46
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +130 -133
- pymobiledevice3/restore/mbn.py +587 -0
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +535 -523
- pymobiledevice3/restore/restore_options.py +122 -115
- pymobiledevice3/restore/restored_client.py +25 -22
- pymobiledevice3/restore/tss.py +378 -270
- pymobiledevice3/service_connection.py +50 -46
- pymobiledevice3/services/accessibilityaudit.py +137 -127
- pymobiledevice3/services/afc.py +363 -293
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +61 -47
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +56 -48
- pymobiledevice3/services/diagnostics.py +971 -968
- pymobiledevice3/services/dtfetchsymbols.py +8 -8
- pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
- pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
- pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
- pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
- pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
- pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
- pymobiledevice3/services/dvt/instruments/device_info.py +11 -11
- pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
- pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
- pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
- pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
- pymobiledevice3/services/dvt/instruments/process_control.py +25 -10
- pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
- pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
- pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
- pymobiledevice3/services/file_relay.py +10 -10
- pymobiledevice3/services/heartbeat.py +8 -7
- pymobiledevice3/services/house_arrest.py +12 -15
- pymobiledevice3/services/installation_proxy.py +119 -100
- pymobiledevice3/services/lockdown_service.py +12 -5
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +84 -72
- pymobiledevice3/services/mobile_config.py +331 -301
- pymobiledevice3/services/mobile_image_mounter.py +137 -116
- pymobiledevice3/services/mobilebackup2.py +188 -150
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +128 -74
- pymobiledevice3/services/pcapd.py +306 -306
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +16 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +13 -10
- pymobiledevice3/services/simulate_location.py +7 -7
- pymobiledevice3/services/springboard.py +15 -15
- pymobiledevice3/services/syslog.py +5 -5
- pymobiledevice3/services/web_protocol/alert.py +3 -3
- pymobiledevice3/services/web_protocol/automation_session.py +183 -179
- pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +47 -45
- pymobiledevice3/services/web_protocol/element.py +74 -63
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +3 -3
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +142 -116
- pymobiledevice3/tcp_forwarder.py +64 -50
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +315 -193
- pymobiledevice3/usbmux.py +197 -148
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-4.27.0.dist-info → pymobiledevice3-5.1.2.dist-info}/METADATA +2 -6
- pymobiledevice3-5.1.2.dist-info/RECORD +173 -0
- pymobiledevice3-4.27.0.dist-info/RECORD +0 -172
- {pymobiledevice3-4.27.0.dist-info → pymobiledevice3-5.1.2.dist-info}/WHEEL +0 -0
- {pymobiledevice3-4.27.0.dist-info → pymobiledevice3-5.1.2.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-4.27.0.dist-info → pymobiledevice3-5.1.2.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-4.27.0.dist-info → pymobiledevice3-5.1.2.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 =
|
|
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,8 +41,8 @@ class DeviceInfo:
|
|
|
41
41
|
result = self._channel.receive_plist()
|
|
42
42
|
assert isinstance(result, list)
|
|
43
43
|
for process in result:
|
|
44
|
-
if
|
|
45
|
-
process[
|
|
44
|
+
if "startDate" in process:
|
|
45
|
+
process["startDate"] = datetime.fromtimestamp(process["startDate"])
|
|
46
46
|
return result
|
|
47
47
|
|
|
48
48
|
def is_running_pid(self, pid: int) -> bool:
|
|
@@ -55,28 +55,28 @@ class DeviceInfo:
|
|
|
55
55
|
return self._channel.receive_plist()
|
|
56
56
|
|
|
57
57
|
def system_information(self):
|
|
58
|
-
return self.request_information(
|
|
58
|
+
return self.request_information("systemInformation")
|
|
59
59
|
|
|
60
60
|
def hardware_information(self):
|
|
61
|
-
return self.request_information(
|
|
61
|
+
return self.request_information("hardwareInformation")
|
|
62
62
|
|
|
63
63
|
def network_information(self):
|
|
64
|
-
return self.request_information(
|
|
64
|
+
return self.request_information("networkInformation")
|
|
65
65
|
|
|
66
66
|
def mach_time_info(self):
|
|
67
|
-
return self.request_information(
|
|
67
|
+
return self.request_information("machTimeInfo")
|
|
68
68
|
|
|
69
69
|
def mach_kernel_name(self) -> str:
|
|
70
|
-
return self.request_information(
|
|
70
|
+
return self.request_information("machKernelName")
|
|
71
71
|
|
|
72
72
|
def kpep_database(self) -> typing.Optional[dict]:
|
|
73
|
-
kpep_database = self.request_information(
|
|
73
|
+
kpep_database = self.request_information("kpepDatabase")
|
|
74
74
|
if kpep_database is not None:
|
|
75
75
|
return plistlib.loads(kpep_database)
|
|
76
76
|
|
|
77
77
|
def trace_codes(self):
|
|
78
|
-
codes_file = self.request_information(
|
|
79
|
-
return {int(k, 16): v for k, v in
|
|
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())}
|
|
80
80
|
|
|
81
81
|
def request_information(self, selector_name):
|
|
82
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
5
|
+
IDENTIFIER = "com.apple.instruments.server.services.mobilenotifications"
|
|
6
6
|
|
|
7
7
|
def __init__(self, dvt):
|
|
8
8
|
self._dvt = dvt
|
|
@@ -17,7 +17,7 @@ class OutputReceivedEvent:
|
|
|
17
17
|
message: str
|
|
18
18
|
|
|
19
19
|
@classmethod
|
|
20
|
-
def create(cls, message) ->
|
|
20
|
+
def create(cls, message) -> "OutputReceivedEvent":
|
|
21
21
|
try:
|
|
22
22
|
date = OSUTIL.parse_timestamp(message[2].value)
|
|
23
23
|
except (ValueError, OSError):
|
|
@@ -27,7 +27,7 @@ class OutputReceivedEvent:
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class ProcessControl:
|
|
30
|
-
IDENTIFIER =
|
|
30
|
+
IDENTIFIER = "com.apple.instruments.server.services.processcontrol"
|
|
31
31
|
|
|
32
32
|
def __init__(self, dvt: DvtSecureSocketProxyService):
|
|
33
33
|
self._channel = dvt.make_channel(self.IDENTIFIER)
|
|
@@ -58,11 +58,20 @@ class ProcessControl:
|
|
|
58
58
|
self._channel.killPid_(MessageAux().append_obj(pid), expects_reply=False)
|
|
59
59
|
|
|
60
60
|
def process_identifier_for_bundle_identifier(self, app_bundle_identifier: str) -> int:
|
|
61
|
-
self._channel.processIdentifierForBundleIdentifier_(
|
|
61
|
+
self._channel.processIdentifierForBundleIdentifier_(
|
|
62
|
+
MessageAux().append_obj(app_bundle_identifier), expects_reply=True
|
|
63
|
+
)
|
|
62
64
|
return self._channel.receive_plist()
|
|
63
65
|
|
|
64
|
-
def launch(
|
|
65
|
-
|
|
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:
|
|
66
75
|
"""
|
|
67
76
|
Launch a process.
|
|
68
77
|
:param bundle_id: Bundle id of the process.
|
|
@@ -76,13 +85,19 @@ class ProcessControl:
|
|
|
76
85
|
arguments = [] if arguments is None else arguments
|
|
77
86
|
environment = {} if environment is None else environment
|
|
78
87
|
options = {
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
"StartSuspendedKey": start_suspended,
|
|
89
|
+
"KillExisting": kill_existing,
|
|
81
90
|
}
|
|
82
91
|
if extra_options:
|
|
83
92
|
options.update(extra_options)
|
|
84
|
-
args =
|
|
85
|
-
|
|
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
|
+
)
|
|
86
101
|
self._channel.launchSuspendedProcessWithDevicePath_bundleIdentifier_environment_arguments_options_(args)
|
|
87
102
|
result = self._channel.receive_plist()
|
|
88
103
|
assert result
|
|
@@ -90,5 +105,5 @@ class ProcessControl:
|
|
|
90
105
|
|
|
91
106
|
def __iter__(self) -> typing.Generator[OutputReceivedEvent, None, None]:
|
|
92
107
|
key, value = self._channel.receive_key_value()
|
|
93
|
-
if key ==
|
|
108
|
+
if key == "outputReceived:fromProcess:atTime:":
|
|
94
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 =
|
|
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
|
-
"""
|
|
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 =
|
|
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(
|
|
14
|
-
system_attributes = list(self._device_info.request_information(
|
|
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(
|
|
17
|
-
self.system_attributes_cls = dataclasses.make_dataclass(
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
37
|
+
if "Processes" not in row:
|
|
38
38
|
continue
|
|
39
39
|
|
|
40
40
|
entries = []
|
|
41
41
|
|
|
42
|
-
processes = row[
|
|
43
|
-
for
|
|
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
|
|
17
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 = [
|
|
39
|
-
self.service.send_plist({
|
|
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(
|
|
44
|
-
if s ==
|
|
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(
|
|
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
|
|
@@ -10,8 +11,9 @@ class HeartbeatService:
|
|
|
10
11
|
"""
|
|
11
12
|
Use to keep an active connection with lockdownd
|
|
12
13
|
"""
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
35
|
-
break
|
|
35
|
+
if interval is not None and time.time() >= start + interval:
|
|
36
|
+
break
|
|
36
37
|
|
|
37
|
-
service.send_plist({
|
|
38
|
+
service.send_plist({"Command": "Polo"})
|
|
@@ -3,25 +3,22 @@ from pymobiledevice3.lockdown import LockdownClient
|
|
|
3
3
|
from pymobiledevice3.lockdown_service_provider import LockdownServiceProvider
|
|
4
4
|
from pymobiledevice3.services.afc import AfcService, AfcShell
|
|
5
5
|
|
|
6
|
-
VEND_CONTAINER =
|
|
7
|
-
VEND_DOCUMENTS =
|
|
6
|
+
VEND_CONTAINER = "VendContainer"
|
|
7
|
+
VEND_DOCUMENTS = "VendDocuments"
|
|
8
8
|
|
|
9
|
-
DOCUMENTS_ROOT =
|
|
9
|
+
DOCUMENTS_ROOT = "/Documents"
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class HouseArrestService(AfcService):
|
|
13
|
-
SERVICE_NAME =
|
|
14
|
-
RSD_SERVICE_NAME =
|
|
13
|
+
SERVICE_NAME = "com.apple.mobile.house_arrest"
|
|
14
|
+
RSD_SERVICE_NAME = "com.apple.mobile.house_arrest.shim.remote"
|
|
15
15
|
|
|
16
16
|
def __init__(self, lockdown: LockdownServiceProvider, bundle_id: str, documents_only: bool = False):
|
|
17
17
|
if isinstance(lockdown, LockdownClient):
|
|
18
18
|
super().__init__(lockdown, self.SERVICE_NAME)
|
|
19
19
|
else:
|
|
20
20
|
super().__init__(lockdown, self.RSD_SERVICE_NAME)
|
|
21
|
-
if documents_only
|
|
22
|
-
cmd = VEND_DOCUMENTS
|
|
23
|
-
else:
|
|
24
|
-
cmd = VEND_CONTAINER
|
|
21
|
+
cmd = VEND_DOCUMENTS if documents_only else VEND_CONTAINER
|
|
25
22
|
self.documents_only = documents_only
|
|
26
23
|
try:
|
|
27
24
|
self.send_command(bundle_id, cmd)
|
|
@@ -29,14 +26,14 @@ class HouseArrestService(AfcService):
|
|
|
29
26
|
self.close()
|
|
30
27
|
raise
|
|
31
28
|
|
|
32
|
-
def send_command(self, bundle_id: str, cmd: str =
|
|
33
|
-
response = self.service.send_recv_plist({
|
|
34
|
-
error = response.get(
|
|
29
|
+
def send_command(self, bundle_id: str, cmd: str = "VendContainer") -> None:
|
|
30
|
+
response = self.service.send_recv_plist({"Command": cmd, "Identifier": bundle_id})
|
|
31
|
+
error = response.get("Error")
|
|
35
32
|
if error:
|
|
36
|
-
if error ==
|
|
37
|
-
raise AppNotInstalledError(f
|
|
33
|
+
if error == "ApplicationLookupFailed":
|
|
34
|
+
raise AppNotInstalledError(f"No app with bundle id {bundle_id} found")
|
|
38
35
|
else:
|
|
39
36
|
raise PyMobileDevice3Exception(error)
|
|
40
37
|
|
|
41
38
|
def shell(self) -> None:
|
|
42
|
-
AfcShell.create(self.lockdown, service=self, auto_cd=DOCUMENTS_ROOT if self.documents_only else
|
|
39
|
+
AfcShell.create(self.lockdown, service=self, auto_cd=DOCUMENTS_ROOT if self.documents_only else "/")
|