From dc6e3ec53bd82bf465cf9622b166b41cd1cca05c Mon Sep 17 00:00:00 2001 From: albexk Date: Tue, 5 Dec 2023 16:10:29 +0300 Subject: [PATCH] Add passing the VPN connection status when rebinding to the service --- client/amnezia_application.cpp | 10 ++--- .../src/main/kotlin/ProtocolState.kt | 1 + .../protocolApi/src/main/kotlin/Status.kt | 16 ++++---- .../src/org/amnezia/vpn/AmneziaActivity.kt | 4 +- .../src/org/amnezia/vpn/AmneziaVpnService.kt | 2 +- .../org/amnezia/vpn/qt/QtAndroidController.kt | 2 +- .../platforms/android/android_controller.cpp | 40 +++++++++++++++---- client/platforms/android/android_controller.h | 18 +++++++-- 8 files changed, 65 insertions(+), 28 deletions(-) diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 5af762d7..dcaae1b6 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -92,12 +92,10 @@ void AmneziaApplication::init() #ifdef Q_OS_ANDROID connect(AndroidController::instance(), &AndroidController::serviceIsAlive, this, - [this](bool connected) { - if (connected) { - m_connectionController->onConnectionStateChanged(Vpn::ConnectionState::Connected); - if (m_vpnConnection) - m_vpnConnection->restoreConnection(); - } + [this](Vpn::ConnectionState state) { + m_connectionController->onConnectionStateChanged(state); + if (m_vpnConnection) + m_vpnConnection->restoreConnection(); }); if (!AndroidController::instance()->initialize()) { qCritical() << QString("Init failed"); diff --git a/client/android/protocolApi/src/main/kotlin/ProtocolState.kt b/client/android/protocolApi/src/main/kotlin/ProtocolState.kt index d79949fa..977ef284 100644 --- a/client/android/protocolApi/src/main/kotlin/ProtocolState.kt +++ b/client/android/protocolApi/src/main/kotlin/ProtocolState.kt @@ -1,5 +1,6 @@ package org.amnezia.vpn.protocol +// keep synchronized with client/platforms/android/android_controller.h ConnectionState enum class ProtocolState { CONNECTED, CONNECTING, diff --git a/client/android/protocolApi/src/main/kotlin/Status.kt b/client/android/protocolApi/src/main/kotlin/Status.kt index 0bda689e..e22e4180 100644 --- a/client/android/protocolApi/src/main/kotlin/Status.kt +++ b/client/android/protocolApi/src/main/kotlin/Status.kt @@ -2,19 +2,19 @@ package org.amnezia.vpn.protocol import android.os.Bundle -private const val IS_CONNECTED_KEY = "isConnected" +private const val STATE_KEY = "state" @Suppress("DataClassPrivateConstructor") data class Status private constructor( - val isConnected: Boolean = false + val state: ProtocolState ) { - private constructor(builder: Builder) : this(builder.isConnected) + private constructor(builder: Builder) : this(builder.state) class Builder { - var isConnected: Boolean = false + lateinit var state: ProtocolState private set - fun setConnected(isConnected: Boolean) = apply { this.isConnected = isConnected } + fun setState(state: ProtocolState) = apply { this.state = state } fun build(): Status = Status(this) } @@ -24,11 +24,11 @@ data class Status private constructor( } } -fun Bundle.putStatus(statistics: Status) { - putBoolean(IS_CONNECTED_KEY, statistics.isConnected) +fun Bundle.putStatus(status: Status) { + putInt(STATE_KEY, status.state.ordinal) } fun Bundle.getStatus(): Status = Status.build { - setConnected(getBoolean(IS_CONNECTED_KEY)) + setState(ProtocolState.entries[getInt(STATE_KEY)]) } diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt index 048cb88b..bd9d121f 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt @@ -62,8 +62,8 @@ class AmneziaActivity : QtActivity() { ServiceEvent.STATUS -> { if (isWaitingStatus) { isWaitingStatus = false - msg.data?.getStatus()?.let { (isConnected) -> - QtAndroidController.onStatus(isConnected) + msg.data?.getStatus()?.let { (state) -> + QtAndroidController.onStatus(state.ordinal) } } } diff --git a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt index 77b19463..f44c4b22 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt @@ -123,7 +123,7 @@ class AmneziaVpnService : VpnService() { clientMessenger.send { ServiceEvent.STATUS.packToMessage { putStatus(Status.build { - setConnected(this@AmneziaVpnService.isConnected) + setState(this@AmneziaVpnService.protocolState.value) }) } } diff --git a/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt b/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt index 0f3c7b1f..72f2c83c 100644 --- a/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt +++ b/client/android/src/org/amnezia/vpn/qt/QtAndroidController.kt @@ -5,7 +5,7 @@ package org.amnezia.vpn.qt * called by events in the Android part of the client */ object QtAndroidController { - external fun onStatus(isVpnConnected: Boolean) + external fun onStatus(stateCode: Int) external fun onServiceDisconnected() external fun onServiceError() diff --git a/client/platforms/android/android_controller.cpp b/client/platforms/android/android_controller.cpp index 041d1869..d4e7ef62 100644 --- a/client/platforms/android/android_controller.cpp +++ b/client/platforms/android/android_controller.cpp @@ -15,12 +15,12 @@ namespace AndroidController::AndroidController() : QObject() { connect(this, &AndroidController::status, this, - [this](bool isVpnConnected) { - qDebug() << "Android event: status; connected:" << isVpnConnected; + [this](AndroidController::ConnectionState state) { + qDebug() << "Android event: status; state:" << textConnectionState(state); if (isWaitingStatus) { qDebug() << "Android VPN service is alive, initialization by service status"; isWaitingStatus = false; - emit serviceIsAlive(isVpnConnected); + emit serviceIsAlive(convertState(state)); } }, Qt::QueuedConnection); @@ -30,7 +30,7 @@ AndroidController::AndroidController() : QObject() [this]() { qDebug() << "Android event: service disconnected"; isWaitingStatus = true; - emit connectionStateChanged(Vpn::ConnectionState::Unknown); + emit connectionStateChanged(Vpn::ConnectionState::Disconnected); }, Qt::QueuedConnection); @@ -95,7 +95,7 @@ bool AndroidController::initialize() qDebug() << "Initialize AndroidController"; const JNINativeMethod methods[] = { - {"onStatus", "(Z)V", reinterpret_cast(onStatus)}, + {"onStatus", "(I)V", reinterpret_cast(onStatus)}, {"onServiceDisconnected", "()V", reinterpret_cast(onServiceDisconnected)}, {"onServiceError", "()V", reinterpret_cast(onServiceError)}, {"onVpnPermissionRejected", "()V", reinterpret_cast(onVpnPermissionRejected)}, @@ -179,14 +179,40 @@ void AndroidController::qtAndroidControllerInitialized() callActivityMethod("qtAndroidControllerInitialized", "()V"); } +// static +Vpn::ConnectionState AndroidController::convertState(AndroidController::ConnectionState state) +{ + switch (state) { + case AndroidController::ConnectionState::CONNECTED: return Vpn::ConnectionState::Connected; + case AndroidController::ConnectionState::CONNECTING: return Vpn::ConnectionState::Connecting; + case AndroidController::ConnectionState::DISCONNECTED: return Vpn::ConnectionState::Disconnected; + case AndroidController::ConnectionState::DISCONNECTING: return Vpn::ConnectionState::Disconnecting; + case AndroidController::ConnectionState::UNKNOWN: return Vpn::ConnectionState::Unknown; + } +} + +// static +QString AndroidController::textConnectionState(AndroidController::ConnectionState state) +{ + switch (state) { + case AndroidController::ConnectionState::CONNECTED: return "CONNECTED"; + case AndroidController::ConnectionState::CONNECTING: return "CONNECTING"; + case AndroidController::ConnectionState::DISCONNECTED: return "DISCONNECTED"; + case AndroidController::ConnectionState::DISCONNECTING: return "DISCONNECTING"; + case AndroidController::ConnectionState::UNKNOWN: return "UNKNOWN"; + } +} + // JNI functions called by Android // static -void AndroidController::onStatus(JNIEnv *env, jobject thiz, jboolean isVpnConnected) +void AndroidController::onStatus(JNIEnv *env, jobject thiz, jint stateCode) { Q_UNUSED(env); Q_UNUSED(thiz); - emit AndroidController::instance()->status(isVpnConnected); + auto state = ConnectionState(stateCode); + + emit AndroidController::instance()->status(state); } // static diff --git a/client/platforms/android/android_controller.h b/client/platforms/android/android_controller.h index eb4109be..8ab92592 100644 --- a/client/platforms/android/android_controller.h +++ b/client/platforms/android/android_controller.h @@ -17,6 +17,15 @@ public: bool initialize(); + // keep synchronized with org.amnezia.vpn.protocol.ProtocolState + enum class ConnectionState { + CONNECTED, + CONNECTING, + DISCONNECTED, + DISCONNECTING, + UNKNOWN + }; + ErrorCode start(const QJsonObject &vpnConfig); void stop(); void setNotificationText(const QString &title, const QString &message, int timerSec); @@ -25,7 +34,7 @@ public: signals: void connectionStateChanged(Vpn::ConnectionState state); - void status(bool isVpnConnected); + void status(ConnectionState state); void serviceDisconnected(); void serviceError(); void vpnPermissionRejected(); @@ -34,15 +43,18 @@ signals: void statisticsUpdated(quint64 rxBytes, quint64 txBytes); void configImported(); void importConfigFromOutside(QString &data); - void serviceIsAlive(bool connected); + void serviceIsAlive(Vpn::ConnectionState state); private: bool isWaitingStatus = true; void qtAndroidControllerInitialized(); + static Vpn::ConnectionState convertState(ConnectionState state); + static QString textConnectionState(ConnectionState state); + // JNI functions called by Android - static void onStatus(JNIEnv *env, jobject thiz, jboolean isVpnConnected); + static void onStatus(JNIEnv *env, jobject thiz, jint stateCode); static void onServiceDisconnected(JNIEnv *env, jobject thiz); static void onServiceError(JNIEnv *env, jobject thiz); static void onVpnPermissionRejected(JNIEnv *env, jobject thiz);