# psiphon-inc/psiphon-android architecture

> Architecture diagram of the GitHub repository psiphon-inc/psiphon-android, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-22). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/psiphon-inc/psiphon-android
- Repository: https://github.com/psiphon-inc/psiphon-android

## Overview

1. **Overall shape**
   - This is an Android VPN/proxy client for Psiphon.
   - The repository is split into two Gradle modules:
     - `app`: the actual Android client app.
     - `tray`: an embedded preference-storage library used by the app.
   - The app combines a Java/Kotlin-free Android UI layer with a substantial native networking layer built from `badvpn`/`tun2socks`.

2. **User-facing app shell**
   - `MainActivity` is the main entry point and hosts the top-level tabbed UI.
   - The primary screens are organized into fragments such as `HomeTabFragment`, `OptionsTabFragment`, `LogsTabFragment`, and `StatisticsTabFragment`.
   - Supporting activities handle permissions, onboarding/help, feedback, and Psiphon-specific NFC “bump” flows.

3. **Tunnel control plane**
   - The core orchestration lives under `com.psiphon3.psiphonlibrary`.
   - `TunnelManager`, `TunnelServiceInteractor`, `TunnelVpnService`, and `VpnManager` coordinate starting, stopping, and monitoring the VPN tunnel.
   - `TunnelState` represents the connection lifecycle, while `MainActivityViewModel` likely exposes that state to the UI.

4. **VPN and routing boundary**
   - The app uses Android’s VPN service model as the boundary between device traffic and the Psiphon tunnel.
   - `VpnRulesHelper`, `VpnAppsUtils`, and related preference activities manage which apps/routes are included or excluded.
   - This is the point where user configuration becomes actual device routing behavior.

5. **Native networking engine**
   - The `app/src/main/jni/badvpn` tree contains the low-level tunnel implementation, including `tun2socks`, `udpgw`, `lwip`, and networking utilities.
   - Java loads native code through `ca.psiphon.Tun2SocksJniLoader`.
   - The native layer is responsible for moving packets from the Android VPN interface into socket-based network traffic and back again.

6. **Configuration and protocol handling**
   - The native code includes large generated and protocol-oriented subsystems (`protocol`, `ncd`, `generated`, `server_connection`, `socksclient`, `udpgw_client`).
   - These pieces suggest a modular native control/configuration system, with packet framing, SOCKS/UDP gateway handling, and connection management separated from the Android UI.
   - The Java app configures this engine rather than implementing packet forwarding itself.

7. **State, preferences, and persistence**
   - Persistent settings are split across standard Android preferences and the bundled `tray` library.
   - `tray` provides a content-provider-backed storage layer with SQLite helpers and typed preference accessors.
   - In the app, helpers like `SharedPreferenceUtils`, `SafeFileStorage`, `PackageHelper`, and various preference activities manage stored state, migrations, and app-specific configuration.

8. **Logging and diagnostics**
   - Logging is a distinct subsystem under `com.psiphon3.log`.
   - `LoggingContentProvider`, `LogEntryDao`, `LogsDataSourceFactory`, `LogsMaintenanceWorker`, and `LogsLastEntryHelper` provide structured log persistence and cleanup.
   - `LogsTabFragment` and `LogsListAdapter` expose those logs in the UI.
   - This is an important boundary because tunnel/network events are persisted separately from the main app state.

9. **Feedback and crash handling**
   - `FeedbackActivity`, `FeedbackWorker`, and the `assets/feedback.html` template support user feedback submission.
   - `PsiphonCrashService` and the included `jndcrash` AAR indicate dedicated crash reporting/handling.
   - These flows are operationally separate from tunnel management but fed by app state and logs.

10. **Update and lifecycle hooks**
    - `PsiphonUpdateReceiver` handles app/package update events.
    - `UpgradeChecker` and `UpgradeManager` encapsulate version/update logic.
    - `PsiphonApplication` is the process-level initialization point for global app setup.

11. **Localization and content assets**
    - The repo has extensive locale coverage in `res/values-*` and localized layout variants.
    - The `i18n` directory contains translation tooling and feedback template generation.
    - `assets/startpage` and other bundled assets provide built-in content shown by the app.

12. **External dependencies that matter architecturally**
    - The app uses packaged third-party binaries/libraries: `ca.psiphon.aar`, `achartengine`, `jackson-core`, `snakeyaml`, and `jndcrash`.
    - `achartengine` is likely used for statistics visualization.
    - `jackson`/`snakeyaml` suggest structured configuration/data parsing in the client or its bundled libraries.

13. **How the main data flow works**
    - User interaction starts in `MainActivity` and fragments.
    - Preferences and actions are passed into the Psiphon library layer.
    - That layer drives `TunnelVpnService` / `VpnManager`, which hands traffic to the native `tun2socks`/`badvpn` stack.
    - Runtime events, logs, and statistics are written back to persistence and surfaced in the UI.
    - Feedback/crash/update flows reuse the same persisted state but remain separate from the live tunnel path.

14. **Diagram boundaries to draw**
    - Treat the UI, tunnel orchestration, persistence/logging, and native networking as four separate boxes.
    - The most important boundary is the Java-to-native JNI bridge feeding the VPN/tunnel engine.
    - A second key boundary is the app’s storage layer: user preferences and logs are stored via different mechanisms and consumed by different UI surfaces.

Main entry points: [`app/src/main/java/com/psiphon3/MainActivity.java`](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/MainActivity.java) (MainActivity), [`app/src/main/jni/badvpn/tun2socks/tun2socks.c`](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/tun2socks/tun2socks.c) (tun2socks), [`app/src/main/java/com/psiphon3/psiphonlibrary/TunnelManager.java`](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelManager.java) (TunnelManager), [`app/src/main/java/com/psiphon3/VpnManager.java`](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/VpnManager.java) (VpnManager)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app_shell["App shell"]
  node_main_activity["MainActivity<br/>android entry<br/>[MainActivity.java]"]
  node_home_fragment["Home Tab<br/>ui fragment"]
  node_options_fragment["Options Tab<br/>ui fragment"]
  node_logs_fragment["Logs Tab<br/>ui fragment"]
  node_stats_fragment["Stats Tab<br/>ui fragment"]
  node_view_model["ViewModel<br/>ui state"]
end

subgraph group_tunnel["Tunnel control"]
  node_tunnel_manager["TunnelManager<br/>control plane<br/>[TunnelManager.java]"]
  node_service_interactor["Service Interactor<br/>service bridge"]
  node_vpn_service["TunnelVpnService<br/>vpn service"]
  node_vpn_manager["VpnManager<br/>routing<br/>[VpnManager.java]"]
  node_vpn_rules["VpnRulesHelper<br/>routing rules"]
end

subgraph group_storage["Storage & logs"]
  node_log_provider["Logging Provider<br/>log persistence"]
  node_safe_storage["Safe Storage<br/>file storage"]
end

subgraph group_native["Native engine"]
  node_jni_loader["Jni Loader<br/>jni bridge"]
  node_tun2socks["tun2socks<br/>native tunnel core<br/>[tun2socks.c]"]
  node_udpgw["udpgw<br/>native udp relay<br/>[udpgw.c]"]
  node_server_conn["ServerConnection<br/>native session<br/>[ServerConnection.c]"]
  node_native_proto["Protocols<br/>native protocol layer<br/>[spproto.h]"]
end

subgraph group_tray["Tray library"]
  node_tray_core["Tray<br/>preference storage<br/>[Tray.java]"]
  node_tray_provider["Tray Provider<br/>storage provider"]
end

node_main_activity -->|"hosts"| node_home_fragment
node_main_activity -->|"hosts"| node_options_fragment
node_main_activity -->|"hosts"| node_logs_fragment
node_main_activity -->|"hosts"| node_stats_fragment
node_main_activity -->|"binds"| node_view_model
node_view_model -->|"controls"| node_tunnel_manager
node_tunnel_manager -->|"starts"| node_service_interactor
node_service_interactor -->|"binds"| node_vpn_service
node_vpn_service -->|"delegates"| node_vpn_manager
node_vpn_manager -->|"applies"| node_vpn_rules
node_vpn_manager -->|"loads"| node_jni_loader
node_jni_loader -->|"bridges"| node_tun2socks
node_tun2socks -->|"uses"| node_udpgw
node_tun2socks -->|"connects"| node_server_conn
node_tun2socks -->|"encodes"| node_native_proto
node_tunnel_manager -->|"writes"| node_log_provider
node_logs_fragment -->|"reads"| node_log_provider
node_stats_fragment -->|"observes"| node_tunnel_manager
node_options_fragment -->|"reads/writes"| node_tray_core
node_tray_core -->|"stores"| node_tray_provider
node_safe_storage -.->|"adjacent"| node_tray_core

click node_main_activity "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/MainActivity.java"
click node_home_fragment "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/HomeTabFragment.java"
click node_options_fragment "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/OptionsTabFragment.java"
click node_logs_fragment "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/LogsTabFragment.java"
click node_stats_fragment "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/StatisticsTabFragment.java"
click node_view_model "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/MainActivityViewModel.java"
click node_tunnel_manager "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelManager.java"
click node_service_interactor "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelServiceInteractor.java"
click node_vpn_service "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelVpnService.java"
click node_vpn_manager "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/VpnManager.java"
click node_vpn_rules "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/VpnRulesHelper.java"
click node_jni_loader "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/ca/psiphon/Tun2SocksJniLoader.java"
click node_tun2socks "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/tun2socks/tun2socks.c"
click node_udpgw "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/udpgw/udpgw.c"
click node_server_conn "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/server_connection/ServerConnection.c"
click node_native_proto "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/protocol/spproto.h"
click node_log_provider "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/log/LoggingContentProvider.java"
click node_safe_storage "https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/SafeFileStorage.java"
click node_tray_core "https://github.com/psiphon-inc/psiphon-android/blob/master/tray/src/main/java/net/grandcentrix/tray/Tray.java"
click node_tray_provider "https://github.com/psiphon-inc/psiphon-android/blob/master/tray/src/main/java/net/grandcentrix/tray/provider/TrayContentProvider.java"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_main_activity,node_home_fragment,node_options_fragment,node_logs_fragment,node_stats_fragment,node_view_model toneBlue
class node_tunnel_manager,node_service_interactor,node_vpn_service,node_vpn_manager,node_vpn_rules toneAmber
class node_log_provider,node_safe_storage toneMint
class node_jni_loader,node_tun2socks,node_udpgw,node_server_conn,node_native_proto toneRose
class node_tray_core,node_tray_provider toneIndigo
```

## Components

### App shell

Main activity, tabs, onboarding, permissions, and user-facing screens.

- [MainActivity](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/MainActivity.java): android entry · Top-level activity hosting the client UI. · `app/src/main/java/com/psiphon3/MainActivity.java`
- [Home Tab](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/HomeTabFragment.java): ui fragment · Primary connection/status screen. · `app/src/main/java/com/psiphon3/HomeTabFragment.java`
- [Options Tab](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/OptionsTabFragment.java): ui fragment · Settings and configuration surface. · `app/src/main/java/com/psiphon3/OptionsTabFragment.java`
- [Logs Tab](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/LogsTabFragment.java): ui fragment · Log viewer surface. · `app/src/main/java/com/psiphon3/LogsTabFragment.java`
- [Stats Tab](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/StatisticsTabFragment.java): ui fragment · Connection statistics and charts. · `app/src/main/java/com/psiphon3/StatisticsTabFragment.java`
- [ViewModel](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/MainActivityViewModel.java): ui state · UI-facing tunnel state and coordination state. · `app/src/main/java/com/psiphon3/MainActivityViewModel.java`

### Tunnel control

Java-side orchestration of VPN lifecycle and routing decisions.

- [TunnelManager](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelManager.java): control plane · Starts, stops, and monitors the Psiphon tunnel. · `app/src/main/java/com/psiphon3/psiphonlibrary/TunnelManager.java`
- [Service Interactor](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelServiceInteractor.java): service bridge · Binds app logic to the VPN service lifecycle. · `app/src/main/java/com/psiphon3/psiphonlibrary/TunnelServiceInteractor.java`
- [TunnelVpnService](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/psiphonlibrary/TunnelVpnService.java): vpn service · Android VPNService boundary for tunnel traffic. · `app/src/main/java/com/psiphon3/psiphonlibrary/TunnelVpnService.java`
- [VpnManager](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/VpnManager.java): routing · Applies VPN routing and tunnel configuration. · `app/src/main/java/com/psiphon3/VpnManager.java`
- [VpnRulesHelper](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/VpnRulesHelper.java): routing rules · Resolves app/include-exclude routing policy. · `app/src/main/java/com/psiphon3/VpnRulesHelper.java`

### Storage & logs

Preferences, file state, and persisted log/event data.

- [Logging Provider](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/log/LoggingContentProvider.java): log persistence · Structured log storage and maintenance. · `app/src/main/java/com/psiphon3/log/LoggingContentProvider.java`
- [Safe Storage](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/com/psiphon3/SafeFileStorage.java): file storage · App-specific durable file storage helpers. · `app/src/main/java/com/psiphon3/SafeFileStorage.java`

### Native engine

JNI bridge and the embedded badvpn/tun2socks networking stack.

- [Jni Loader](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/java/ca/psiphon/Tun2SocksJniLoader.java): jni bridge · Loads the native tun2socks library into the app process. · `app/src/main/java/ca/psiphon/Tun2SocksJniLoader.java`
- [tun2socks](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/tun2socks/tun2socks.c): native tunnel core · Moves packets between the VPN interface and socket traffic. · `app/src/main/jni/badvpn/tun2socks/tun2socks.c`
- [udpgw](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/udpgw/udpgw.c): native udp relay · UDP gateway component used by the tunnel stack. · `app/src/main/jni/badvpn/udpgw/udpgw.c`
- [ServerConnection](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/server_connection/ServerConnection.c): native session · Native connection/session management for remote server links. · `app/src/main/jni/badvpn/server_connection/ServerConnection.c`
- [Protocols](https://github.com/psiphon-inc/psiphon-android/blob/master/app/src/main/jni/badvpn/protocol/spproto.h): native protocol layer · Generated and hand-written packet/protocol framing code. · `app/src/main/jni/badvpn/protocol/spproto.h`

### Tray library

Bundled content-provider preference storage module.

- [Tray](https://github.com/psiphon-inc/psiphon-android/blob/master/tray/src/main/java/net/grandcentrix/tray/Tray.java): preference storage · Bundled preference-storage library backed by a content provider. · `tray/src/main/java/net/grandcentrix/tray/Tray.java`
- [Tray Provider](https://github.com/psiphon-inc/psiphon-android/blob/master/tray/src/main/java/net/grandcentrix/tray/provider/TrayContentProvider.java): storage provider · SQLite/content-provider backend for tray preferences. · `tray/src/main/java/net/grandcentrix/tray/provider/TrayContentProvider.java`

## Connections

- MainActivity → Home Tab: hosts · Main activity displays the primary connection screen.
- MainActivity → Options Tab: hosts · Main activity exposes settings and options.
- MainActivity → Logs Tab: hosts · Main activity exposes log viewing.
- MainActivity → Stats Tab: hosts · Main activity exposes statistics.
- MainActivity → ViewModel: binds · Activity consumes shared tunnel state.
- ViewModel → TunnelManager: controls · ViewModel reflects and drives tunnel lifecycle state.
- TunnelManager → Service Interactor: starts · Coordinates service binding and tunnel operations.
- Service Interactor → TunnelVpnService: binds · Manages the VPN service boundary.
- TunnelVpnService → VpnManager: delegates · Service hands routing/control decisions to VPN manager.
- VpnManager → VpnRulesHelper: applies · VPN manager turns user policy into routing behavior.
- VpnManager → Jni Loader: loads · VPN setup initializes the native tunnel engine.
- Jni Loader → tun2socks: bridges · Java loads the native packet-forwarding core.
- tun2socks → udpgw: uses · Native tunnel stack relies on UDP gateway support.
- tun2socks → ServerConnection: connects · Tunnel core establishes and manages remote sessions.
- tun2socks → Protocols: encodes · Packet flow uses shared protocol/framing definitions.
- TunnelManager → Logging Provider: writes · Tunnel events are persisted for diagnostics.
- Logs Tab → Logging Provider: reads · Log UI reads structured persisted logs.
- Stats Tab → TunnelManager: observes · Statistics derive from tunnel/runtime metrics.
- Options Tab → Tray: reads/writes · Settings use the tray preference layer.
- Tray → Tray Provider: stores · Tray persists preferences via its content provider backend.
- Safe Storage → Tray: adjacent · App-specific storage complements preference storage.
