This document describes the current repository as a starting point for future development. It is based on the implementation in the repository, not only on the intended product behavior.
The app enrolls an Android device into a MeshCentral server and exposes a mobile-specific subset of the MeshCentral agent protocol. Its main capabilities are:
mc:// deep link, or manual
pairing-link entry.The remote desktop implementation is currently view only. Protocol handlers for keyboard, mouse, Unicode key, and input-lock messages exist, but they are no-ops. This app does not currently provide general remote input control.
| Item | Current value |
|---|---|
| Project type | Single-module Android application, Kotlin and XML views |
| Module | app |
| Application ID | com.meshcentral.agent2 |
| Kotlin namespace | com.meshcentral.agent |
| Minimum Android SDK | 23 (Android 6.0) |
| Compile/target SDK | 37 |
| Version | 1.0.23 (versionCode 30) |
| Kotlin | Built into the Android Gradle Plugin |
| Android Gradle Plugin | 9.3.1 |
| Gradle wrapper | 9.5.0 |
| Java/Kotlin target | JVM 17 |
The package namespace and installed application ID intentionally differ in the current build configuration. Keep that distinction in mind when working with Firebase configuration, manifests, or package-sensitive integrations.
flowchart LR
User[Device user] --> UI[MainActivity and fragments]
UI --> Pairing[Pairing link and preferences]
Pairing --> Agent[MeshAgent control channel]
FCM[Firebase Cloud Messaging] --> Push[MeshFirebaseMessagingService]
Push --> UI
Push --> Agent
Agent <-->|WSS /agent.ashx| Server[MeshCentral server]
Agent --> Tunnel[MeshTunnel relay channels]
Tunnel <-->|WSS /meshrelay.ashx| Server
Tunnel --> Capture[ScreenCaptureService]
Tunnel --> Media[MediaStore and shared storage]
Capture --> Projection[Android MediaProjection]
This is a compact, stateful application rather than a layered Android
architecture. MainActivity.kt declares process-wide top-level variables for
the active activity, fragments, server link, agent, tunnels, screen-capture
service, desktop settings, and pending 2FA request. The principal classes refer
to this shared state directly.
MainActivity.kt is the application coordinator. It loads pairing data,
generates or loads the agent identity, requests runtime permissions, starts
and stops the agent, manages reconnect behavior, launches MediaProjection,
displays local alerts/notifications, and applies settings.MainFragment.kt is the home/status screen. It shows pairing and connection
state, server branding, and users with active tunnel sessions.ScannerFragment.kt scans and validates mc:// pairing QR codes. Pairing can
also be entered manually or received through the manifest’s mc deep-link
intent filter.AuthFragment.kt displays a decoded 2FA code with approve and reject actions.
Requests expire after approximately 60 seconds.SettingsFragment.kt exposes automatic connection and automatic screen-share
consent preferences.WebViewFragment.kt provides an in-app browser used by the openurl console
command. A separate openbrowser command launches the system browser.nav_graph.xml defines navigation from the home screen to scanner, browser,
authentication, and settings screens.MeshAgent.kt owns the long-lived control connection to
wss://<server>/agent.ashx using OkHttp. Its state values are:
| State | Meaning |
|---|---|
| 0 | Disconnected |
| 1 | Connecting |
| 2 | Authenticating |
| 3 | Connected and authenticated |
The handshake uses a 2048-bit RSA identity held in Android Keystore. New identities receive a self-signed X.509 certificate; existing identities are imported from older installations. The app exchanges nonces, validates the server identity from the pairing link, signs the handshake, and then sends Android agent metadata and capabilities. Once connected, the control channel:
The connection advertises MeshCentral capabilities for files and console access in addition to the mobile/desktop-view capability.
MeshTunnel.kt creates a separate pinned WebSocket for each MeshCentral relay
session. Implemented tunnel usages are:
The virtual roots presented to MeshCentral are Sdcard, Images, Audio, and
Videos. Behavior differs across Android versions because Android 10 and later
use scoped MediaStore APIs while older versions use public storage paths.
ScreenCaptureService.kt is a foreground service with the mediaProjection
service type. The flow is:
MainActivity launches Android’s
MediaProjection consent UI.ImageReader.Captured data is broadcast to all connected remote-desktop tunnels. Capture is stopped when the user stops it, the agent disconnects, or no desktop tunnel remains.
MeshFirebaseMessagingService.kt receives FCM tokens and messages. Incoming
messages are accepted only after their abbreviated server hash matches the
stored pairing link. Depending on payload, the service can:
2fa:// URL to the approval UI.MainActivity to show a standard Android notification, optionally with a
URL action.flash, netinfo, sysinfo, and
vibrate) and send a response through FCM.For 2FA, AuthFragment extracts and Base64-decodes the code query parameter.
The user’s decision is sent over the authenticated control WebSocket by
MeshAgent.send2faAuth.
The connected agent channel supports commands for:
alert, toast, openurl, openbrowser, uiclose, and uistate.dial, flash, and vibrate.battery, netinfo, storageinfo, and sysinfo.kvmstart, kvmstop, serverlog, and help.Commands and relevant actions are logged back to the server. Some actions open Android UI or require an active activity and therefore are not silent background management operations.
mc://host,serverHash,deviceGroupId link.qrmsh in the meshagent SharedPreferences file.agentCert and
agentKey preferences, or generates a new identity when none exists.
The legacy entries are removed after the identity is loaded successfully.MeshAgent connects to /agent.ashx and authenticates both sides using the
pairing data, TLS certificate hash, nonces, and signatures.The build also supports a source-level hardCodedServerLink. When populated,
users cannot replace or clear the configured server.
ScreenCaptureService sends changed image regions through every active
desktop tunnel.Persistent state is held in Android Keystore and two SharedPreferences stores:
meshcentral-agent-identity alias.meshagent preferences: the pairing link (qrmsh). Legacy certificate and
key entries remain here only until identity migration succeeds.Most live state is held in process-wide Kotlin variables. There is no database, repository layer, dependency injection container, or persistent background work scheduler. A process restart reconstructs state from preferences and FCM, then reconnects only when the current settings and Android lifecycle permit it.
The manifest declares:
INTERNET, VIBRATE, and CAMERA.POST_NOTIFICATIONS.READ_MEDIA_IMAGES, READ_MEDIA_AUDIO, and
READ_MEDIA_VIDEO.READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE,
with legacy external-storage behavior requested by the application.FOREGROUND_SERVICE and
FOREGROUND_SERVICE_MEDIA_PROJECTION.The camera is optional hardware. The manifest registers MainActivity, the FCM
service, and ScreenCaptureService. It also removes Google Mobile Ads’ AD_ID
permission during manifest merging.
The main external dependencies are:
Identity generation and signing use Android Keystore and the platform Java security APIs. Dependencies resolve through Google, Maven Central and JitPack.
app/
build.gradle Android module configuration
google-services.json Firebase application configuration
proguard-rules.pro Release shrinker rules
src/main/
AndroidManifest.xml Permissions, activity, and services
java/com/meshcentral/agent/
MainActivity.kt App lifecycle and coordinator
MainFragment.kt Home and connection status
ScannerFragment.kt QR pairing
AuthFragment.kt 2FA approval
SettingsFragment.kt Preference screen
WebViewFragment.kt In-app browser
MeshAgent.kt Authenticated control channel
MeshTunnel.kt Desktop/file relay channels
ProtocolValidation.kt Pairing, tunnel and file-path validation
ScreenCaptureService.kt MediaProjection screen encoder
MeshFirebaseMessagingService.kt FCM handling
NotificationUtils.kt Foreground-service notification
res/ Layouts, navigation, strings, themes, icons
src/test/java/com/meshcentral/agent/
ProtocolValidationTest.kt JVM validation tests
The release workflow uses JDK 17, Android Gradle Plugin 9.3.1 and Gradle 9.5.0.
Install Android SDK 37 and use the repository’s Gradle wrapper. Kotlin support
is provided by AGP.
Confirm that JAVA_HOME and java -version select the intended JDK.
From the repository root on Windows:
.\gradlew.bat assembleDebug
Useful related tasks include:
.\gradlew.bat lintDebug
.\gradlew.bat testDebugUnitTest
.\gradlew.bat clean
The JUnit tests in ProtocolValidationTest.kt cover pairing-link validation,
tunnel usage checks and file-path containment. Device behavior still requires
manual testing against Android devices and a MeshCentral server.
See Creating a release for production signing, version tags and publishing APK and AAB assets.
For device-level verification, exercise at least:
These are current implementation characteristics to review before broad changes, not a complete security audit: