From 3ddd6ee699effb8056358e253a94938ee9b834fa Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:40:48 +0800 Subject: [PATCH] Refactor V2Ray native integration to V2RayNativeManager Introduced V2RayNativeManager as a thread-safe singleton to encapsulate all Libv2ray native method calls, replacing direct usage throughout the codebase. Updated SpeedtestManager, V2RayServiceManager, V2RayTestService, AboutActivity, and CheckUpdateActivity to use the new manager, improving code organization and maintainability. --- .../com/v2ray/ang/handler/SpeedtestManager.kt | 26 ------ .../v2ray/ang/handler/V2RayNativeManager.kt | 91 +++++++++++++++++++ .../v2ray/ang/handler/V2RayServiceManager.kt | 7 +- .../com/v2ray/ang/service/V2RayTestService.kt | 15 ++- .../java/com/v2ray/ang/ui/AboutActivity.kt | 4 +- .../com/v2ray/ang/ui/CheckUpdateActivity.kt | 4 +- 6 files changed, 103 insertions(+), 44 deletions(-) create mode 100644 V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayNativeManager.kt diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt index 760c7d72..08c95320 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt @@ -10,7 +10,6 @@ import com.v2ray.ang.util.HttpUtil import com.v2ray.ang.util.JsonUtil import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.isActive -import libv2ray.Libv2ray import java.io.IOException import java.net.InetSocketAddress import java.net.Socket @@ -41,21 +40,6 @@ object SpeedtestManager { return time } - /** - * Measures the real ping time using the V2Ray library. - * - * @param config The configuration string for the V2Ray library. - * @return The ping time in milliseconds, or -1 if the ping failed. - */ - fun realPing(config: String): Long { - return try { - Libv2ray.measureOutboundDelay(config, SettingsManager.getDelayTestUrl()) - } catch (e: Exception) { - Log.e(AppConfig.TAG, "Failed to measure outbound delay", e) - -1L - } - } - /** * Measures the time taken to establish a TCP connection to a given URL and port. * @@ -160,14 +144,4 @@ object SpeedtestManager { return "(${country ?: "unknown"}) ${ip ?: "unknown"}" } - - /** - * Gets the version of the V2Ray library. - * - * @return The version of the V2Ray library. - */ - fun getLibVersion(): String { - return Libv2ray.checkVersionX() - } - } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayNativeManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayNativeManager.kt new file mode 100644 index 00000000..9d46279e --- /dev/null +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayNativeManager.kt @@ -0,0 +1,91 @@ +package com.v2ray.ang.handler + +import android.content.Context +import android.util.Log +import com.v2ray.ang.AppConfig +import com.v2ray.ang.util.Utils +import go.Seq +import libv2ray.CoreCallbackHandler +import libv2ray.CoreController +import libv2ray.Libv2ray +import java.util.concurrent.atomic.AtomicBoolean + +/** + * V2Ray Native Library Manager + * + * Thread-safe singleton wrapper for Libv2ray native methods. + * Provides initialization protection and unified API for V2Ray core operations. + */ +object V2RayNativeManager { + private val initialized = AtomicBoolean(false) + + /** + * Initialize V2Ray core environment. + * This method is thread-safe and ensures initialization happens only once. + * Subsequent calls will be ignored silently. + * + */ + fun initCoreEnv(context: Context?) { + if (initialized.compareAndSet(false, true)) { + try { + Seq.setContext(context?.applicationContext) + val assetPath = Utils.userAssetPath(context) + val deviceId = Utils.getDeviceIdForXUDPBaseKey() + Libv2ray.initCoreEnv(assetPath, deviceId) + Log.i(AppConfig.TAG, "V2Ray core environment initialized successfully") + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to initialize V2Ray core environment", e) + initialized.set(false) + throw e + } + } else { + Log.d(AppConfig.TAG, "V2Ray core environment already initialized, skipping") + } + } + + + /** + * Get V2Ray core version. + * + * @return Version string of the V2Ray core + */ + fun getLibVersion(): String { + return try { + Libv2ray.checkVersionX() + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to check V2Ray version", e) + "Unknown" + } + } + + /** + * Measure outbound connection delay. + * + * @param config The configuration JSON string + * @param testUrl The URL to test against + * @return Delay in milliseconds, or -1 if test failed + */ + fun measureOutboundDelay(config: String, testUrl: String): Long { + return try { + Libv2ray.measureOutboundDelay(config, testUrl) + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to measure outbound delay", e) + -1L + } + } + + /** + * Create a new core controller instance. + * + * @param handler The callback handler for core events + * @return A new CoreController instance + */ + fun newCoreController(handler: CoreCallbackHandler): CoreController { + return try { + Libv2ray.newCoreController(handler) + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to create core controller", e) + throw e + } + } +} diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt index 43e90d4f..1cbe24f3 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt @@ -18,26 +18,23 @@ import com.v2ray.ang.service.V2RayProxyOnlyService import com.v2ray.ang.service.V2RayVpnService import com.v2ray.ang.util.MessageUtil import com.v2ray.ang.util.Utils -import go.Seq import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import libv2ray.CoreCallbackHandler import libv2ray.CoreController -import libv2ray.Libv2ray import java.lang.ref.SoftReference object V2RayServiceManager { - private val coreController: CoreController = Libv2ray.newCoreController(CoreCallback()) + private val coreController: CoreController = V2RayNativeManager.newCoreController(CoreCallback()) private val mMsgReceive = ReceiveMessageHandler() private var currentConfig: ProfileItem? = null var serviceControl: SoftReference? = null set(value) { field = value - Seq.setContext(value?.get()?.getService()?.applicationContext) - Libv2ray.initCoreEnv(Utils.userAssetPath(value?.get()?.getService()), Utils.getDeviceIdForXUDPBaseKey()) + V2RayNativeManager.initCoreEnv(value?.get()?.getService()) } /** diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayTestService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayTestService.kt index bb3237e7..68934f11 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayTestService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayTestService.kt @@ -11,20 +11,18 @@ import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.extension.serializable import com.v2ray.ang.handler.MmkvManager import com.v2ray.ang.handler.PluginServiceManager -import com.v2ray.ang.handler.SpeedtestManager +import com.v2ray.ang.handler.SettingsManager +import com.v2ray.ang.handler.V2RayNativeManager import com.v2ray.ang.handler.V2rayConfigManager import com.v2ray.ang.util.MessageUtil -import com.v2ray.ang.util.Utils -import go.Seq +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren -import kotlinx.coroutines.launch import kotlinx.coroutines.joinAll -import kotlinx.coroutines.CancellationException -import libv2ray.Libv2ray +import kotlinx.coroutines.launch import java.util.concurrent.atomic.AtomicInteger class V2RayTestService : Service() { @@ -45,8 +43,7 @@ class V2RayTestService : Service() { */ override fun onCreate() { super.onCreate() - Seq.setContext(this) - Libv2ray.initCoreEnv(Utils.userAssetPath(this), Utils.getDeviceIdForXUDPBaseKey()) + V2RayNativeManager.initCoreEnv(this) } /** @@ -141,7 +138,7 @@ class V2RayTestService : Service() { if (!configResult.status) { return retFailure } - return SpeedtestManager.realPing(configResult.content) + return V2RayNativeManager.measureOutboundDelay(configResult.content, SettingsManager.getDelayTestUrl()) } } } \ No newline at end of file diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/AboutActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/AboutActivity.kt index 7ec4f76c..70b80ca3 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/AboutActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/AboutActivity.kt @@ -5,7 +5,7 @@ import com.v2ray.ang.AppConfig import com.v2ray.ang.BuildConfig import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityAboutBinding -import com.v2ray.ang.handler.SpeedtestManager +import com.v2ray.ang.handler.V2RayNativeManager import com.v2ray.ang.util.Utils class AboutActivity : BaseActivity() { @@ -42,7 +42,7 @@ class AboutActivity : BaseActivity() { Utils.openUri(this, AppConfig.APP_PRIVACY_POLICY) } - "v${BuildConfig.VERSION_NAME} (${SpeedtestManager.getLibVersion()})".also { + "v${BuildConfig.VERSION_NAME} (${V2RayNativeManager.getLibVersion()})".also { binding.tvVersion.text = it } BuildConfig.APPLICATION_ID.also { diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt index fbd3739c..cae45425 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/CheckUpdateActivity.kt @@ -13,8 +13,8 @@ import com.v2ray.ang.extension.toast import com.v2ray.ang.extension.toastError import com.v2ray.ang.extension.toastSuccess import com.v2ray.ang.handler.MmkvManager -import com.v2ray.ang.handler.SpeedtestManager import com.v2ray.ang.handler.UpdateCheckerManager +import com.v2ray.ang.handler.V2RayNativeManager import com.v2ray.ang.util.Utils import kotlinx.coroutines.launch @@ -36,7 +36,7 @@ class CheckUpdateActivity : BaseActivity() { } binding.checkPreRelease.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_CHECK_UPDATE_PRE_RELEASE, false) - "v${BuildConfig.VERSION_NAME} (${SpeedtestManager.getLibVersion()})".also { + "v${BuildConfig.VERSION_NAME} (${V2RayNativeManager.getLibVersion()})".also { binding.tvVersion.text = it }