spawn_and_attach
Force stop an Android app, launch it fresh, and attach Frida for reliable hooking. Avoids timeouts common with connect(spawn=True).
Instructions
Force stop app, launch fresh, and attach Frida. The reliable alternative to connect(spawn=True) which often times out.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| package | Yes | App package name (e.g., 'com.bestbuy.android') | |
| device_id | No | Device ID (optional) | |
| wait_ms | No | Time to wait for app to start in ms (default: 3000) |
Implementation Reference
- src/frida_mcp/device.py:211-217 (handler)The handler function that implements the spawn_and_attach tool logic. It force-stops the app, launches fresh, and attaches Frida by delegating to connect() with spawn=True.
def spawn_and_attach( package: str, device_id: str | None = None, wait_ms: int = 5000, ) -> dict: """Force stop app, launch fresh, and attach Frida.""" return connect(package, device_id, spawn=True, timeout_ms=wait_ms) - src/frida_mcp/tools.py:111-123 (schema)The Tool definition with inputSchema for spawn_and_attach, declaring 'package' (required string), 'device_id' (optional string), and 'wait_ms' (optional integer).
Tool( name="spawn_and_attach", description="Force stop app, launch fresh, and attach Frida. The reliable alternative to connect(spawn=True) which often times out.", inputSchema={ "type": "object", "properties": { "package": {"type": "string", "description": "App package name (e.g., 'com.bestbuy.android')"}, "device_id": {"type": "string", "description": "Device ID (optional)"}, "wait_ms": {"type": "integer", "description": "Time to wait for app to start in ms (default: 3000)"}, }, "required": ["package"], }, ), - src/frida_mcp/server.py:54-59 (registration)The dispatch/registration point in server.py that routes 'spawn_and_attach' calls to device.spawn_and_attach().
elif name == "spawn_and_attach": return device.spawn_and_attach( arguments["package"], arguments.get("device_id"), arguments.get("wait_ms", 3000), ) - src/frida_mcp/device.py:58-159 (helper)The connect() function that spawn_and_attach delegates to. It handles force-stopping the app, launching via monkey, waiting for PID, attaching Frida, and loading the agent.
def connect( target: str, device_id: str | None = None, spawn: bool = False, timeout_ms: int = 15000, ) -> dict: """Connect to an app by name/bundle ID or PID.""" # Disconnect existing active session active = registry.get_active() if active: registry.remove(active.id) # Get device if device_id: device = frida.get_device(device_id) else: device = frida.get_usb_device(timeout=10) # Ensure SELinux is permissive selinux_status = ensure_selinux_permissive(device_id) # Determine if target is PID or name pid = None spawn_method = None try: pid = int(target) frida_session = device.attach(pid) target_name = target except ValueError: if spawn: # Force stop the app adb_shell(["am", "force-stop", target], device_id) # Wait for process to die for _ in range(10): time_module.sleep(0.2) if not adb_shell(["pidof", target], device_id): break time_module.sleep(0.3) # Launch via monkey adb_shell([ "monkey", "-p", target, "-c", "android.intent.category.LAUNCHER", "1" ], device_id) # Wait for PID pid = wait_for_pid(target, device_id, timeout_ms) frida_session = device.attach(pid) spawn_method = "adb_launch" else: frida_session = device.attach(target) target_name = target # Load agent agent_source = get_agent_source() script = frida_session.create_script(agent_source) actual_pid = pid if actual_pid is None: try: actual_pid = frida_session._impl.pid except Exception: actual_pid = 0 script.load() api = script.exports_sync # Register session fs = registry.create( device=device, session=frida_session, api=api, target=target_name, pid=actual_pid, ) # Message handler def on_message(message, data): if message["type"] == "send": payload = message['payload'] display = str(payload)[:200] + '...' if len(str(payload)) > 200 else str(payload) print(f"[FRIDA] {display}", file=sys.stderr) if isinstance(payload, str) and payload.startswith('['): fs.add_message("agent", payload) elif message["type"] == "error": print(f"[ERROR] {message.get('stack', message)}", file=sys.stderr) script.on("message", on_message) result = { "status": "connected", "session_id": fs.id, "device": device.name, "target": target_name, "pid": actual_pid, "selinux": selinux_status, } if spawn_method: result["spawn_method"] = spawn_method return result