AndroidFridaManager 1.9.5__py3-none-any.whl → 1.9.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.
@@ -2,4 +2,4 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  __author__ = "Daniel Baier"
5
- __version__ = "1.9.5"
5
+ __version__ = "1.9.6"
@@ -32,7 +32,7 @@ class Job:
32
32
  display_name: Human-readable name for UI display.
33
33
  hooks_registry: List of methods/functions this job hooks (for conflict detection).
34
34
  priority: Job priority (lower = higher priority, default 50).
35
- state: Current state ("initialized", "running", "stopping").
35
+ state: Current state ("initialized", "running", "stopping", "error", "stopped").
36
36
  started_at: Timestamp when job was started (None if not started).
37
37
  """
38
38
 
@@ -75,6 +75,50 @@ class Job:
75
75
  self.priority = priority
76
76
  self.started_at: Optional[datetime.datetime] = None
77
77
 
78
+ # State propagation for callers to wait on job readiness
79
+ self._ready_event = threading.Event()
80
+ self._error_message: Optional[str] = None
81
+
82
+ def _set_state(self, new_state: str, error_msg: Optional[str] = None) -> None:
83
+ """Set state and signal ready event if terminal state reached.
84
+
85
+ Args:
86
+ new_state: New state value ("initialized", "running", "error", "stopping", "stopped").
87
+ error_msg: Optional error message when transitioning to "error" state.
88
+ """
89
+ self.state = new_state
90
+ if error_msg:
91
+ self._error_message = error_msg
92
+ # Signal ready event when job reaches a terminal state (running, error, stopped)
93
+ if new_state in ("running", "error", "stopped"):
94
+ self._ready_event.set()
95
+
96
+ def wait_until_ready(self, timeout: float = 10.0) -> bool:
97
+ """Wait for job to reach running or error state.
98
+
99
+ Blocks until the job thread signals that hooks have been loaded
100
+ successfully (state="running") or an error occurred (state="error").
101
+
102
+ Args:
103
+ timeout: Maximum seconds to wait (default: 10.0).
104
+
105
+ Returns:
106
+ True if job is running successfully, False if error or timeout.
107
+ """
108
+ if self._ready_event.wait(timeout=timeout):
109
+ return self.state == "running"
110
+ # Timeout occurred
111
+ self._error_message = f"Timeout waiting for job to start after {timeout}s"
112
+ return False
113
+
114
+ def get_error(self) -> Optional[str]:
115
+ """Get error message if job failed.
116
+
117
+ Returns:
118
+ Error message string if job is in error state, None otherwise.
119
+ """
120
+ return self._error_message
121
+
78
122
 
79
123
  def create_job_script(self):
80
124
  self.instrument(self.process_session)
@@ -93,18 +137,39 @@ class Job:
93
137
 
94
138
 
95
139
  def invoke_handle_hooking(self):
96
- if self.is_script_created == False:
97
- self.instrument(self.process_session)
98
- self.is_script_created = True
99
- self.script.on("message", self.wrap_custom_hooking_handler_with_job_id(self.custom_hooking_handler))
100
- self.script.load()
101
- self.state = "running"
102
- self.logger.info("[+] hooks successfully loaded")
103
-
104
- #if self.is_running_as_thread:
105
- # Keep the thread alive to handle messages until stop_event is set
106
- while not self.stop_event.is_set():
107
- self.stop_event.wait(1) # Sleep for 1 second and check again
140
+ try:
141
+ if self.is_script_created == False:
142
+ self.instrument(self.process_session)
143
+ self.is_script_created = True
144
+ self.script.on("message", self.wrap_custom_hooking_handler_with_job_id(self.custom_hooking_handler))
145
+ self.script.load()
146
+ self._set_state("running")
147
+ self.logger.info("[+] hooks successfully loaded")
148
+
149
+ #if self.is_running_as_thread:
150
+ # Keep the thread alive to handle messages until stop_event is set
151
+ while not self.stop_event.is_set():
152
+ self.stop_event.wait(1) # Sleep for 1 second and check again
153
+ except frida.TransportError as e:
154
+ error_msg = f"TransportError during script load: {e} - target app may have crashed or restarted"
155
+ self._set_state("error", error_msg)
156
+ self.logger.error(f"[-] {error_msg}")
157
+ except frida.InvalidOperationError as e:
158
+ error_msg = f"InvalidOperationError during script load: {e}"
159
+ self._set_state("error", error_msg)
160
+ self.logger.error(f"[-] {error_msg}")
161
+ except frida.ProcessNotFoundError as e:
162
+ error_msg = f"ProcessNotFoundError: Target process no longer exists: {e}"
163
+ self._set_state("error", error_msg)
164
+ self.logger.error(f"[-] {error_msg}")
165
+ except frida.ProtocolError as e:
166
+ error_msg = f"ProtocolError: Connection issue with target: {e}"
167
+ self._set_state("error", error_msg)
168
+ self.logger.error(f"[-] {error_msg}")
169
+ except Exception as e:
170
+ error_msg = f"Unexpected error in hook thread: {type(e).__name__}: {e}"
171
+ self._set_state("error", error_msg)
172
+ self.logger.error(f"[-] {error_msg}")
108
173
 
109
174
 
110
175
  def wrap_custom_hooking_handler_with_job_id(self, handler):
@@ -137,6 +202,12 @@ class Job:
137
202
  def close_job(self, timeout: float = 5.0) -> bool:
138
203
  """Stop the job and cleanup resources.
