# How Android START, STOP, and TOGGLE Intents Control FlClash's VPN Service

> Learn how Android START STOP and TOGGLE intents control FlClashs VPN service. Discover how TempActivity dispatches commands for external control via shortcuts quick settings or ADB.

- Repository: [chen08209/FlClash](https://github.com/chen08209/FlClash)
- Tags: how-to-guide
- Published: 2026-05-31

---

**FlClash processes Android START, STOP, and TOGGLE intents through a dedicated TempActivity that dispatches commands to the VPN service layer, enabling external control via shortcuts, quick settings tiles, or ADB commands.**

The chen08209/FlClash repository implements a lightweight intent-driven pipeline on Android that exposes VPN control actions to external system components. By declaring specific action strings and handling them through a transient entry point Activity, FlClash allows automation tools, quick settings tiles, and third-party launchers to start, stop, or toggle the VPN tunnel without launching the main application interface.

## Intent Definition and Construction

FlClash defines its external control interface through a sealed enum and extension functions that construct explicit intents targeting a hidden Activity.

### The QuickAction Enum

The three supported operations are declared in [`android/common/src/main/java/com/follow/clash/common/Enums.kt`](https://github.com/chen08209/FlClash/blob/main/android/common/src/main/java/com/follow/clash/common/Enums.kt) as the `QuickAction` enum (lines 6-10). This definition specifies the action strings for **START**, **STOP**, and **TOGGLE** operations that the system recognizes when broadcast to FlClash's package.

### Building Explicit Intents

The `quickIntent` extension function in [`android/common/src/main/java/com/follow/clash/common/Ext.kt`](https://github.com/chen08209/FlClash/blob/main/android/common/src/main/java/com/follow/clash/common/Ext.kt) (lines 60-66) constructs an explicit `Intent` targeting `TempActivity`. This function packages the selected `QuickAction` into an intent with the corresponding action string (e.g., `com.follow.clash.action.START`), preparing it for delivery via `startActivity()` or `PendingIntent` creation.

## The Intent Processing Pipeline

When an external component fires one of these intents, FlClash routes the command through several abstraction layers before touching the actual VPN interface.

### TempActivity Entry Point

[`android/app/src/main/kotlin/com/follow/clash/TempActivity.kt`](https://github.com/chen08209/FlClash/blob/main/android/app/src/main/kotlin/com/follow/clash/TempActivity.kt) serves as the intent receiver. In lines 16-34, `TempActivity` extracts the action string from the incoming intent, matches it against the `QuickAction` enum values, and immediately dispatches to the appropriate coroutine handler in the `State` object. This Activity has no UI and finishes immediately after delegating the work, ensuring minimal overhead.

### State-Level Command Serialization

The `State` class in [`android/app/src/main/kotlin/com/follow/clash/State.kt`](https://github.com/chen08209/FlClash/blob/main/android/app/src/main/kotlin/com/follow/clash/State.kt) contains the core logic for `handleStartServiceAction`, `handleStopServiceAction`, and `handleToggleAction` (lines 39-99). These methods serialize the request, update the quick settings tile state if present, and determine whether to invoke the service layer based on current VPN status. They prevent race conditions by managing service state through centralized coroutines.

### Service Abstraction and AIDL Binding

[`android/app/src/main/kotlin/com/follow/clash/Service.kt`](https://github.com/chen08209/FlClash/blob/main/android/app/src/main/kotlin/com/follow/clash/Service.kt) acts as a thin wrapper around a bound AIDL-based `RemoteService`. Lines 65-74 define `startService` and `stopService` methods that forward commands to the remote process. This abstraction separates the UI process from the VPN service process, allowing the VPN to persist even if the main app closes.

### VPN Core Execution

The actual tunnel creation occurs in [`android/service/src/main/java/com/follow/clash/service/VpnService.kt`](https://github.com/chen08209/FlClash/blob/main/android/service/src/main/java/com/follow/clash/service/VpnService.kt). This class extends Android's `VpnService` and implements `startService` (lines 29-34) and `stopService` (lines 36-44). These methods build the TUN interface using the Android VPN API and hand the file descriptor to the native Clash core through `Core.startTun` and `Core.stopTun`, bringing the VPN tunnel up or down as requested.

## Lifecycle Synchronization via BroadcastReceiver

To maintain UI consistency when the VPN starts or stops independently of direct intents, FlClash implements a broadcast mechanism. [`android/app/src/main/kotlin/com/follow/clash/BroadcastReceiver.kt`](https://github.com/chen08209/FlClash/blob/main/android/app/src/main/kotlin/com/follow/clash/BroadcastReceiver.kt) (lines 13-27) listens for `SERVICE_CREATED` and `SERVICE_DESTROYED` broadcasts. When received, it updates the `State` singleton, ensuring that quick settings tiles and in-app indicators reflect the true service status even when toggled via external intents.

## Practical Usage Examples

You can trigger FlClash's VPN service directly from ADB or integrate control into your own Android applications using the intent scheme.

### Triggering via ADB

Send a START intent from the command line:

```bash
adb shell am start -n com.follow.clash/.TempActivity \
    -a com.follow.clash.action.START

```

Send a STOP intent:

```bash
adb shell am start -n com.follow.clash/.TempActivity \
    -a com.follow.clash.action.STOP

```

Send a TOGGLE intent:

```bash
adb shell am start -n com.follow.clash/.TempActivity \
    -a com.follow.clash.action.TOGGLE

```

### Integrating in Kotlin Applications

Create a shortcut or quick settings tile using the extension functions:

```kotlin
val intent = QuickAction.START.quickIntent  // Or STOP / TOGGLE
val pendingIntent = intent.toPendingIntent    // See Ext.kt for conversion
// Attach pendingIntent to ShortcutInfo or TileBuilder

```

Fire an intent directly from another component:

```kotlin
val context: Context = GlobalState.application
context.startActivity(QuickAction.TOGGLE.quickIntent)

```

## Summary

- **Intent Definition**: `QuickAction` enum in [`Enums.kt`](https://github.com/chen08209/FlClash/blob/main/Enums.kt) defines START, STOP, and TOGGLE constants.
- **Entry Point**: `TempActivity` receives external intents and dispatches them to `State` handlers.
- **State Management**: [`State.kt`](https://github.com/chen08209/FlClash/blob/main/State.kt) serializes requests and manages the quick settings tile synchronization.
- **Service Layer**: [`Service.kt`](https://github.com/chen08209/FlClash/blob/main/Service.kt) forwards commands via AIDL to the remote VPN process.
- **VPN Execution**: [`VpnService.kt`](https://github.com/chen08209/FlClash/blob/main/VpnService.kt) creates the TUN interface and controls the native Clash core.
- **Synchronization**: [`BroadcastReceiver.kt`](https://github.com/chen08209/FlClash/blob/main/BroadcastReceiver.kt) listens for service lifecycle events to keep the UI updated.

## Frequently Asked Questions

### What permissions are required to send these intents to FlClash?

Applications sending these intents must typically hold standard Android permissions to start Activities in other packages. Since `TempActivity` handles the specific action strings, any app with `START_ACTIVITY` permission can trigger these intents. However, FlClash may enforce signature-level permissions or require the caller to be the system or a privileged app depending on the Android version and specific build configuration.

### Can these intents be triggered from a background service?

The intents target `TempActivity`, which is an Activity component. Therefore, they must be launched using `startActivity()` or via `PendingIntent` from notifications or shortcuts. Background services without a visible window generally cannot directly call `startActivity()` on these intents due to Android background execution limits unless they use `PendingIntent` or are bound to a foreground service context.

### How does FlClash handle rapid successive TOGGLE intents?

The `State` class in [`State.kt`](https://github.com/chen08209/FlClash/blob/main/State.kt) implements state validation in `handleToggleAction`. Before executing a start or stop command, it checks the current service status through the bound `Service` connection. If a toggle is already in progress or the requested state matches the current state, the coroutine exits early, preventing conflicting calls to the native VPN interface.

### What is the difference between using the STOP intent versus killing the FlClash app process?

Sending the STOP intent gracefully terminates the VPN tunnel by calling `VpnService.stopService`, which properly closes the TUN file descriptor and notifies the native Clash core via `Core.stopTun`. Killing the app process (via settings or `am force-stop`) terminates the VPN service abruptly without cleanup, potentially leaving routing rules or DNS settings in an inconsistent state until the system reclaims the VPN interface.