139
204
 
205
+ Uses a staged shutdown approach:
206
+ 1. Set stop_event FIRST to signal thread to exit wait loop
207
+ 2. Wait briefly for thread to notice stop_event
208
+ 3. Try to unload script (may hang if connection broken)
209
+ 4. Set final stopped state
210
+
140
211
  Args:
141
212
  timeout: Maximum seconds to wait for thread to stop.
142
213
  Default 5.0 seconds. Use 0 for no wait.
@@ -144,24 +215,31 @@ class Job:
144
215
  Returns:
145
216
  True if job stopped cleanly, False if timed out.
146
217
  """
147
- self.state = "stopping"
218
+ self._set_state("stopping")
219
+
220
+ # Step 1: Signal thread to exit wait loop FIRST
148
221
  self.stop_event.set()
149
222
 
223
+ # Step 2: Wait for thread to notice stop_event (short timeout)
224
+ thread_timeout = min(1.0, timeout) if timeout > 0 else 1.0
150
225
  timed_out = False
151
226
  if self.thread and self.thread.is_alive():
152
- self.thread.join(timeout=timeout if timeout > 0 else None)
227
+ self.thread.join(timeout=thread_timeout)
153
228
  if self.thread.is_alive():
154
229
  self.logger.warning(
155
- f"Job {self.job_id} thread did not stop within {timeout}s"
230
+ f"Job {self.job_id} thread did not stop within {thread_timeout}s"
156
231
  )
157
232
  timed_out = True
158
233
 
159
- # Try to unload script even if thread timed out
234
+ # Step 3: Try to unload script (may hang if connection broken)
160
235
  if self.script:
161
236
  try:
162
237
  self.script.unload()
163
238
  except Exception as e:
164
- self.logger.warning(f"Error unloading script: {e}")
239
+ self.logger.warning(f"Script unload failed (connection may be broken): {e}")
240
+
241
+ # Step 4: Set final state
242
+ self._set_state("stopped")
165
243
 
166
244
  status = "timed out" if timed_out else "stopped"
167
245
  self.logger.info(f"Job {self.job_id} {status}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AndroidFridaManager
3
- Version: 1.9.5
3
+ Version: 1.9.6
4
4
  Summary: A python API in order to install and run the frida-server on an Android device.
5
5
  Home-page: https://github.com/fkie-cad/AndroidFridaManager
6
6
  Author: Daniel Baier
@@ -33,7 +33,7 @@ Dynamic: requires-dist
33
33
  Dynamic: requires-python
34
34
  Dynamic: summary
35
35
 
36
- ![version](https://img.shields.io/badge/version-1.9.5-blue) [![PyPI version](https://badge.fury.io/py/AndroidFridaManager.svg)](https://badge.fury.io/py/AndroidFridaManager) [![Publish status](https://github.com/fkie-cad/friTap/actions/workflows/publish.yml/badge.svg?branch=main)](https://github.com/fkie-cad/AndroidFridaManager/actions/workflows/publish-to-pypi.yml)
36
+ ![version](https://img.shields.io/badge/version-1.9.6-blue) [![PyPI version](https://badge.fury.io/py/AndroidFridaManager.svg)](https://badge.fury.io/py/AndroidFridaManager) [![Publish status](https://github.com/fkie-cad/friTap/actions/workflows/publish.yml/badge.svg?branch=main)](https://github.com/fkie-cad/AndroidFridaManager/actions/workflows/publish-to-pypi.yml)
37
37
 
38
38
  # AndroidFridaManager
39
39
 
@@ -0,0 +1,11 @@
1
+ AndroidFridaManager/FridaManager.py,sha256=pTcis4oLPBN5U7CdBqdUufwuG6QQDWTPBleTC7rtTbI,32145
2
+ AndroidFridaManager/__init__.py,sha256=T6AKtrGSLQ9M5bJoWDQcsRTJbSEbksdgrx3AAAdozRI,171
3
+ AndroidFridaManager/about.py,sha256=tytVSs7JHtb8wVUCXH89lg4vd5mn04MrHfzmOgihOUQ,98
4
+ AndroidFridaManager/job.py,sha256=jDDaqiG_ri-vAwwk045X80mzftd8INxh7UIv9YOELDU,10525
5
+ AndroidFridaManager/job_manager.py,sha256=Ce2lHLezRVKuj7r_RodH6Q8l43zL_cL5ZGhE1zGB-E8,27336
6
+ androidfridamanager-1.9.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
7
+ androidfridamanager-1.9.6.dist-info/METADATA,sha256=Dmw-7QAphEDeTviAvvTbHllZzksDSnO7lSfdgAF-3Xw,5141
8
+ androidfridamanager-1.9.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
9
+ androidfridamanager-1.9.6.dist-info/entry_points.txt,sha256=GmNngu2fDNCxUcquFRegBa7GWknPKG1jsM4lvWeyKnY,64
10
+ androidfridamanager-1.9.6.dist-info/top_level.txt,sha256=oH2lVMSRlghmt-_tVrOEUqvY462P9hd5Ktgp5-1qF3o,20
11
+ androidfridamanager-1.9.6.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- AndroidFridaManager/FridaManager.py,sha256=pTcis4oLPBN5U7CdBqdUufwuG6QQDWTPBleTC7rtTbI,32145
2
- AndroidFridaManager/__init__.py,sha256=T6AKtrGSLQ9M5bJoWDQcsRTJbSEbksdgrx3AAAdozRI,171
3
- AndroidFridaManager/about.py,sha256=wGo_88YOuzXo2vF1EyCEmIO4uxM7wOJLC-FrGLp__Mw,98
4
- AndroidFridaManager/job.py,sha256=Yzir0XkkpFj5cFIcMRGJlLnIcIuDVZ9jBLFMqwQKTFA,7041
5
- AndroidFridaManager/job_manager.py,sha256=Ce2lHLezRVKuj7r_RodH6Q8l43zL_cL5ZGhE1zGB-E8,27336
6
- androidfridamanager-1.9.5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
7
- androidfridamanager-1.9.5.dist-info/METADATA,sha256=pjOCtO1KPNhyybRz8O5a56LXfeTqnKRcm0P0Kii5kpA,5141
8
- androidfridamanager-1.9.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
9
- androidfridamanager-1.9.5.dist-info/entry_points.txt,sha256=GmNngu2fDNCxUcquFRegBa7GWknPKG1jsM4lvWeyKnY,64
10
- androidfridamanager-1.9.5.dist-info/top_level.txt,sha256=oH2lVMSRlghmt-_tVrOEUqvY462P9hd5Ktgp5-1qF3o,20
11
- androidfridamanager-1.9.5.dist-info/RECORD,,