diff --git a/analysis_options.yaml b/analysis_options.yaml
index 1bb9e87..5eaf784 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,5 +1,7 @@
include: package:flutter_lints/flutter.yaml
analyzer:
+ plugins:
+ - custom_lint
exclude:
- lib/l10n/intl/**
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
index 337dedf..292f6d3 100644
--- a/android/app/build.gradle.kts
+++ b/android/app/build.gradle.kts
@@ -1,3 +1,4 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.util.Properties
plugins {
@@ -24,22 +25,19 @@ val isRelease = mStoreFile.exists()
android {
namespace = "com.follow.clash"
- compileSdk = 35
- ndkVersion = "28.0.13004108"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+ ndkVersion = libs.versions.ndkVersion.get()
+
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
- kotlinOptions {
- jvmTarget = JavaVersion.VERSION_17.toString()
- }
-
defaultConfig {
applicationId = "com.follow.clash"
minSdk = flutter.minSdkVersion
- targetSdk = flutter.targetSdkVersion
+ targetSdk = libs.versions.targetSdk.get().toInt()
versionCode = flutter.versionCode
versionName = flutter.versionName
}
@@ -63,8 +61,7 @@ android {
release {
isMinifyEnabled = true
- isDebuggable = false
-
+ isShrinkResources = true
signingConfig = if (isRelease) {
signingConfigs.getByName("release")
} else {
@@ -79,15 +76,22 @@ android {
}
}
+kotlin {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+}
+
flutter {
source = "../.."
}
dependencies {
- implementation(project(":core"))
- implementation("androidx.core:core-splashscreen:1.0.1")
- implementation("com.google.code.gson:gson:2.10.1")
- implementation("com.android.tools.smali:smali-dexlib2:3.0.9") {
+ implementation(project(":service"))
+ implementation(project(":common"))
+ implementation(libs.core.splashscreen)
+ implementation(libs.gson)
+ implementation(libs.smali.dexlib2) {
exclude(group = "com.google.guava", module = "guava")
}
}
\ No newline at end of file
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
index 17e22a6..0b65f1f 100644
--- a/android/app/proguard-rules.pro
+++ b/android/app/proguard-rules.pro
@@ -1,2 +1,4 @@
--keep class com.follow.clash.models.**{ *; }
\ No newline at end of file
+-keep class com.follow.clash.models.**{ *; }
+
+-keep class com.follow.clash.service.models.**{ *; }
\ No newline at end of file
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index 8fe3c0a..61ad146 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -9,7 +9,7 @@
android:label="FlClash Debug"
tools:replace="android:label">
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index dad0f94..1987f18 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,11 @@
+
+
+
@@ -13,19 +18,19 @@
-
-
-
+
+
@@ -47,6 +52,7 @@
+
@@ -67,12 +73,9 @@
-
-
@@ -85,17 +88,16 @@
-
+
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
@@ -104,6 +106,19 @@
android:value="true" />
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/app/src/main/kotlin/com/follow/clash/Application.kt b/android/app/src/main/kotlin/com/follow/clash/Application.kt
new file mode 100644
index 0000000..a3320b7
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/Application.kt
@@ -0,0 +1,13 @@
+package com.follow.clash
+
+import android.app.Application
+import android.content.Context
+import com.follow.clash.common.GlobalState
+
+class Application : Application() {
+
+ override fun attachBaseContext(base: Context?) {
+ super.attachBaseContext(base)
+ GlobalState.init(this)
+ }
+}
diff --git a/android/app/src/main/kotlin/com/follow/clash/BroadcastReceiver.kt b/android/app/src/main/kotlin/com/follow/clash/BroadcastReceiver.kt
new file mode 100644
index 0000000..e3d43e0
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/BroadcastReceiver.kt
@@ -0,0 +1,34 @@
+package com.follow.clash
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import com.follow.clash.common.BroadcastAction
+import com.follow.clash.common.action
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+
+class BroadcastReceiver : BroadcastReceiver(),
+ CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ when (intent?.action) {
+ BroadcastAction.START.action -> {
+ launch {
+ State.handleStartServiceAction()
+ }
+ }
+
+ BroadcastAction.STOP.action -> {
+ State.handleStopServiceAction()
+ }
+
+ BroadcastAction.TOGGLE.action -> {
+ launch {
+ State.handleToggleAction()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/Ext.kt b/android/app/src/main/kotlin/com/follow/clash/Ext.kt
new file mode 100644
index 0000000..4821298
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/Ext.kt
@@ -0,0 +1,76 @@
+package com.follow.clash
+
+import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
+import android.os.Handler
+import android.os.Looper
+import android.util.Base64
+import androidx.core.graphics.drawable.toBitmap
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.plugin.common.MethodChannel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
+import java.io.ByteArrayOutputStream
+import kotlin.coroutines.resume
+
+suspend fun Drawable.getBase64(): String {
+ val drawable = this
+ return withContext(Dispatchers.IO) {
+ val bitmap = drawable.toBitmap()
+ val byteArrayOutputStream = ByteArrayOutputStream()
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
+ Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.NO_WRAP)
+ }
+}
+
+suspend fun MethodChannel.awaitResult(
+ method: String, arguments: Any? = null
+): T? = withContext(Dispatchers.Main) {
+ suspendCancellableCoroutine { continuation ->
+ invokeMethod(method, arguments, object : MethodChannel.Result {
+ override fun success(result: Any?) {
+ @Suppress("UNCHECKED_CAST") continuation.resume(result as T?)
+ }
+
+ override fun error(code: String, message: String?, details: Any?) {
+ continuation.resume(null)
+ }
+
+ override fun notImplemented() {
+ continuation.resume(null)
+ }
+ })
+ }
+}
+
+inline fun FlutterEngine.plugin(): T? {
+ return plugins.get(T::class.java) as T?
+}
+
+
+fun MethodChannel.invokeMethodOnMainThread(
+ method: String,
+ arguments: Any? = null,
+ callback: ((Result) -> Unit)? = null
+) {
+ Handler(Looper.getMainLooper()).post {
+ invokeMethod(method, arguments, object : MethodChannel.Result {
+ override fun success(result: Any?) {
+ @Suppress("UNCHECKED_CAST")
+ callback?.invoke(Result.success(result as T))
+ }
+
+ override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
+ val exception = Exception("MethodChannel error: $errorCode - $errorMessage")
+ callback?.invoke(Result.failure(exception))
+ }
+
+ override fun notImplemented() {
+ val exception = NotImplementedError("Method not implemented: $method")
+ callback?.invoke(Result.failure(exception))
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/FilesProvider.kt b/android/app/src/main/kotlin/com/follow/clash/FilesProvider.kt
index 5ae2f06..fef654e 100644
--- a/android/app/src/main/kotlin/com/follow/clash/FilesProvider.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/FilesProvider.kt
@@ -43,7 +43,7 @@ class FilesProvider : DocumentsProvider() {
add(Root.COLUMN_ROOT_ID, DEFAULT_ROOT_ID)
add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY)
add(Root.COLUMN_ICON, R.mipmap.ic_launcher)
- add(Root.COLUMN_TITLE, context!!.getString(R.string.fl_clash))
+ add(Root.COLUMN_TITLE, "FlClash")
add(Root.COLUMN_SUMMARY, "Data")
add(Root.COLUMN_DOCUMENT_ID, "/")
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt b/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt
deleted file mode 100644
index e2b2783..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.follow.clash;
-
-import android.app.Application
-import android.content.Context
-
-class FlClashApplication : Application() {
- companion object {
- private lateinit var instance: FlClashApplication
- fun getAppContext(): Context {
- return instance.applicationContext
- }
- }
-
- override fun onCreate() {
- super.onCreate()
- instance = this
- }
-}
diff --git a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
deleted file mode 100644
index f47ff57..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.follow.clash
-
-import androidx.lifecycle.MutableLiveData
-import com.follow.clash.plugins.AppPlugin
-import com.follow.clash.plugins.TilePlugin
-import com.follow.clash.plugins.VpnPlugin
-import io.flutter.FlutterInjector
-import io.flutter.embedding.engine.FlutterEngine
-import io.flutter.embedding.engine.dart.DartExecutor
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.util.concurrent.locks.ReentrantLock
-import kotlin.concurrent.withLock
-
-enum class RunState {
- START,
- PENDING,
- STOP
-}
-
-
-object GlobalState {
- val runLock = ReentrantLock()
-
- const val NOTIFICATION_CHANNEL = "FlClash"
-
- const val NOTIFICATION_ID = 1
-
- val runState: MutableLiveData = MutableLiveData(RunState.STOP)
- var flutterEngine: FlutterEngine? = null
- private var serviceEngine: FlutterEngine? = null
-
- fun getCurrentAppPlugin(): AppPlugin? {
- val currentEngine = if (flutterEngine != null) flutterEngine else serviceEngine
- return currentEngine?.plugins?.get(AppPlugin::class.java) as AppPlugin?
- }
-
- fun syncStatus() {
- CoroutineScope(Dispatchers.Default).launch {
- val status = getCurrentVPNPlugin()?.getStatus() ?: false
- withContext(Dispatchers.Main){
- runState.value = if (status) RunState.START else RunState.STOP
- }
- }
- }
-
- suspend fun getText(text: String): String {
- return getCurrentAppPlugin()?.getText(text) ?: ""
- }
-
- fun getCurrentTilePlugin(): TilePlugin? {
- val currentEngine = if (flutterEngine != null) flutterEngine else serviceEngine
- return currentEngine?.plugins?.get(TilePlugin::class.java) as TilePlugin?
- }
-
- fun getCurrentVPNPlugin(): VpnPlugin? {
- return serviceEngine?.plugins?.get(VpnPlugin::class.java) as VpnPlugin?
- }
-
- fun handleToggle() {
- val starting = handleStart()
- if (!starting) {
- handleStop()
- }
- }
-
- fun handleStart(): Boolean {
- if (runState.value == RunState.STOP) {
- runState.value = RunState.PENDING
- runLock.lock()
- val tilePlugin = getCurrentTilePlugin()
- if (tilePlugin != null) {
- tilePlugin.handleStart()
- } else {
- initServiceEngine()
- }
- return true
- }
- return false
- }
-
- fun handleStop() {
- if (runState.value == RunState.START) {
- runState.value = RunState.PENDING
- runLock.lock()
- getCurrentTilePlugin()?.handleStop()
- }
- }
-
- fun handleTryDestroy() {
- if (flutterEngine == null) {
- destroyServiceEngine()
- }
- }
-
- fun destroyServiceEngine() {
- runLock.withLock {
- serviceEngine?.destroy()
- serviceEngine = null
- }
- }
-
- fun initServiceEngine() {
- if (serviceEngine != null) return
- destroyServiceEngine()
- runLock.withLock {
- serviceEngine = FlutterEngine(FlClashApplication.getAppContext())
- serviceEngine?.plugins?.add(VpnPlugin)
- serviceEngine?.plugins?.add(AppPlugin())
- serviceEngine?.plugins?.add(TilePlugin())
- val vpnService = DartExecutor.DartEntrypoint(
- FlutterInjector.instance().flutterLoader().findAppBundlePath(),
- "_service"
- )
- serviceEngine?.dartExecutor?.executeDartEntrypoint(
- vpnService,
- if (flutterEngine == null) listOf("quick") else null
- )
- }
- }
-}
-
-
diff --git a/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt b/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt
index de930ca..84b7237 100644
--- a/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt
@@ -5,19 +5,27 @@ import com.follow.clash.plugins.ServicePlugin
import com.follow.clash.plugins.TilePlugin
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+
+class MainActivity : FlutterActivity(),
+ CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
-class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
+ launch {
+ State.destroyServiceEngine()
+ }
super.configureFlutterEngine(flutterEngine)
flutterEngine.plugins.add(AppPlugin())
- flutterEngine.plugins.add(ServicePlugin)
+ flutterEngine.plugins.add(ServicePlugin())
flutterEngine.plugins.add(TilePlugin())
- GlobalState.flutterEngine = flutterEngine
+ State.flutterEngine = flutterEngine
}
override fun onDestroy() {
- GlobalState.flutterEngine = null
- GlobalState.runState.value = RunState.STOP
+ State.flutterEngine = null
super.onDestroy()
}
}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/Service.kt b/android/app/src/main/kotlin/com/follow/clash/Service.kt
new file mode 100644
index 0000000..b494c96
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/Service.kt
@@ -0,0 +1,77 @@
+package com.follow.clash
+
+import com.follow.clash.common.ServiceDelegate
+import com.follow.clash.common.intent
+import com.follow.clash.service.ICallbackInterface
+import com.follow.clash.service.IRemoteInterface
+import com.follow.clash.service.RemoteService
+import com.follow.clash.service.models.NotificationParams
+import com.follow.clash.service.models.VpnOptions
+import java.util.concurrent.atomic.AtomicBoolean
+
+object Service {
+ private val delegate by lazy {
+ ServiceDelegate(
+ RemoteService::class.intent, ::handleOnServiceCrash
+ ) {
+ IRemoteInterface.Stub.asInterface(it)
+ }
+ }
+
+ var onServiceCrash: (() -> Unit)? = null
+
+ private fun handleOnServiceCrash() {
+ bindingState.set(false)
+ onServiceCrash?.let {
+ it()
+ }
+ }
+
+ private val bindingState = AtomicBoolean(false)
+
+ fun bind() {
+ if (bindingState.compareAndSet(false, true)) {
+ delegate.bind()
+ }
+ }
+
+ suspend fun invokeAction(
+ data: String, cb: (result: String?) -> Unit
+ ) {
+ delegate.useService {
+ it.invokeAction(data, object : ICallbackInterface.Stub() {
+ override fun onResult(result: String?) {
+ cb(result)
+ }
+ })
+ }
+ }
+
+ suspend fun updateNotificationParams(
+ params: NotificationParams
+ ) {
+ delegate.useService {
+ it.updateNotificationParams(params)
+ }
+ }
+
+ suspend fun setMessageCallback(
+ cb: (result: String?) -> Unit
+ ) {
+ delegate.useService {
+ it.setMessageCallback(object : ICallbackInterface.Stub() {
+ override fun onResult(result: String?) {
+ cb(result)
+ }
+ })
+ }
+ }
+
+ suspend fun startService(options: VpnOptions, inApp: Boolean) {
+ delegate.useService { it.startService(options, inApp) }
+ }
+
+ suspend fun stopService() {
+ delegate.useService { it.stopService() }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/State.kt b/android/app/src/main/kotlin/com/follow/clash/State.kt
new file mode 100644
index 0000000..418e9b2
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/State.kt
@@ -0,0 +1,148 @@
+package com.follow.clash
+
+import com.follow.clash.common.GlobalState
+import com.follow.clash.plugins.AppPlugin
+import com.follow.clash.plugins.ServicePlugin
+import com.follow.clash.plugins.TilePlugin
+import io.flutter.FlutterInjector
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.embedding.engine.dart.DartExecutor
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+
+enum class RunState {
+ START, PENDING, STOP
+}
+
+
+object State {
+
+ val runLock = Mutex()
+
+ var runTime: Long = 0
+
+ val runStateFlow: MutableStateFlow = MutableStateFlow(RunState.STOP)
+ var flutterEngine: FlutterEngine? = null
+ var serviceFlutterEngine: FlutterEngine? = null
+
+ val appPlugin: AppPlugin?
+ get() = flutterEngine?.plugin() ?: serviceFlutterEngine?.plugin()
+
+ val servicePlugin: ServicePlugin?
+ get() = flutterEngine?.plugin()
+ ?: serviceFlutterEngine?.plugin()
+
+ val tilePlugin: TilePlugin?
+ get() = flutterEngine?.plugin() ?: serviceFlutterEngine?.plugin()
+
+ suspend fun handleToggleAction() {
+ var action: (suspend () -> Unit)?
+ runLock.withLock {
+ action = when (runStateFlow.value) {
+ RunState.PENDING -> null
+ RunState.START -> ::handleStopServiceAction
+ RunState.STOP -> ::handleStartServiceAction
+ }
+ }
+ action?.invoke()
+ }
+
+ suspend fun handleStartServiceAction() {
+ tilePlugin?.handleStart()
+ if (flutterEngine != null) {
+ return
+ }
+ startServiceWithEngine()
+ }
+
+ fun handleStopServiceAction() {
+ tilePlugin?.handleStop()
+ if (flutterEngine != null || serviceFlutterEngine != null) {
+ return
+ }
+ handleStopService()
+ }
+
+ fun handleStartService() {
+ if (appPlugin != null) {
+ appPlugin?.requestNotificationsPermission {
+ startService()
+ }
+ return
+ }
+ startService()
+ }
+
+ suspend fun destroyServiceEngine() {
+ runLock.withLock {
+ withContext(Dispatchers.Main) {
+ runCatching {
+ serviceFlutterEngine?.destroy()
+ serviceFlutterEngine = null
+ }
+ }
+ }
+ }
+
+ suspend fun startServiceWithEngine() {
+ runLock.withLock {
+ withContext(Dispatchers.Main) {
+ serviceFlutterEngine = FlutterEngine(GlobalState.application)
+ serviceFlutterEngine?.plugins?.add(ServicePlugin())
+ serviceFlutterEngine?.plugins?.add(AppPlugin())
+ serviceFlutterEngine?.plugins?.add(TilePlugin())
+ val dartEntrypoint = DartExecutor.DartEntrypoint(
+ FlutterInjector.instance().flutterLoader().findAppBundlePath(), "_service"
+ )
+ serviceFlutterEngine?.dartExecutor?.executeDartEntrypoint(dartEntrypoint)
+ }
+
+ }
+ }
+
+ private fun startService() {
+ GlobalState.launch {
+ runLock.withLock {
+ if (runStateFlow.value == RunState.PENDING || runStateFlow.value == RunState.START) {
+ return@launch
+ }
+ runStateFlow.tryEmit(RunState.PENDING)
+ if (servicePlugin == null) {
+ return@launch
+ }
+ val options = servicePlugin?.handleGetVpnOptions()
+ if (options == null) {
+ return@launch
+ }
+ appPlugin?.prepare(options.enable) {
+ Service.startService(options, true)
+ runStateFlow.tryEmit(RunState.START)
+ runTime = System.currentTimeMillis()
+ }
+ }
+ }
+
+ }
+
+ fun handleStopService() {
+ GlobalState.launch {
+ runLock.withLock {
+ if (runStateFlow.value == RunState.PENDING || runStateFlow.value == RunState.STOP) {
+ return@launch
+ }
+ runStateFlow.tryEmit(RunState.PENDING)
+ Service.stopService()
+ runStateFlow.tryEmit(RunState.STOP)
+ runTime = 0
+ }
+ destroyServiceEngine()
+ }
+
+ }
+}
+
+
diff --git a/android/app/src/main/kotlin/com/follow/clash/TempActivity.kt b/android/app/src/main/kotlin/com/follow/clash/TempActivity.kt
index 33f631a..1e8a519 100644
--- a/android/app/src/main/kotlin/com/follow/clash/TempActivity.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/TempActivity.kt
@@ -2,24 +2,34 @@ package com.follow.clash
import android.app.Activity
import android.os.Bundle
-import com.follow.clash.extensions.wrapAction
+import com.follow.clash.common.QuickAction
+import com.follow.clash.common.action
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
-class TempActivity : Activity() {
+class TempActivity : Activity(),
+ CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
when (intent.action) {
- wrapAction("START") -> {
- GlobalState.handleStart()
+ QuickAction.START.action -> {
+ launch {
+ State.handleStartServiceAction()
+ }
}
- wrapAction("STOP") -> {
- GlobalState.handleStop()
+ QuickAction.STOP.action -> {
+ State.handleStopServiceAction()
}
- wrapAction("CHANGE") -> {
- GlobalState.handleToggle()
+ QuickAction.TOGGLE.action -> {
+ launch {
+ State.handleToggleAction()
+ }
}
}
- finishAndRemoveTask()
+ finish()
}
}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/TileService.kt b/android/app/src/main/kotlin/com/follow/clash/TileService.kt
new file mode 100644
index 0000000..907732d
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/TileService.kt
@@ -0,0 +1,61 @@
+package com.follow.clash
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.service.quicksettings.Tile
+import android.service.quicksettings.TileService
+import com.follow.clash.common.QuickAction
+import com.follow.clash.common.quickIntent
+import com.follow.clash.common.toPendingIntent
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+
+class TileService : TileService() {
+ private var scope: CoroutineScope? = null
+ private fun updateTile(runState: RunState) {
+ if (qsTile != null) {
+ qsTile.state = when (runState) {
+ RunState.START -> Tile.STATE_ACTIVE
+ RunState.PENDING -> Tile.STATE_UNAVAILABLE
+ RunState.STOP -> Tile.STATE_INACTIVE
+ }
+ qsTile.updateTile()
+ }
+ }
+
+ override fun onStartListening() {
+ super.onStartListening()
+ scope?.cancel()
+ scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
+ scope?.launch {
+ State.runStateFlow.collect {
+ updateTile(it)
+ }
+ }
+ }
+
+ @SuppressLint("StartActivityAndCollapseDeprecated")
+ private fun handleToggle() {
+ val intent = QuickAction.TOGGLE.quickIntent
+ val pendingIntent = intent.toPendingIntent
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ startActivityAndCollapse(pendingIntent)
+ } else {
+ @Suppress("DEPRECATION")
+ startActivityAndCollapse(intent)
+ }
+ }
+
+ override fun onClick() {
+ super.onClick()
+ handleToggle()
+ }
+
+ override fun onStopListening() {
+ scope?.cancel()
+ super.onStopListening()
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt b/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt
deleted file mode 100644
index 10e0536..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-package com.follow.clash.extensions
-
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.graphics.Bitmap
-import android.graphics.drawable.Drawable
-import android.net.ConnectivityManager
-import android.net.Network
-import android.os.Build
-import android.system.OsConstants.IPPROTO_TCP
-import android.system.OsConstants.IPPROTO_UDP
-import android.util.Base64
-import androidx.core.graphics.drawable.toBitmap
-import com.follow.clash.TempActivity
-import com.follow.clash.models.CIDR
-import com.follow.clash.models.Metadata
-import com.follow.clash.models.VpnOptions
-import io.flutter.plugin.common.MethodChannel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import java.io.ByteArrayOutputStream
-import java.net.Inet4Address
-import java.net.Inet6Address
-import java.net.InetAddress
-import java.util.concurrent.locks.ReentrantLock
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
-
-suspend fun Drawable.getBase64(): String {
- val drawable = this
- return withContext(Dispatchers.IO) {
- val bitmap = drawable.toBitmap()
- val byteArrayOutputStream = ByteArrayOutputStream()
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
- Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.NO_WRAP)
- }
-}
-
-fun Metadata.getProtocol(): Int? {
- if (network.startsWith("tcp")) return IPPROTO_TCP
- if (network.startsWith("udp")) return IPPROTO_UDP
- return null
-}
-
-fun VpnOptions.getIpv4RouteAddress(): List {
- return routeAddress.filter {
- it.isIpv4()
- }.map {
- it.toCIDR()
- }
-}
-
-fun VpnOptions.getIpv6RouteAddress(): List {
- return routeAddress.filter {
- it.isIpv6()
- }.map {
- it.toCIDR()
- }
-}
-
-fun String.isIpv4(): Boolean {
- val parts = split("/")
- if (parts.size != 2) {
- throw IllegalArgumentException("Invalid CIDR format")
- }
- val address = InetAddress.getByName(parts[0])
- return address.address.size == 4
-}
-
-fun String.isIpv6(): Boolean {
- val parts = split("/")
- if (parts.size != 2) {
- throw IllegalArgumentException("Invalid CIDR format")
- }
- val address = InetAddress.getByName(parts[0])
- return address.address.size == 16
-}
-
-fun String.toCIDR(): CIDR {
- val parts = split("/")
- if (parts.size != 2) {
- throw IllegalArgumentException("Invalid CIDR format")
- }
- val ipAddress = parts[0]
- val prefixLength = parts[1].toIntOrNull()
- ?: throw IllegalArgumentException("Invalid prefix length")
-
- val address = InetAddress.getByName(ipAddress)
-
- val maxPrefix = if (address.address.size == 4) 32 else 128
- if (prefixLength < 0 || prefixLength > maxPrefix) {
- throw IllegalArgumentException("Invalid prefix length for IP version")
- }
-
- return CIDR(address, prefixLength)
-}
-
-fun ConnectivityManager.resolveDns(network: Network?): List {
- val properties = getLinkProperties(network) ?: return listOf()
- return properties.dnsServers.map { it.asSocketAddressText(53) }
-}
-
-fun InetAddress.asSocketAddressText(port: Int): String {
- return when (this) {
- is Inet6Address ->
- "[${numericToTextFormat(this)}]:$port"
-
- is Inet4Address ->
- "${this.hostAddress}:$port"
-
- else -> throw IllegalArgumentException("Unsupported Inet type ${this.javaClass}")
- }
-}
-
-fun Context.wrapAction(action: String): String {
- return "${this.packageName}.action.$action"
-}
-
-fun Context.getActionIntent(action: String): Intent {
- val actionIntent = Intent(this, TempActivity::class.java)
- actionIntent.action = wrapAction(action)
- return actionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
-}
-
-fun Context.getActionPendingIntent(action: String): PendingIntent {
- return if (Build.VERSION.SDK_INT >= 31) {
- PendingIntent.getActivity(
- this,
- 0,
- getActionIntent(action),
- PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
- )
- } else {
- PendingIntent.getActivity(
- this,
- 0,
- getActionIntent(action),
- PendingIntent.FLAG_UPDATE_CURRENT
- )
- }
-}
-
-private fun numericToTextFormat(address: Inet6Address): String {
- val src = address.address
- val sb = StringBuilder(39)
- for (i in 0 until 8) {
- sb.append(
- Integer.toHexString(
- src[i shl 1].toInt() shl 8 and 0xff00
- or (src[(i shl 1) + 1].toInt() and 0xff)
- )
- )
- if (i < 7) {
- sb.append(":")
- }
- }
- if (address.scopeId > 0) {
- sb.append("%")
- sb.append(address.scopeId)
- }
- return sb.toString()
-}
-
-suspend fun MethodChannel.awaitResult(
- method: String,
- arguments: Any? = null
-): T? = withContext(Dispatchers.Main) { // 切换到主线程
- suspendCoroutine { continuation ->
- invokeMethod(method, arguments, object : MethodChannel.Result {
- override fun success(result: Any?) {
- @Suppress("UNCHECKED_CAST")
- continuation.resume(result as T)
- }
-
- override fun error(code: String, message: String?, details: Any?) {
- continuation.resume(null)
- }
-
- override fun notImplemented() {
- continuation.resume(null)
- }
- })
- }
-}
-
-fun ReentrantLock.safeLock() {
- if (this.isLocked) {
- return
- }
- this.lock()
-}
-
-fun ReentrantLock.safeUnlock() {
- if (!this.isLocked) {
- return
- }
-
- this.unlock()
-}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/models/Process.kt b/android/app/src/main/kotlin/com/follow/clash/models/Process.kt
deleted file mode 100644
index a889564..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/models/Process.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.follow.clash.models
-
-data class Process(
- val id: String,
- val metadata: Metadata,
-)
-
-data class Metadata(
- val network: String,
- val sourceIP: String,
- val sourcePort: Int,
- val destinationIP: String,
- val destinationPort: Int,
- val host: String
-)
diff --git a/android/app/src/main/kotlin/com/follow/clash/models/Props.kt b/android/app/src/main/kotlin/com/follow/clash/models/Props.kt
deleted file mode 100644
index 9a7ed7b..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/models/Props.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.follow.clash.models
-
-import java.net.InetAddress
-
-enum class AccessControlMode {
- acceptSelected, rejectSelected,
-}
-
-data class AccessControl(
- val enable: Boolean,
- val mode: AccessControlMode,
- val acceptList: List,
- val rejectList: List,
-)
-
-data class CIDR(val address: InetAddress, val prefixLength: Int)
-
-data class VpnOptions(
- val enable: Boolean,
- val port: Int,
- val accessControl: AccessControl,
- val allowBypass: Boolean,
- val systemProxy: Boolean,
- val bypassDomain: List,
- val routeAddress: List,
- val ipv4Address: String,
- val ipv6Address: String,
- val dnsServerAddress: String,
-)
-
-data class StartForegroundParams(
- val title: String,
- val content: String,
-)
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/models/State.kt b/android/app/src/main/kotlin/com/follow/clash/models/State.kt
new file mode 100644
index 0000000..7df9850
--- /dev/null
+++ b/android/app/src/main/kotlin/com/follow/clash/models/State.kt
@@ -0,0 +1,8 @@
+package com.follow.clash.models
+
+
+data class AppState(
+ val currentProfileName: String,
+ val stopText: String,
+ val onlyStatisticsProxy: Boolean,
+)
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt
index 757c193..efb0b18 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt
@@ -13,17 +13,16 @@ import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService
-import androidx.core.content.FileProvider
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile
-import com.follow.clash.FlClashApplication
-import com.follow.clash.GlobalState
import com.follow.clash.R
-import com.follow.clash.extensions.awaitResult
-import com.follow.clash.extensions.getActionIntent
-import com.follow.clash.extensions.getBase64
+import com.follow.clash.common.Components
+import com.follow.clash.common.GlobalState
+import com.follow.clash.common.QuickAction
+import com.follow.clash.common.quickIntent
+import com.follow.clash.getBase64
import com.follow.clash.models.Package
import com.google.gson.Gson
import io.flutter.embedding.android.FlutterActivity
@@ -44,13 +43,20 @@ import java.util.zip.ZipFile
class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware {
+ companion object {
+ const val VPN_PERMISSION_REQUEST_CODE = 1001
+ const val NOTIFICATION_PERMISSION_REQUEST_CODE = 1002
+ }
+
private var activityRef: WeakReference? = null
private lateinit var channel: MethodChannel
private lateinit var scope: CoroutineScope
- private var vpnCallBack: (() -> Unit)? = null
+ private var vpnPrepareCallback: (suspend () -> Unit)? = null
+
+ private var requestNotificationCallback: (() -> Unit)? = null
private val iconMap = mutableMapOf()
@@ -111,46 +117,8 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex()
}
- val VPN_PERMISSION_REQUEST_CODE = 1001
-
- val NOTIFICATION_PERMISSION_REQUEST_CODE = 1002
-
private var isBlockNotification: Boolean = false
- override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
- scope = CoroutineScope(Dispatchers.Default)
- channel = MethodChannel(flutterPluginBinding.binaryMessenger, "app")
- channel.setMethodCallHandler(this)
- }
-
- private fun initShortcuts(label: String) {
- val shortcut = ShortcutInfoCompat.Builder(FlClashApplication.getAppContext(), "toggle")
- .setShortLabel(label)
- .setIcon(
- IconCompat.createWithResource(
- FlClashApplication.getAppContext(),
- R.mipmap.ic_launcher_round
- )
- )
- .setIntent(FlClashApplication.getAppContext().getActionIntent("CHANGE"))
- .build()
- ShortcutManagerCompat.setDynamicShortcuts(
- FlClashApplication.getAppContext(),
- listOf(shortcut)
- )
- }
-
- override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
- channel.setMethodCallHandler(null)
- scope.cancel()
- }
-
- private fun tip(message: String?) {
- if (GlobalState.flutterEngine == null) {
- Toast.makeText(FlClashApplication.getAppContext(), message, Toast.LENGTH_LONG).show()
- }
- }
-
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"moveTaskToBack" -> {
@@ -196,7 +164,7 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
}
if (iconMap["default"] == null) {
iconMap["default"] =
- FlClashApplication.getAppContext().packageManager?.defaultActivityIcon?.getBase64()
+ GlobalState.application.packageManager?.defaultActivityIcon?.getBase64()
}
result.success(iconMap["default"])
return@launch
@@ -210,56 +178,36 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
result.success(true)
}
- "openFile" -> {
- val path = call.argument("path")!!
- openFile(path)
- result.success(true)
- }
-
else -> {
result.notImplemented()
}
}
}
- private fun openFile(path: String) {
- val file = File(path)
- val uri = FileProvider.getUriForFile(
- FlClashApplication.getAppContext(),
- "${FlClashApplication.getAppContext().packageName}.fileProvider",
- file
- )
-
- val intent = Intent(Intent.ACTION_VIEW).setDataAndType(
- uri,
- "text/plain"
- )
-
- val flags =
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
-
- val resInfoList = FlClashApplication.getAppContext().packageManager.queryIntentActivities(
- intent, PackageManager.MATCH_DEFAULT_ONLY
- )
-
- for (resolveInfo in resInfoList) {
- val packageName = resolveInfo.activityInfo.packageName
- FlClashApplication.getAppContext().grantUriPermission(
- packageName,
- uri,
- flags
+ private fun initShortcuts(label: String) {
+ val shortcut = with(ShortcutInfoCompat.Builder(GlobalState.application, "toggle")) {
+ setShortLabel(label)
+ setIcon(
+ IconCompat.createWithResource(
+ GlobalState.application,
+ R.mipmap.ic_launcher_round,
+ )
)
+ setIntent(QuickAction.TOGGLE.quickIntent)
+ build()
}
-
- try {
- activityRef?.get()?.startActivity(intent)
- } catch (e: Exception) {
- println(e)
- }
+ ShortcutManagerCompat.setDynamicShortcuts(
+ GlobalState.application, listOf(shortcut)
+ )
}
+ private fun tip(message: String?) {
+ Toast.makeText(GlobalState.application, message, Toast.LENGTH_LONG).show()
+ }
+
+ @Suppress("DEPRECATION")
private fun updateExcludeFromRecents(value: Boolean?) {
- val am = getSystemService(FlClashApplication.getAppContext(), ActivityManager::class.java)
+ val am = getSystemService(GlobalState.application, ActivityManager::class.java)
val task = am?.appTasks?.firstOrNull {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
it.taskInfo.taskId == activityRef?.get()?.taskId
@@ -276,7 +224,7 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
}
private suspend fun getPackageIcon(packageName: String): String? {
- val packageManager = FlClashApplication.getAppContext().packageManager
+ val packageManager = GlobalState.application.packageManager
if (iconMap[packageName] == null) {
iconMap[packageName] = try {
packageManager?.getApplicationIcon(packageName)?.getBase64()
@@ -289,11 +237,11 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
}
private fun getPackages(): List {
- val packageManager = FlClashApplication.getAppContext().packageManager
+ val packageManager = GlobalState.application.packageManager
if (packages.isNotEmpty()) return packages
packageManager?.getInstalledPackages(PackageManager.GET_META_DATA or PackageManager.GET_PERMISSIONS)
?.filter {
- it.packageName != FlClashApplication.getAppContext().packageName || it.packageName == "android"
+ it.packageName != GlobalState.application.packageName || it.packageName == "android"
}?.map {
Package(
@@ -321,52 +269,63 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
}
}
- fun requestVpnPermission(callBack: () -> Unit) {
- vpnCallBack = callBack
- val intent = VpnService.prepare(FlClashApplication.getAppContext())
- if (intent != null) {
- activityRef?.get()?.startActivityForResult(intent, VPN_PERMISSION_REQUEST_CODE)
- return
- }
- vpnCallBack?.invoke()
- }
-
- fun requestNotificationsPermission() {
+ fun requestNotificationsPermission(callBack: () -> Unit) {
+ requestNotificationCallback = callBack
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val permission = ContextCompat.checkSelfPermission(
- FlClashApplication.getAppContext(),
- Manifest.permission.POST_NOTIFICATIONS
+ GlobalState.application, Manifest.permission.POST_NOTIFICATIONS
)
- if (permission != PackageManager.PERMISSION_GRANTED) {
- if (isBlockNotification) return
- if (activityRef?.get() == null) return
- activityRef?.get()?.let {
- ActivityCompat.requestPermissions(
- it,
- arrayOf(Manifest.permission.POST_NOTIFICATIONS),
- NOTIFICATION_PERMISSION_REQUEST_CODE
- )
- return
- }
+ if (permission == PackageManager.PERMISSION_GRANTED || isBlockNotification) {
+ invokeRequestNotificationCallback()
+ return
+ }
+ activityRef?.get()?.let {
+ ActivityCompat.requestPermissions(
+ it,
+ arrayOf(Manifest.permission.POST_NOTIFICATIONS),
+ NOTIFICATION_PERMISSION_REQUEST_CODE
+ )
+ return
}
}
}
- suspend fun getText(text: String): String? {
- return withContext(Dispatchers.Default) {
- channel.awaitResult("getText", text)
+ fun invokeRequestNotificationCallback() {
+ requestNotificationCallback?.invoke()
+ requestNotificationCallback = null
+ }
+
+ fun prepare(needPrepare: Boolean, callBack: (suspend () -> Unit)) {
+ vpnPrepareCallback = callBack
+ if (!needPrepare) {
+ invokeVpnPrepareCallback()
+ return
+ }
+ val intent = VpnService.prepare(GlobalState.application)
+ if (intent != null) {
+ activityRef?.get()?.startActivityForResult(intent, VPN_PERMISSION_REQUEST_CODE)
+ return
+ }
+ invokeVpnPrepareCallback()
+ }
+
+ fun invokeVpnPrepareCallback() {
+ GlobalState.launch {
+ vpnPrepareCallback?.invoke()
+ vpnPrepareCallback = null
}
}
+
+ @Suppress("DEPRECATION")
private fun isChinaPackage(packageName: String): Boolean {
- val packageManager = FlClashApplication.getAppContext().packageManager ?: return false
+ val packageManager = GlobalState.application.packageManager ?: return false
skipPrefixList.forEach {
if (packageName == it || packageName.startsWith("$it.")) return false
}
val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
} else {
- @Suppress("DEPRECATION")
PackageManager.GET_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
}
if (packageName.matches(chinaAppRegex)) {
@@ -375,8 +334,7 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
try {
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(
- packageName,
- PackageManager.PackageInfoFlags.of(packageManagerFlags.toLong())
+ packageName, PackageManager.PackageInfoFlags.of(packageManagerFlags.toLong())
)
} else {
packageManager.getPackageInfo(
@@ -427,6 +385,18 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
return false
}
+ override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
+ scope = CoroutineScope(Dispatchers.Default)
+ channel =
+ MethodChannel(flutterPluginBinding.binaryMessenger, "${Components.PACKAGE_NAME}/app")
+ channel.setMethodCallHandler(this)
+ }
+
+ override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
+ channel.setMethodCallHandler(null)
+ scope.cancel()
+ }
+
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activityRef = WeakReference(binding.activity)
binding.addActivityResultListener(::onActivityResult)
@@ -449,21 +419,19 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
private fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
if (requestCode == VPN_PERMISSION_REQUEST_CODE) {
if (resultCode == FlutterActivity.RESULT_OK) {
- GlobalState.initServiceEngine()
- vpnCallBack?.invoke()
+ invokeVpnPrepareCallback()
}
}
return true
}
private fun onRequestPermissionsResultListener(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
+ requestCode: Int, permissions: Array, grantResults: IntArray
): Boolean {
if (requestCode == NOTIFICATION_PERMISSION_REQUEST_CODE) {
isBlockNotification = true
}
+ invokeRequestNotificationCallback()
return true
}
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt
index 62db45d..7ef78fb 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt
@@ -1,19 +1,33 @@
package com.follow.clash.plugins
-import com.follow.clash.GlobalState
-import com.follow.clash.models.VpnOptions
+import com.follow.clash.RunState
+import com.follow.clash.Service
+import com.follow.clash.State
+import com.follow.clash.awaitResult
+import com.follow.clash.common.Components
+import com.follow.clash.invokeMethodOnMainThread
+import com.follow.clash.models.AppState
+import com.follow.clash.service.models.NotificationParams
+import com.follow.clash.service.models.VpnOptions
import com.google.gson.Gson
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Semaphore
+import kotlinx.coroutines.sync.withPermit
-
-data object ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
-
+class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
+ CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
private lateinit var flutterMethodChannel: MethodChannel
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
- flutterMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "service")
+ flutterMethodChannel = MethodChannel(
+ flutterPluginBinding.binaryMessenger, "${Components.PACKAGE_NAME}/service"
+ )
flutterMethodChannel.setMethodCallHandler(this)
}
@@ -22,28 +36,28 @@ data object ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) = when (call.method) {
- "startVpn" -> {
- val data = call.argument("data")
- val options = Gson().fromJson(data, VpnOptions::class.java)
- GlobalState.getCurrentVPNPlugin()?.handleStart(options)
- result.success(true)
- }
-
- "stopVpn" -> {
- GlobalState.getCurrentVPNPlugin()?.handleStop()
- result.success(true)
- }
-
"init" -> {
- GlobalState.getCurrentAppPlugin()
- ?.requestNotificationsPermission()
- GlobalState.initServiceEngine()
- result.success(true)
+ handleInit(result)
}
- "destroy" -> {
- handleDestroy()
- result.success(true)
+ "invokeAction" -> {
+ handleInvokeAction(call, result)
+ }
+
+ "getRunTime" -> {
+ handleGetRunTime(result)
+ }
+
+ "syncState" -> {
+ handleSyncState(call, result)
+ }
+
+ "start" -> {
+ handleStart(result)
+ }
+
+ "stop" -> {
+ handleStop(result)
}
else -> {
@@ -51,8 +65,73 @@ data object ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
}
}
+ private fun handleInvokeAction(call: MethodCall, result: MethodChannel.Result) {
+ launch {
+ val data = call.arguments()!!
+ Service.invokeAction(data) {
+ result.success(it)
+ }
+ }
+ }
- private fun handleDestroy() {
- GlobalState.destroyServiceEngine()
+ private fun handleStart(result: MethodChannel.Result) {
+ State.handleStartService()
+ result.success(true)
+ }
+
+ private fun handleStop(result: MethodChannel.Result) {
+ State.handleStopService()
+ result.success(true)
+ }
+
+ suspend fun handleGetVpnOptions(): VpnOptions? {
+ val res = flutterMethodChannel.awaitResult("getVpnOptions", null)
+ return Gson().fromJson(res, VpnOptions::class.java)
+ }
+
+ val semaphore = Semaphore(10)
+
+ fun handleSendEvent(value: String?) {
+ launch(Dispatchers.Main) {
+ semaphore.withPermit {
+ flutterMethodChannel.invokeMethod("event", value)
+ }
+ }
+ }
+
+ private fun onServiceCrash() {
+ State.runStateFlow.tryEmit(RunState.STOP)
+ flutterMethodChannel.invokeMethodOnMainThread("crash", null)
+ }
+
+ private fun handleSyncState(call: MethodCall, result: MethodChannel.Result) {
+ launch {
+ val data = call.arguments()!!
+ val params = Gson().fromJson(data, AppState::class.java)
+ Service.updateNotificationParams(
+ NotificationParams(
+ title = params.currentProfileName,
+ stopText = params.stopText,
+ onlyStatisticsProxy = params.onlyStatisticsProxy
+ )
+ )
+ result.success(true)
+ }
+
+ }
+
+ fun handleInit(result: MethodChannel.Result) {
+ Service.bind()
+ launch {
+ Service.setMessageCallback {
+ handleSendEvent(it)
+ }
+ result.success(true)
+ }
+ Service.onServiceCrash = ::onServiceCrash
+ }
+
+ private fun handleGetRunTime(result: MethodChannel.Result) {
+ return result.success(State.runTime)
}
}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/TilePlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/TilePlugin.kt
index 6a6bd97..f7a5732 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/TilePlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/TilePlugin.kt
@@ -1,5 +1,7 @@
package com.follow.clash.plugins
+import com.follow.clash.common.Components
+import com.follow.clash.invokeMethodOnMainThread
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
@@ -9,25 +11,21 @@ class TilePlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private lateinit var channel: MethodChannel
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
- channel = MethodChannel(flutterPluginBinding.binaryMessenger, "tile")
+ channel =
+ MethodChannel(flutterPluginBinding.binaryMessenger, "${Components.PACKAGE_NAME}/tile")
channel.setMethodCallHandler(this)
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
- handleDetached()
channel.setMethodCallHandler(null)
}
fun handleStart() {
- channel.invokeMethod("start", null)
+ channel.invokeMethodOnMainThread("start", null)
}
fun handleStop() {
- channel.invokeMethod("stop", null)
- }
-
- private fun handleDetached() {
- channel.invokeMethod("detached", null)
+ channel.invokeMethodOnMainThread("stop", null)
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
deleted file mode 100644
index 3d3cc39..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
+++ /dev/null
@@ -1,276 +0,0 @@
-package com.follow.clash.plugins
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.ServiceConnection
-import android.net.ConnectivityManager
-import android.net.Network
-import android.net.NetworkCapabilities
-import android.net.NetworkRequest
-import android.os.Build
-import android.os.IBinder
-import androidx.core.content.getSystemService
-import com.follow.clash.FlClashApplication
-import com.follow.clash.GlobalState
-import com.follow.clash.RunState
-import com.follow.clash.core.Core
-import com.follow.clash.extensions.awaitResult
-import com.follow.clash.extensions.resolveDns
-import com.follow.clash.models.StartForegroundParams
-import com.follow.clash.models.VpnOptions
-import com.follow.clash.services.BaseServiceInterface
-import com.follow.clash.services.FlClashService
-import com.follow.clash.services.FlClashVpnService
-import com.google.gson.Gson
-import io.flutter.embedding.engine.plugins.FlutterPlugin
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.common.MethodChannel
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.isActive
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import java.net.InetSocketAddress
-import kotlin.concurrent.withLock
-
-data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
- private lateinit var flutterMethodChannel: MethodChannel
- private var flClashService: BaseServiceInterface? = null
- private var options: VpnOptions? = null
- private var isBind: Boolean = false
- private lateinit var scope: CoroutineScope
- private var lastStartForegroundParams: StartForegroundParams? = null
- private var timerJob: Job? = null
- private val uidPageNameMap = mutableMapOf()
-
- private val connectivity by lazy {
- FlClashApplication.getAppContext().getSystemService()
- }
-
- private val connection = object : ServiceConnection {
- override fun onServiceConnected(className: ComponentName, service: IBinder) {
- isBind = true
- flClashService = when (service) {
- is FlClashVpnService.LocalBinder -> service.getService()
- is FlClashService.LocalBinder -> service.getService()
- else -> throw Exception("invalid binder")
- }
- handleStartService()
- }
-
- override fun onServiceDisconnected(arg: ComponentName) {
- isBind = false
- flClashService = null
- }
- }
-
- override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
- scope = CoroutineScope(Dispatchers.Default)
- scope.launch {
- registerNetworkCallback()
- }
- flutterMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "vpn")
- flutterMethodChannel.setMethodCallHandler(this)
- }
-
- override fun onDetachedFromEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
- unRegisterNetworkCallback()
- flutterMethodChannel.setMethodCallHandler(null)
- }
-
- override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
- when (call.method) {
- "start" -> {
- val data = call.argument("data")
- result.success(handleStart(Gson().fromJson(data, VpnOptions::class.java)))
- }
-
- "stop" -> {
- handleStop()
- result.success(true)
- }
-
- else -> {
- result.notImplemented()
- }
- }
- }
-
- fun handleStart(options: VpnOptions): Boolean {
- onUpdateNetwork();
- if (options.enable != this.options?.enable) {
- this.flClashService = null
- }
- this.options = options
- when (options.enable) {
- true -> handleStartVpn()
- false -> handleStartService()
- }
- return true
- }
-
- private fun handleStartVpn() {
- GlobalState.getCurrentAppPlugin()?.requestVpnPermission {
- handleStartService()
- }
- }
-
- fun requestGc() {
- flutterMethodChannel.invokeMethod("gc", null)
- }
-
- val networks = mutableSetOf()
-
- fun onUpdateNetwork() {
- val dns = networks.flatMap { network ->
- connectivity?.resolveDns(network) ?: emptyList()
- }.toSet().joinToString(",")
- scope.launch {
- withContext(Dispatchers.Main) {
- flutterMethodChannel.invokeMethod("dnsChanged", dns)
- }
- }
- }
-
- private val callback = object : ConnectivityManager.NetworkCallback() {
- override fun onAvailable(network: Network) {
- networks.add(network)
- onUpdateNetwork()
- }
-
- override fun onLost(network: Network) {
- networks.remove(network)
- onUpdateNetwork()
- }
- }
-
- private val request = NetworkRequest.Builder().apply {
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- }.build()
-
- private fun registerNetworkCallback() {
- networks.clear()
- connectivity?.registerNetworkCallback(request, callback)
- }
-
- private fun unRegisterNetworkCallback() {
- connectivity?.unregisterNetworkCallback(callback)
- networks.clear()
- onUpdateNetwork()
- }
-
- private suspend fun startForeground() {
- GlobalState.runLock.lock()
- try {
- if (GlobalState.runState.value != RunState.START) return
- val data = flutterMethodChannel.awaitResult("getStartForegroundParams")
- val startForegroundParams = if (data != null) Gson().fromJson(
- data, StartForegroundParams::class.java
- ) else StartForegroundParams(
- title = "", content = ""
- )
- if (lastStartForegroundParams != startForegroundParams) {
- lastStartForegroundParams = startForegroundParams
- flClashService?.startForeground(
- startForegroundParams.title,
- startForegroundParams.content,
- )
- }
- } finally {
- GlobalState.runLock.unlock()
- }
- }
-
- private fun startForegroundJob() {
- stopForegroundJob()
- timerJob = CoroutineScope(Dispatchers.Main).launch {
- while (isActive) {
- startForeground()
- delay(1000)
- }
- }
- }
-
- private fun stopForegroundJob() {
- timerJob?.cancel()
- timerJob = null
- }
-
-
- suspend fun getStatus(): Boolean? {
- return withContext(Dispatchers.Default) {
- flutterMethodChannel.awaitResult("status", null)
- }
- }
-
- private fun handleStartService() {
- if (flClashService == null) {
- bindService()
- return
- }
- GlobalState.runLock.withLock {
- if (GlobalState.runState.value == RunState.START) return
- GlobalState.runState.value = RunState.START
- val fd = flClashService?.start(options!!)
- Core.startTun(
- fd = fd ?: 0,
- protect = this::protect,
- resolverProcess = this::resolverProcess,
- )
- startForegroundJob()
- }
- }
-
- private fun protect(fd: Int): Boolean {
- return (flClashService as? FlClashVpnService)?.protect(fd) == true
- }
-
- private fun resolverProcess(
- protocol: Int,
- source: InetSocketAddress,
- target: InetSocketAddress,
- uid: Int,
- ): String {
- val nextUid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- connectivity?.getConnectionOwnerUid(protocol, source, target) ?: -1
- } else {
- uid
- }
- if (nextUid == -1) {
- return ""
- }
- if (!uidPageNameMap.containsKey(nextUid)) {
- uidPageNameMap[nextUid] =
- FlClashApplication.getAppContext().packageManager?.getPackagesForUid(nextUid)
- ?.first() ?: ""
- }
- return uidPageNameMap[nextUid] ?: ""
- }
-
- fun handleStop() {
- GlobalState.runLock.withLock {
- if (GlobalState.runState.value == RunState.STOP) return
- GlobalState.runState.value = RunState.STOP
- flClashService?.stop()
- stopForegroundJob()
- Core.stopTun()
- GlobalState.handleTryDestroy()
- }
- }
-
- private fun bindService() {
- if (isBind) {
- FlClashApplication.getAppContext().unbindService(connection)
- }
- val intent = when (options?.enable == true) {
- true -> Intent(FlClashApplication.getAppContext(), FlClashVpnService::class.java)
- false -> Intent(FlClashApplication.getAppContext(), FlClashService::class.java)
- }
- FlClashApplication.getAppContext().bindService(intent, connection, Context.BIND_AUTO_CREATE)
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/BaseServiceInterface.kt b/android/app/src/main/kotlin/com/follow/clash/services/BaseServiceInterface.kt
deleted file mode 100644
index 287267b..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/services/BaseServiceInterface.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.follow.clash.services
-
-import android.annotation.SuppressLint
-import android.app.Notification
-import android.app.Notification.FOREGROUND_SERVICE_IMMEDIATE
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.app.Service
-import android.content.Intent
-import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
-import android.os.Build
-import androidx.core.app.NotificationCompat
-import com.follow.clash.GlobalState
-import com.follow.clash.MainActivity
-import com.follow.clash.R
-import com.follow.clash.extensions.getActionPendingIntent
-import com.follow.clash.models.VpnOptions
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.async
-
-interface BaseServiceInterface {
-
- fun start(options: VpnOptions): Int
-
- fun stop()
-
- suspend fun startForeground(title: String, content: String)
-}
-
-fun Service.createFlClashNotificationBuilder(): Deferred =
- CoroutineScope(Dispatchers.Main).async {
- val stopText = GlobalState.getText("stop")
- val intent = Intent(this@createFlClashNotificationBuilder, MainActivity::class.java)
-
- val pendingIntent = if (Build.VERSION.SDK_INT >= 31) {
- PendingIntent.getActivity(
- this@createFlClashNotificationBuilder,
- 0,
- intent,
- PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
- )
- } else {
- PendingIntent.getActivity(
- this@createFlClashNotificationBuilder, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
- )
- }
-
- with(
- NotificationCompat.Builder(
- this@createFlClashNotificationBuilder, GlobalState.NOTIFICATION_CHANNEL
- )
- ) {
- setSmallIcon(R.drawable.ic)
- setContentTitle("FlClash")
- setContentIntent(pendingIntent)
- setCategory(NotificationCompat.CATEGORY_SERVICE)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- foregroundServiceBehavior = FOREGROUND_SERVICE_IMMEDIATE
- }
- setOngoing(true)
- addAction(
- 0, stopText, getActionPendingIntent("STOP")
- )
- setShowWhen(false)
- setOnlyAlertOnce(true)
- }
- }
-
-@SuppressLint("ForegroundServiceType")
-fun Service.startForeground(notification: Notification) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val manager = getSystemService(NotificationManager::class.java)
- var channel = manager?.getNotificationChannel(GlobalState.NOTIFICATION_CHANNEL)
- if (channel == null) {
- channel = NotificationChannel(
- GlobalState.NOTIFICATION_CHANNEL, "SERVICE_CHANNEL", NotificationManager.IMPORTANCE_LOW
- )
- manager?.createNotificationChannel(channel)
- }
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- try {
- startForeground(
- GlobalState.NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC
- )
- } catch (_: Exception) {
- startForeground(GlobalState.NOTIFICATION_ID, notification)
- }
- } else {
- startForeground(GlobalState.NOTIFICATION_ID, notification)
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt
deleted file mode 100644
index 2f09531..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.follow.clash.services
-
-import android.annotation.SuppressLint
-import android.app.Service
-import android.content.Intent
-import android.os.Binder
-import android.os.Build
-import android.os.IBinder
-import androidx.core.app.NotificationCompat
-import com.follow.clash.GlobalState
-import com.follow.clash.models.VpnOptions
-
-
-class FlClashService : Service(), BaseServiceInterface {
-
- override fun start(options: VpnOptions) = 0
-
- override fun stop() {
- stopSelf()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- stopForeground(STOP_FOREGROUND_REMOVE)
- }
- }
-
- private var cachedBuilder: NotificationCompat.Builder? = null
-
- private suspend fun notificationBuilder(): NotificationCompat.Builder {
- if (cachedBuilder == null) {
- cachedBuilder = createFlClashNotificationBuilder().await()
- }
- return cachedBuilder!!
- }
-
- @SuppressLint("ForegroundServiceType")
- override suspend fun startForeground(title: String, content: String) {
- startForeground(
- notificationBuilder()
- .setContentTitle(title)
- .setContentText(content).build()
- )
- }
-
- override fun onTrimMemory(level: Int) {
- super.onTrimMemory(level)
- GlobalState.getCurrentVPNPlugin()?.requestGc()
- }
-
-
- private val binder = LocalBinder()
-
- inner class LocalBinder : Binder() {
- fun getService(): FlClashService = this@FlClashService
- }
-
- override fun onBind(intent: Intent): IBinder {
- return binder
- }
-
- override fun onUnbind(intent: Intent?): Boolean {
- return super.onUnbind(intent)
- }
-
- override fun onDestroy() {
- stop()
- super.onDestroy()
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt
deleted file mode 100644
index 76e4083..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.follow.clash.services
-
-import android.annotation.SuppressLint
-import android.app.PendingIntent
-import android.content.Intent
-import android.os.Build
-import android.service.quicksettings.Tile
-import android.service.quicksettings.TileService
-import androidx.annotation.RequiresApi
-import androidx.lifecycle.Observer
-import com.follow.clash.GlobalState
-import com.follow.clash.RunState
-import com.follow.clash.TempActivity
-
-
-@RequiresApi(Build.VERSION_CODES.N)
-class FlClashTileService : TileService() {
-
- private val observer = Observer { runState ->
- updateTile(runState)
- }
-
- private fun updateTile(runState: RunState) {
- if (qsTile != null) {
- qsTile.state = when (runState) {
- RunState.START -> Tile.STATE_ACTIVE
- RunState.PENDING -> Tile.STATE_UNAVAILABLE
- RunState.STOP -> Tile.STATE_INACTIVE
- }
- qsTile.updateTile()
- }
- }
-
- override fun onStartListening() {
- super.onStartListening()
- GlobalState.syncStatus()
- GlobalState.runState.value?.let { updateTile(it) }
- GlobalState.runState.observeForever(observer)
- }
-
- @SuppressLint("StartActivityAndCollapseDeprecated")
- private fun activityTransfer() {
- val intent = Intent(this, TempActivity::class.java)
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
- val pendingIntent = if (Build.VERSION.SDK_INT >= 31) {
- PendingIntent.getActivity(
- this,
- 0,
- intent,
- PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
- )
- } else {
- PendingIntent.getActivity(
- this,
- 0,
- intent,
- PendingIntent.FLAG_UPDATE_CURRENT
- )
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- startActivityAndCollapse(pendingIntent)
- } else {
- startActivityAndCollapse(intent)
- }
- }
-
- override fun onClick() {
- super.onClick()
- activityTransfer()
- GlobalState.handleToggle()
- }
-
- override fun onDestroy() {
- GlobalState.runState.removeObserver(observer)
- super.onDestroy()
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
deleted file mode 100644
index cb6ab40..0000000
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
+++ /dev/null
@@ -1,193 +0,0 @@
-package com.follow.clash.services
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.net.ProxyInfo
-import android.net.VpnService
-import android.os.Binder
-import android.os.Build
-import android.os.IBinder
-import android.os.Parcel
-import android.os.RemoteException
-import android.util.Log
-import androidx.core.app.NotificationCompat
-import com.follow.clash.GlobalState
-import com.follow.clash.extensions.getIpv4RouteAddress
-import com.follow.clash.extensions.getIpv6RouteAddress
-import com.follow.clash.extensions.toCIDR
-import com.follow.clash.models.AccessControlMode
-import com.follow.clash.models.VpnOptions
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-
-
-class FlClashVpnService : VpnService(), BaseServiceInterface {
- override fun onCreate() {
- super.onCreate()
- GlobalState.initServiceEngine()
- }
-
- override fun start(options: VpnOptions): Int {
- return with(Builder()) {
- if (options.ipv4Address.isNotEmpty()) {
- val cidr = options.ipv4Address.toCIDR()
- addAddress(cidr.address, cidr.prefixLength)
- Log.d(
- "addAddress",
- "address: ${cidr.address} prefixLength:${cidr.prefixLength}"
- )
- val routeAddress = options.getIpv4RouteAddress()
- if (routeAddress.isNotEmpty()) {
- try {
- routeAddress.forEach { i ->
- Log.d(
- "addRoute4",
- "address: ${i.address} prefixLength:${i.prefixLength}"
- )
- addRoute(i.address, i.prefixLength)
- }
- } catch (_: Exception) {
- addRoute("0.0.0.0", 0)
- }
- } else {
- addRoute("0.0.0.0", 0)
- }
- } else {
- addRoute("0.0.0.0", 0)
- }
- try {
- if (options.ipv6Address.isNotEmpty()) {
- val cidr = options.ipv6Address.toCIDR()
- Log.d(
- "addAddress6",
- "address: ${cidr.address} prefixLength:${cidr.prefixLength}"
- )
- addAddress(cidr.address, cidr.prefixLength)
- val routeAddress = options.getIpv6RouteAddress()
- if (routeAddress.isNotEmpty()) {
- try {
- routeAddress.forEach { i ->
- Log.d(
- "addRoute6",
- "address: ${i.address} prefixLength:${i.prefixLength}"
- )
- addRoute(i.address, i.prefixLength)
- }
- } catch (_: Exception) {
- addRoute("::", 0)
- }
- } else {
- addRoute("::", 0)
- }
- }
- }catch (_:Exception){
- Log.d(
- "addAddress6",
- "IPv6 is not supported."
- )
- }
- addDnsServer(options.dnsServerAddress)
- setMtu(9000)
- options.accessControl.let { accessControl ->
- if (accessControl.enable) {
- when (accessControl.mode) {
- AccessControlMode.acceptSelected -> {
- (accessControl.acceptList + packageName).forEach {
- addAllowedApplication(it)
- }
- }
-
- AccessControlMode.rejectSelected -> {
- (accessControl.rejectList - packageName).forEach {
- addDisallowedApplication(it)
- }
- }
- }
- }
- }
- setSession("FlClash")
- setBlocking(false)
- if (Build.VERSION.SDK_INT >= 29) {
- setMetered(false)
- }
- if (options.allowBypass) {
- allowBypass()
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && options.systemProxy) {
- setHttpProxy(
- ProxyInfo.buildDirectProxy(
- "127.0.0.1",
- options.port,
- options.bypassDomain
- )
- )
- }
- establish()?.detachFd()
- ?: throw NullPointerException("Establish VPN rejected by system")
- }
- }
-
- override fun stop() {
- stopSelf()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- stopForeground(STOP_FOREGROUND_REMOVE)
- }
- }
-
- private var cachedBuilder: NotificationCompat.Builder? = null
-
- private suspend fun notificationBuilder(): NotificationCompat.Builder {
- if (cachedBuilder == null) {
- cachedBuilder = createFlClashNotificationBuilder().await()
- }
- return cachedBuilder!!
- }
-
- @SuppressLint("ForegroundServiceType")
- override suspend fun startForeground(title: String, content: String) {
- startForeground(
- notificationBuilder()
- .setContentTitle(title)
- .setContentText(content).build()
- )
- }
-
- override fun onTrimMemory(level: Int) {
- super.onTrimMemory(level)
- GlobalState.getCurrentVPNPlugin()?.requestGc()
- }
-
- private val binder = LocalBinder()
-
- inner class LocalBinder : Binder() {
- fun getService(): FlClashVpnService = this@FlClashVpnService
-
- override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
- try {
- val isSuccess = super.onTransact(code, data, reply, flags)
- if (!isSuccess) {
- CoroutineScope(Dispatchers.Main).launch {
- GlobalState.getCurrentTilePlugin()?.handleStop()
- }
- }
- return isSuccess
- } catch (e: RemoteException) {
- throw e
- }
- }
- }
-
- override fun onBind(intent: Intent): IBinder {
- return binder
- }
-
- override fun onUnbind(intent: Intent?): Boolean {
- return super.onUnbind(intent)
- }
-
- override fun onDestroy() {
- stop()
- super.onDestroy()
- }
-}
\ No newline at end of file
diff --git a/android/build.gradle.kts b/android/build.gradle.kts
index 1bfd741..8f89645 100644
--- a/android/build.gradle.kts
+++ b/android/build.gradle.kts
@@ -1,3 +1,12 @@
+buildscript {
+ dependencies {
+ classpath(libs.build.kotlin)
+ }
+}
+
+plugins {
+ id("com.android.library") apply false
+}
allprojects {
repositories {
@@ -5,8 +14,10 @@ allprojects {
mavenCentral()
}
}
-
-val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
+val newBuildDir: Directory =
+ rootProject.layout.buildDirectory
+ .dir("../../build")
+ .get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
@@ -20,3 +31,4 @@ subprojects {
tasks.register("clean") {
delete(rootProject.layout.buildDirectory)
}
+
diff --git a/android/common/.gitignore b/android/common/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/android/common/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/android/common/build.gradle.kts b/android/common/build.gradle.kts
new file mode 100644
index 0000000..4fe775f
--- /dev/null
+++ b/android/common/build.gradle.kts
@@ -0,0 +1,42 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace = "com.follow.clash.common"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+
+ defaultConfig {
+ minSdk = 21
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+}
+
+dependencies {
+ implementation(libs.androidx.core)
+ implementation(libs.gson)
+}
\ No newline at end of file
diff --git a/android/common/src/main/AndroidManifest.xml b/android/common/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c7fd999
--- /dev/null
+++ b/android/common/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/common/src/main/java/com/follow/clash/common/Components.kt b/android/common/src/main/java/com/follow/clash/common/Components.kt
new file mode 100644
index 0000000..6d8dd50
--- /dev/null
+++ b/android/common/src/main/java/com/follow/clash/common/Components.kt
@@ -0,0 +1,16 @@
+package com.follow.clash.common
+
+import android.content.ComponentName
+
+object Components {
+ const val PACKAGE_NAME = "com.follow.clash"
+
+ val MAIN_ACTIVITY =
+ ComponentName(GlobalState.packageName, "${PACKAGE_NAME}.MainActivity")
+
+ val TEMP_ACTIVITY =
+ ComponentName(GlobalState.packageName, "${PACKAGE_NAME}.TempActivity")
+
+ val BROADCAST_RECEIVER =
+ ComponentName(GlobalState.packageName, "${PACKAGE_NAME}.BroadcastReceiver")
+}
\ No newline at end of file
diff --git a/android/common/src/main/java/com/follow/clash/common/Enums.kt b/android/common/src/main/java/com/follow/clash/common/Enums.kt
new file mode 100644
index 0000000..c56b2b9
--- /dev/null
+++ b/android/common/src/main/java/com/follow/clash/common/Enums.kt
@@ -0,0 +1,24 @@
+package com.follow.clash.common
+
+import com.google.gson.annotations.SerializedName
+
+
+enum class QuickAction {
+ STOP,
+ START,
+ TOGGLE,
+}
+
+enum class BroadcastAction {
+ START,
+ STOP,
+ TOGGLE,
+}
+
+enum class AccessControlMode {
+ @SerializedName("acceptSelected")
+ ACCEPT_SELECTED,
+
+ @SerializedName("rejectSelected")
+ REJECT_SELECTED,
+}
\ No newline at end of file
diff --git a/android/common/src/main/java/com/follow/clash/common/Ext.kt b/android/common/src/main/java/com/follow/clash/common/Ext.kt
new file mode 100644
index 0000000..56e34fa
--- /dev/null
+++ b/android/common/src/main/java/com/follow/clash/common/Ext.kt
@@ -0,0 +1,204 @@
+package com.follow.clash.common
+
+import android.annotation.SuppressLint
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Context.RECEIVER_NOT_EXPORTED
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.ServiceConnection
+import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
+import android.os.Build
+import android.os.IBinder
+import android.os.RemoteException
+import android.util.Log
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlin.reflect.KClass
+
+//fun Context.startForegroundServiceCompat(intent: Intent?) {
+// if (Build.VERSION.SDK_INT >= 26) {
+// startForegroundService(intent)
+// } else {
+// startService(intent)
+// }
+//}
+
+val KClass<*>.intent: Intent
+ get() = Intent(GlobalState.application, this.java)
+
+fun Service.startForegroundCompat(id: Int, notification: Notification) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ startForeground(id, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
+ } else {
+ startForeground(id, notification)
+ }
+}
+
+val QuickAction.action: String
+ get() = "${GlobalState.application.packageName}.action.${this.name}"
+
+val QuickAction.quickIntent: Intent
+ get() = Intent().apply {
+ setComponent(Components.TEMP_ACTIVITY)
+ setPackage(GlobalState.packageName)
+ action = this@quickIntent.action
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
+ }
+
+val BroadcastAction.action: String
+ get() = "${GlobalState.application.packageName}.intent.action.${this.name}"
+
+val BroadcastAction.quickIntent: Intent
+ get() = Intent().apply {
+ setComponent(Components.BROADCAST_RECEIVER)
+ setPackage(GlobalState.packageName)
+ action = this@quickIntent.action
+ }
+
+fun BroadcastAction.sendBroadcast() {
+ val intent = Intent().apply {
+ action = this@sendBroadcast.action
+ Log.d("[sendBroadcast]", "$action")
+ setPackage(GlobalState.packageName)
+ }
+ GlobalState.application.sendBroadcast(
+ intent, GlobalState.RECEIVE_BROADCASTS_PERMISSIONS
+ )
+}
+
+
+val Intent.toPendingIntent: PendingIntent
+ get() = PendingIntent.getActivity(
+ GlobalState.application,
+ 0,
+ this,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+
+
+fun Service.startForeground(notification: Notification) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val manager = getSystemService(NotificationManager::class.java)
+ var channel = manager?.getNotificationChannel(GlobalState.NOTIFICATION_CHANNEL)
+ if (channel == null) {
+ channel = NotificationChannel(
+ GlobalState.NOTIFICATION_CHANNEL,
+ "SERVICE_CHANNEL",
+ NotificationManager.IMPORTANCE_LOW
+ )
+ manager?.createNotificationChannel(channel)
+ }
+ }
+ startForegroundCompat(GlobalState.NOTIFICATION_ID, notification)
+}
+
+@SuppressLint("UnspecifiedRegisterReceiverFlag")
+fun Context.registerReceiverCompat(
+ receiver: BroadcastReceiver,
+ filter: IntentFilter,
+) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ registerReceiver(receiver, filter, RECEIVER_NOT_EXPORTED)
+} else {
+ registerReceiver(receiver, filter)
+}
+
+fun Context.receiveBroadcastFlow(
+ configure: IntentFilter.() -> Unit,
+): Flow = callbackFlow {
+ val filter = IntentFilter().apply(configure)
+ val receiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (context == null || intent == null) return
+ trySend(intent)
+ }
+ }
+ registerReceiverCompat(receiver, filter)
+ awaitClose { unregisterReceiver(receiver) }
+}
+
+
+sealed class BindServiceEvent {
+ data class Connected(val binder: T) : BindServiceEvent()
+ object Disconnected : BindServiceEvent()
+ object Crashed : BindServiceEvent()
+}
+
+inline fun Context.bindServiceFlow(
+ intent: Intent,
+ flags: Int = Context.BIND_AUTO_CREATE,
+): Flow> = callbackFlow {
+ var currentBinder: IBinder? = null
+ val deathRecipient = IBinder.DeathRecipient {
+ trySend(BindServiceEvent.Crashed)
+ }
+
+ val connection = object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
+ if (binder != null) {
+ try {
+ binder.linkToDeath(deathRecipient, 0)
+ currentBinder = binder
+ @Suppress("UNCHECKED_CAST") val casted = binder as? T
+ if (casted != null) {
+ trySend(BindServiceEvent.Connected(casted))
+ } else {
+ GlobalState.log("Binder is not of type ${T::class.java}")
+ trySend(BindServiceEvent.Disconnected)
+ }
+ } catch (e: RemoteException) {
+ GlobalState.log("Failed to link to death: ${e.message}")
+ binder.unlinkToDeath(deathRecipient, 0)
+ trySend(BindServiceEvent.Disconnected)
+ }
+ } else {
+ trySend(BindServiceEvent.Disconnected)
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) {
+ GlobalState.log("Service disconnected")
+ currentBinder?.unlinkToDeath(deathRecipient, 0)
+ currentBinder = null
+ trySend(BindServiceEvent.Disconnected)
+ }
+ }
+
+ if (!bindService(intent, connection, flags)) {
+ GlobalState.log("Failed to bind service")
+ trySend(BindServiceEvent.Disconnected)
+ close()
+ return@callbackFlow
+ }
+
+ awaitClose {
+ currentBinder?.unlinkToDeath(deathRecipient, 0)
+ unbindService(connection)
+ }
+}
+
+
+val Long.formatBytes: String
+ get() {
+ val units = arrayOf("B", "KB", "MB", "GB", "TB")
+ var size = this.toDouble()
+ var unitIndex = 0
+
+ while (size >= 1024 && unitIndex < units.size - 1) {
+ size /= 1024
+ unitIndex++
+ }
+
+ return if (unitIndex == 0) {
+ "${size.toLong()}${units[unitIndex]}"
+ } else {
+ "%.1f${units[unitIndex]}".format(size)
+ }
+ }
\ No newline at end of file
diff --git a/android/common/src/main/java/com/follow/clash/common/GlobalState.kt b/android/common/src/main/java/com/follow/clash/common/GlobalState.kt
new file mode 100644
index 0000000..3ef8957
--- /dev/null
+++ b/android/common/src/main/java/com/follow/clash/common/GlobalState.kt
@@ -0,0 +1,34 @@
+package com.follow.clash.common
+
+import android.app.Application
+import android.util.Log
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+
+object GlobalState : CoroutineScope by CoroutineScope(Dispatchers.Default) {
+
+ const val NOTIFICATION_CHANNEL = "FlClash"
+
+ const val NOTIFICATION_ID = 1
+
+ val packageName: String
+ get() = _application.packageName
+
+ val RECEIVE_BROADCASTS_PERMISSIONS: String
+ get() = "${packageName}.permission.RECEIVE_BROADCASTS"
+
+
+ private lateinit var _application: Application
+
+ val application: Application
+ get() = _application
+
+
+ fun log(text: String) {
+ Log.d("[FlClash]", text)
+ }
+
+ fun init(application: Application) {
+ _application = application
+ }
+}
\ No newline at end of file
diff --git a/android/common/src/main/java/com/follow/clash/common/Service.kt b/android/common/src/main/java/com/follow/clash/common/Service.kt
new file mode 100644
index 0000000..3e02c28
--- /dev/null
+++ b/android/common/src/main/java/com/follow/clash/common/Service.kt
@@ -0,0 +1,71 @@
+package com.follow.clash.common
+
+import android.content.Intent
+import android.os.IBinder
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withTimeoutOrNull
+
+class ServiceDelegate(
+ private val intent: Intent,
+ private val onServiceDisconnected: (() -> Unit)? = null,
+ private val onServiceCrash: (() -> Unit)? = null,
+ private val interfaceCreator: (IBinder) -> T,
+) : CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
+
+ private val _service = MutableStateFlow(null)
+
+ val service: StateFlow = _service
+
+ private var bindJob: Job? = null
+ private fun handleBindEvent(event: BindServiceEvent) {
+ when (event) {
+ is BindServiceEvent.Connected -> {
+ _service.value = event.binder.let(interfaceCreator)
+ }
+
+ is BindServiceEvent.Disconnected -> {
+ _service.value = null
+ onServiceDisconnected?.invoke()
+ }
+
+ is BindServiceEvent.Crashed -> {
+ _service.value = null
+ onServiceCrash?.invoke()
+ }
+ }
+ }
+
+ fun bind() {
+ unbind()
+ bindJob = launch {
+ GlobalState.application.bindServiceFlow(intent).collect { it ->
+ handleBindEvent(it)
+ }
+ }
+ }
+
+ suspend inline fun useService(crossinline block: (T) -> R): Result {
+ return withTimeoutOrNull(10_000) {
+ service.first { it != null }
+ }?.let { service ->
+ try {
+ Result.success(block(service))
+ } catch (e: Exception) {
+ Result.failure(e)
+ }
+ } ?: Result.failure(Exception("Service connection timeout"))
+ }
+
+ fun unbind() {
+ _service.value = null
+ bindJob?.cancel()
+ bindJob = null
+ }
+}
\ No newline at end of file
diff --git a/android/common/src/main/java/com/follow/clash/common/Utils.kt b/android/common/src/main/java/com/follow/clash/common/Utils.kt
new file mode 100644
index 0000000..2b22dd5
--- /dev/null
+++ b/android/common/src/main/java/com/follow/clash/common/Utils.kt
@@ -0,0 +1,14 @@
+package com.follow.clash.common
+
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+
+
+fun tickerFlow(delayMillis: Long, initialDelayMillis: Long = delayMillis): Flow = flow {
+ delay(initialDelayMillis)
+ while (true) {
+ emit(Unit)
+ delay(delayMillis)
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/common/src/main/res/values/strings.xml
similarity index 58%
rename from android/app/src/main/res/values/strings.xml
rename to android/common/src/main/res/values/strings.xml
index 2000dd1..c31b207 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/common/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
- FlClash
+ FlClash
diff --git a/android/core/build.gradle.kts b/android/core/build.gradle.kts
index 1a18c91..38c9f16 100644
--- a/android/core/build.gradle.kts
+++ b/android/core/build.gradle.kts
@@ -1,4 +1,4 @@
-import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.argumentsWithVarargAsSingleArray
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
id("com.android.library")
@@ -7,22 +7,13 @@ plugins {
android {
namespace = "com.follow.clash.core"
- compileSdk = 35
- ndkVersion = "28.0.13004108"
+ compileSdk = libs.versions.compileSdk.get().toInt()
+ ndkVersion = libs.versions.ndkVersion.get()
defaultConfig {
- minSdk = 21
+ minSdk = libs.versions.minSdk.get().toInt()
}
- buildTypes {
- release {
- isJniDebuggable = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
sourceSets {
getByName("main") {
@@ -37,17 +28,30 @@ android {
}
}
- kotlinOptions {
- jvmTarget = "17"
- }
-
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
+
+ buildTypes {
+ release {
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
}
+
+kotlin {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+}
+
+
dependencies {
- implementation("androidx.annotation:annotation-jvm:1.9.1")
+ implementation(libs.annotation.jvm)
}
val copyNativeLibs by tasks.register("copyNativeLibs") {
@@ -56,6 +60,18 @@ val copyNativeLibs by tasks.register("copyNativeLibs") {
}
from("../../libclash/android")
into("src/main/jniLibs")
+
+ doLast {
+ val includesDir = file("src/main/jniLibs/includes")
+ val targetDir = file("src/main/cpp/includes")
+ if (includesDir.exists()) {
+ copy {
+ from(includesDir)
+ into(targetDir)
+ }
+ delete(includesDir)
+ }
+ }
}
afterEvaluate {
diff --git a/android/core/proguard-rules.pro b/android/core/proguard-rules.pro
deleted file mode 100644
index 481bb43..0000000
--- a/android/core/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/android/core/src/main/AndroidManifest.xml b/android/core/src/main/AndroidManifest.xml
index a5918e6..294dbaa 100644
--- a/android/core/src/main/AndroidManifest.xml
+++ b/android/core/src/main/AndroidManifest.xml
@@ -1,4 +1,5 @@
+
\ No newline at end of file
diff --git a/android/core/src/main/cpp/CMakeLists.txt b/android/core/src/main/cpp/CMakeLists.txt
index cdd7623..72e5c10 100644
--- a/android/core/src/main/cpp/CMakeLists.txt
+++ b/android/core/src/main/cpp/CMakeLists.txt
@@ -6,7 +6,9 @@ message("CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}")
message("CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}")
+
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ # set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
add_compile_options(-O3)
add_compile_options(-flto)
@@ -33,7 +35,7 @@ message("LIB_CLASH_PATH ${LIB_CLASH_PATH}")
if (EXISTS ${LIB_CLASH_PATH})
message("Found libclash.so for ABI ${ANDROID_ABI}")
add_compile_definitions(LIBCLASH)
- include_directories(${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
+ include_directories(${CMAKE_SOURCE_DIR}/../cpp/includes/${ANDROID_ABI})
link_directories(${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
add_library(${CMAKE_PROJECT_NAME} SHARED
jni_helper.cpp
diff --git a/android/core/src/main/cpp/core.cpp b/android/core/src/main/cpp/core.cpp
index 19804e8..1772ccb 100644
--- a/android/core/src/main/cpp/core.cpp
+++ b/android/core/src/main/cpp/core.cpp
@@ -1,13 +1,19 @@
-#ifdef LIBCLASH
#include
+
+#ifdef LIBCLASH
+
#include "jni_helper.h"
#include "libclash.h"
+#include "bride.h"
extern "C"
JNIEXPORT void JNICALL
-Java_com_follow_clash_core_Core_startTun(JNIEnv *env, jobject, const jint fd, jobject cb) {
+Java_com_follow_clash_core_Core_startTun(JNIEnv *env, jobject thiz, jint fd, jobject cb,
+ jstring address, jstring dns) {
const auto interface = new_global(cb);
- startTUN(fd, interface);
+ scoped_string addressChar = get_string(address);
+ scoped_string dnsChar = get_string(dns);
+ startTUN(interface, fd, addressChar, dnsChar);
}
extern "C"
@@ -16,9 +22,60 @@ Java_com_follow_clash_core_Core_stopTun(JNIEnv *) {
stopTun();
}
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_forceGC(JNIEnv *env, jobject thiz) {
+ forceGC();
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_updateDNS(JNIEnv *env, jobject thiz, jstring dns) {
+ scoped_string dnsChar = get_string(dns);
+ updateDns(dnsChar);
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_invokeAction(JNIEnv *env, jobject thiz, jstring data, jobject cb) {
+ const auto interface = new_global(cb);
+ scoped_string dataChar = get_string(data);
+ invokeAction(interface, dataChar);
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_setMessageCallback(JNIEnv *env, jobject thiz, jobject cb) {
+ const auto interface = new_global(cb);
+ setMessageCallback(interface);
+}
+
+extern "C"
+JNIEXPORT jstring JNICALL
+Java_com_follow_clash_core_Core_getTraffic(JNIEnv *env, jobject thiz,
+ const jboolean only_statistics_proxy) {
+ scoped_string res = getTraffic(only_statistics_proxy);
+ return new_string(res);
+}
+
+extern "C"
+JNIEXPORT jstring JNICALL
+Java_com_follow_clash_core_Core_getTotalTraffic(JNIEnv *env, jobject thiz,
+ const jboolean only_statistics_proxy) {
+ scoped_string res = getTotalTraffic(only_statistics_proxy);
+ return new_string(res);
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_suspended(JNIEnv *env, jobject thiz, jboolean suspended) {
+ suspend(suspended);
+}
+
static jmethodID m_tun_interface_protect;
static jmethodID m_tun_interface_resolve_process;
+static jmethodID m_invoke_interface_result;
static void release_jni_object_impl(void *obj) {
@@ -33,19 +90,28 @@ static void call_tun_interface_protect_impl(void *tun_interface, const int fd) {
fd);
}
-static const char *
-call_tun_interface_resolve_process_impl(void *tun_interface, int protocol,
+static char *
+call_tun_interface_resolve_process_impl(void *tun_interface, const int protocol,
const char *source,
const char *target,
const int uid) {
ATTACH_JNI();
- const auto packageName = reinterpret_cast(env->CallObjectMethod(static_cast(tun_interface),
- m_tun_interface_resolve_process,
- protocol,
- new_string(source),
- new_string(target),
- uid));
- return get_string(packageName);
+ const auto packageName = reinterpret_cast(env->CallObjectMethod(
+ static_cast(tun_interface),
+ m_tun_interface_resolve_process,
+ protocol,
+ new_string(source),
+ new_string(target),
+ uid));
+ scoped_string packageNameChar = get_string(packageName);
+ return packageNameChar;
+}
+
+static void call_invoke_interface_result_impl(void *invoke_interface, const char *data) {
+ ATTACH_JNI();
+ env->CallVoidMethod(static_cast(invoke_interface),
+ m_invoke_interface_result,
+ new_string(data));
}
extern "C"
@@ -60,13 +126,67 @@ JNI_OnLoad(JavaVM *vm, void *) {
const auto c_tun_interface = find_class("com/follow/clash/core/TunInterface");
+ const auto c_invoke_interface = find_class("com/follow/clash/core/InvokeInterface");
+
m_tun_interface_protect = find_method(c_tun_interface, "protect", "(I)V");
m_tun_interface_resolve_process = find_method(c_tun_interface, "resolverProcess",
"(ILjava/lang/String;Ljava/lang/String;I)Ljava/lang/String;");
+ m_invoke_interface_result = find_method(c_invoke_interface, "onResult",
+ "(Ljava/lang/String;)V");
+
+
+ protect_func = &call_tun_interface_protect_impl;
+ resolve_process_func = &call_tun_interface_resolve_process_impl;
+ result_func = &call_invoke_interface_result_impl;
+ release_object_func = &release_jni_object_impl;
- registerCallbacks(&call_tun_interface_protect_impl,
- &call_tun_interface_resolve_process_impl,
- &release_jni_object_impl);
return JNI_VERSION_1_6;
}
+#else
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_startTun(JNIEnv *env, jobject thiz, jint fd, jobject cb,
+ jstring address, jstring dns) {
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_stopTun(JNIEnv *env, jobject thiz) {
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_invokeAction(JNIEnv *env, jobject thiz, jstring data, jobject cb) {
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_forceGC(JNIEnv *env, jobject thiz) {
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_updateDNS(JNIEnv *env, jobject thiz, jstring dns) {
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_setMessageCallback(JNIEnv *env, jobject thiz, jobject cb) {
+}
+
+extern "C"
+JNIEXPORT jstring JNICALL
+Java_com_follow_clash_core_Core_getTraffic(JNIEnv *env, jobject thiz,
+ const jboolean only_statistics_proxy) {
+}
+extern "C"
+JNIEXPORT jstring JNICALL
+Java_com_follow_clash_core_Core_getTotalTraffic(JNIEnv *env, jobject thiz,
+ const jboolean only_statistics_proxy) {
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_follow_clash_core_Core_suspended(JNIEnv *env, jobject thiz, jboolean suspended) {
+}
#endif
diff --git a/android/core/src/main/cpp/jni_helper.h b/android/core/src/main/cpp/jni_helper.h
index 57fbd55..a408751 100644
--- a/android/core/src/main/cpp/jni_helper.h
+++ b/android/core/src/main/cpp/jni_helper.h
@@ -19,7 +19,7 @@ extern void jni_attach_thread(scoped_jni *jni);
extern void jni_detach_thread(const scoped_jni *env);
-extern void release_string(char **str);
+extern void release_string( char **str);
#define ATTACH_JNI() __attribute__((unused, cleanup(jni_detach_thread))) \
scoped_jni _jni{}; \
diff --git a/android/core/src/main/java/com/follow/clash/core/Core.kt b/android/core/src/main/java/com/follow/clash/core/Core.kt
index c863cae..b1edefe 100644
--- a/android/core/src/main/java/com/follow/clash/core/Core.kt
+++ b/android/core/src/main/java/com/follow/clash/core/Core.kt
@@ -7,7 +7,16 @@ import java.net.URL
data object Core {
private external fun startTun(
fd: Int,
- cb: TunInterface
+ cb: TunInterface,
+ address: String,
+ dns: String,
+ )
+
+ external fun forceGC(
+ )
+
+ external fun updateDNS(
+ dns: String,
)
private fun parseInetSocketAddress(address: String): InetSocketAddress {
@@ -19,31 +28,79 @@ data object Core {
fun startTun(
fd: Int,
protect: (Int) -> Boolean,
- resolverProcess: (protocol: Int, source: InetSocketAddress, target: InetSocketAddress, uid: Int) -> String
+ resolverProcess: (protocol: Int, source: InetSocketAddress, target: InetSocketAddress, uid: Int) -> String,
+ address: String,
+ dns: String,
) {
- startTun(fd, object : TunInterface {
- override fun protect(fd: Int) {
- protect(fd)
- }
+ startTun(
+ fd,
+ object : TunInterface {
+ override fun protect(fd: Int) {
+ protect(fd)
+ }
- override fun resolverProcess(
- protocol: Int,
- source: String,
- target: String,
- uid: Int
- ): String {
- return resolverProcess(
- protocol,
- parseInetSocketAddress(source),
- parseInetSocketAddress(target),
- uid,
- )
- }
- });
+ override fun resolverProcess(
+ protocol: Int,
+ source: String,
+ target: String,
+ uid: Int
+ ): String {
+ return resolverProcess(
+ protocol,
+ parseInetSocketAddress(source),
+ parseInetSocketAddress(target),
+ uid,
+ )
+ }
+ },
+ address,
+ dns
+ )
+ }
+
+ external fun suspended(
+ suspended: Boolean,
+ )
+
+ private external fun invokeAction(
+ data: String,
+ cb: InvokeInterface
+ )
+
+ fun invokeAction(
+ data: String,
+ cb: (result: String?) -> Unit
+ ) {
+ invokeAction(
+ data,
+ object : InvokeInterface {
+ override fun onResult(result: String?) {
+ cb(result)
+ }
+ },
+ )
+ }
+
+ private external fun setMessageCallback(cb: InvokeInterface)
+
+ fun setMessageCallback(
+ cb: (result: String?) -> Unit
+ ) {
+ setMessageCallback(
+ object : InvokeInterface {
+ override fun onResult(result: String?) {
+ cb(result)
+ }
+ },
+ )
}
external fun stopTun()
+ external fun getTraffic(onlyStatisticsProxy: Boolean): String
+
+ external fun getTotalTraffic(onlyStatisticsProxy: Boolean): String
+
init {
System.loadLibrary("core")
}
diff --git a/android/core/src/main/java/com/follow/clash/core/InvokeInterface.kt b/android/core/src/main/java/com/follow/clash/core/InvokeInterface.kt
new file mode 100644
index 0000000..0bf3a8a
--- /dev/null
+++ b/android/core/src/main/java/com/follow/clash/core/InvokeInterface.kt
@@ -0,0 +1,8 @@
+package com.follow.clash.core
+
+import androidx.annotation.Keep
+
+@Keep
+interface InvokeInterface {
+ fun onResult(result: String?)
+}
\ No newline at end of file
diff --git a/android/gradle.properties b/android/gradle.properties
index 9b8b8c5..598d13f 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,3 @@
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
-kotlin_version=1.9.22
-agp_version=8.9.2
diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml
new file mode 100644
index 0000000..990edaf
--- /dev/null
+++ b/android/gradle/libs.versions.toml
@@ -0,0 +1,20 @@
+[versions]
+#agp = "8.10.1"
+minSdk = "23"
+targetSdk = "36"
+compileSdk = "36"
+ndkVersion = "28.0.13004108"
+coreKtx = "1.17.0"
+annotationJvm = "1.9.1"
+coreSplashscreen = "1.0.1"
+gson = "2.13.1"
+kotlin = "2.2.10"
+smaliDexlib2 = "3.0.9"
+
+[libraries]
+build-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
+androidx-core = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
+annotation-jvm = { module = "androidx.annotation:annotation-jvm", version.ref = "annotationJvm" }
+core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
+gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
+smali-dexlib2 = { module = "com.android.tools.smali:smali-dexlib2", version.ref = "smaliDexlib2" }
\ No newline at end of file
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 90df0e8..6064aeb 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
diff --git a/android/service/.gitignore b/android/service/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/android/service/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/android/service/build.gradle.kts b/android/service/build.gradle.kts
new file mode 100644
index 0000000..8d9637b
--- /dev/null
+++ b/android/service/build.gradle.kts
@@ -0,0 +1,48 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+ id("kotlin-parcelize")
+}
+
+android {
+ namespace = "com.follow.clash.service"
+ compileSdk = 36
+
+ defaultConfig {
+ minSdk = libs.versions.minSdk.get().toInt()
+ }
+
+ buildFeatures {
+ aidl = true
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ buildTypes {
+ release {
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+}
+
+
+dependencies {
+ implementation(project(":core"))
+ implementation(project(":common"))
+ implementation(libs.gson)
+ implementation(libs.androidx.core)
+}
\ No newline at end of file
diff --git a/android/service/src/main/AndroidManifest.xml b/android/service/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..64715f1
--- /dev/null
+++ b/android/service/src/main/AndroidManifest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/service/src/main/aidl/com/follow/clash/service/ICallbackInterface.aidl b/android/service/src/main/aidl/com/follow/clash/service/ICallbackInterface.aidl
new file mode 100644
index 0000000..27acc10
--- /dev/null
+++ b/android/service/src/main/aidl/com/follow/clash/service/ICallbackInterface.aidl
@@ -0,0 +1,6 @@
+// ICallbackInterface.aidl
+package com.follow.clash.service;
+
+interface ICallbackInterface {
+ void onResult(String result);
+}
\ No newline at end of file
diff --git a/android/service/src/main/aidl/com/follow/clash/service/IRemoteInterface.aidl b/android/service/src/main/aidl/com/follow/clash/service/IRemoteInterface.aidl
new file mode 100644
index 0000000..f411620
--- /dev/null
+++ b/android/service/src/main/aidl/com/follow/clash/service/IRemoteInterface.aidl
@@ -0,0 +1,14 @@
+// IRemoteInterface.aidl
+package com.follow.clash.service;
+
+import com.follow.clash.service.ICallbackInterface;
+import com.follow.clash.service.models.VpnOptions;
+import com.follow.clash.service.models.NotificationParams;
+
+interface IRemoteInterface {
+ void invokeAction(in String data, in ICallbackInterface callback);
+ void updateNotificationParams(in NotificationParams params);
+ void startService(in VpnOptions options,in boolean inApp);
+ void stopService();
+ void setMessageCallback(in ICallbackInterface messageCallback);
+}
\ No newline at end of file
diff --git a/android/service/src/main/aidl/com/follow/clash/service/models/AccessControl.aidl b/android/service/src/main/aidl/com/follow/clash/service/models/AccessControl.aidl
new file mode 100644
index 0000000..ea75b66
--- /dev/null
+++ b/android/service/src/main/aidl/com/follow/clash/service/models/AccessControl.aidl
@@ -0,0 +1,4 @@
+//AccessControl.aidl
+package com.follow.clash.service.models;
+
+parcelable AccessControl;
\ No newline at end of file
diff --git a/android/service/src/main/aidl/com/follow/clash/service/models/NotificationParams.aidl b/android/service/src/main/aidl/com/follow/clash/service/models/NotificationParams.aidl
new file mode 100644
index 0000000..524221e
--- /dev/null
+++ b/android/service/src/main/aidl/com/follow/clash/service/models/NotificationParams.aidl
@@ -0,0 +1,4 @@
+//NotificationParams.aidl
+package com.follow.clash.service.models;
+
+parcelable NotificationParams;
\ No newline at end of file
diff --git a/android/service/src/main/aidl/com/follow/clash/service/models/VpnOptions.aidl b/android/service/src/main/aidl/com/follow/clash/service/models/VpnOptions.aidl
new file mode 100644
index 0000000..c1d780d
--- /dev/null
+++ b/android/service/src/main/aidl/com/follow/clash/service/models/VpnOptions.aidl
@@ -0,0 +1,6 @@
+//VpnOptions.aidl
+package com.follow.clash.service.models;
+
+import com.follow.clash.service.models.AccessControl;
+
+parcelable VpnOptions;
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/CommonService.kt b/android/service/src/main/java/com/follow/clash/service/CommonService.kt
new file mode 100644
index 0000000..0a41376
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/CommonService.kt
@@ -0,0 +1,55 @@
+package com.follow.clash.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Binder
+import android.os.IBinder
+import com.follow.clash.core.Core
+import com.follow.clash.service.modules.NetworkObserveModule
+import com.follow.clash.service.modules.NotificationModule
+import com.follow.clash.service.modules.SuspendModule
+import com.follow.clash.service.modules.moduleLoader
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+
+class CommonService : Service(), IBaseService,
+ CoroutineScope by CoroutineScope(Dispatchers.Default) {
+
+ private val self: CommonService
+ get() = this
+
+ private val loader = moduleLoader {
+ install(NetworkObserveModule(self))
+ install(NotificationModule(self))
+ install(SuspendModule(self))
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ handleCreate()
+ }
+
+ override fun onLowMemory() {
+ Core.forceGC()
+ super.onLowMemory()
+ }
+
+ private val binder = LocalBinder()
+
+ inner class LocalBinder : Binder() {
+ fun getService(): CommonService = this@CommonService
+ }
+
+ override fun onBind(intent: Intent): IBinder {
+ return binder
+ }
+
+ override fun start() {
+ loader.load()
+ }
+
+ override fun stop() {
+ loader.cancel()
+ stopSelf()
+ }
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/IBaseService.kt b/android/service/src/main/java/com/follow/clash/service/IBaseService.kt
new file mode 100644
index 0000000..738d661
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/IBaseService.kt
@@ -0,0 +1,18 @@
+package com.follow.clash.service
+
+import com.follow.clash.common.BroadcastAction
+import com.follow.clash.common.sendBroadcast
+
+interface IBaseService {
+ fun handleCreate() {
+ if (!State.inApp) {
+ BroadcastAction.START.sendBroadcast()
+ } else {
+ State.inApp = false
+ }
+ }
+
+ fun start()
+
+ fun stop()
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/RemoteService.kt b/android/service/src/main/java/com/follow/clash/service/RemoteService.kt
new file mode 100644
index 0000000..b9606a2
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/RemoteService.kt
@@ -0,0 +1,91 @@
+package com.follow.clash.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import com.follow.clash.common.ServiceDelegate
+import com.follow.clash.common.intent
+import com.follow.clash.core.Core
+import com.follow.clash.service.models.NotificationParams
+import com.follow.clash.service.models.VpnOptions
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+
+class RemoteService : Service(),
+ CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
+ private var delegate: ServiceDelegate? = null
+ private var intent: Intent? = null
+
+ private fun handleStopService() {
+ launch {
+ delegate?.useService { service ->
+ service.stop()
+ }
+ delegate?.unbind()
+ }
+ }
+
+ fun onServiceDisconnected() {
+ handleStopService()
+ }
+
+ private fun handleStartService() {
+ launch {
+ val nextIntent = when (State.options?.enable == true) {
+ true -> VpnService::class.intent
+ false -> CommonService::class.intent
+ }
+ if (intent != nextIntent) {
+ delegate?.unbind()
+ delegate = ServiceDelegate(nextIntent, ::onServiceDisconnected) { binder ->
+ when (binder) {
+ is VpnService.LocalBinder -> binder.getService()
+ is CommonService.LocalBinder -> binder.getService()
+ else -> throw IllegalArgumentException("Invalid binder type")
+ }
+ }
+ intent = nextIntent
+ delegate?.bind()
+ }
+ delegate?.useService { service ->
+ service.start()
+ }
+ }
+ }
+
+ private val binder: IRemoteInterface.Stub = object : IRemoteInterface.Stub() {
+ override fun invokeAction(data: String, callback: ICallbackInterface) {
+ Core.invokeAction(data, callback::onResult)
+ }
+
+ override fun updateNotificationParams(params: NotificationParams?) {
+ State.notificationParamsFlow.tryEmit(params)
+ }
+
+ override fun startService(
+ options: VpnOptions, inApp: Boolean
+ ) {
+ State.options = options
+ State.inApp = inApp
+ handleStartService()
+ }
+
+ override fun stopService() {
+ handleStopService()
+ }
+
+ override fun setMessageCallback(messageCallback: ICallbackInterface) {
+ setMessageCallback(messageCallback::onResult)
+ }
+ }
+
+ private fun setMessageCallback(cb: (result: String?) -> Unit) {
+ Core.setMessageCallback(cb)
+ }
+
+ override fun onBind(intent: Intent?): IBinder {
+ return binder
+ }
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/State.kt b/android/service/src/main/java/com/follow/clash/service/State.kt
new file mode 100644
index 0000000..3857508
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/State.kt
@@ -0,0 +1,13 @@
+package com.follow.clash.service
+
+import com.follow.clash.service.models.NotificationParams
+import com.follow.clash.service.models.VpnOptions
+import kotlinx.coroutines.flow.MutableStateFlow
+
+object State {
+ var options: VpnOptions? = null
+ var inApp: Boolean = false
+ var notificationParamsFlow: MutableStateFlow = MutableStateFlow(
+ NotificationParams()
+ )
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/VpnService.kt b/android/service/src/main/java/com/follow/clash/service/VpnService.kt
new file mode 100644
index 0000000..01db8da
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/VpnService.kt
@@ -0,0 +1,251 @@
+package com.follow.clash.service
+
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.net.ProxyInfo
+import android.os.Binder
+import android.os.Build
+import android.os.IBinder
+import android.os.Parcel
+import android.os.RemoteException
+import android.util.Log
+import androidx.core.content.getSystemService
+import com.follow.clash.common.AccessControlMode
+import com.follow.clash.common.BroadcastAction
+import com.follow.clash.common.GlobalState
+import com.follow.clash.common.sendBroadcast
+import com.follow.clash.core.Core
+import com.follow.clash.service.models.VpnOptions
+import com.follow.clash.service.models.getIpv4RouteAddress
+import com.follow.clash.service.models.getIpv6RouteAddress
+import com.follow.clash.service.models.toCIDR
+import com.follow.clash.service.modules.NetworkObserveModule
+import com.follow.clash.service.modules.NotificationModule
+import com.follow.clash.service.modules.SuspendModule
+import com.follow.clash.service.modules.moduleLoader
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import java.net.InetSocketAddress
+import android.net.VpnService as SystemVpnService
+
+class VpnService : SystemVpnService(), IBaseService,
+ CoroutineScope by CoroutineScope(Dispatchers.Default) {
+
+ private val self: VpnService
+ get() = this
+
+ private val loader = moduleLoader {
+ install(NetworkObserveModule(self))
+ install(NotificationModule(self))
+ install(SuspendModule(self))
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ handleCreate()
+ }
+
+ private val connectivity by lazy {
+ getSystemService()
+ }
+ private val uidPageNameMap = mutableMapOf()
+
+ private fun resolverProcess(
+ protocol: Int,
+ source: InetSocketAddress,
+ target: InetSocketAddress,
+ uid: Int,
+ ): String {
+ val nextUid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ connectivity?.getConnectionOwnerUid(protocol, source, target) ?: -1
+ } else {
+ uid
+ }
+ if (nextUid == -1) {
+ return ""
+ }
+ if (!uidPageNameMap.containsKey(nextUid)) {
+ uidPageNameMap[nextUid] = this.packageManager?.getPackagesForUid(nextUid)?.first() ?: ""
+ }
+ return uidPageNameMap[nextUid] ?: ""
+ }
+
+ val VpnOptions.address
+ get(): String = buildString {
+ append(IPV4_ADDRESS)
+ if (ipv6) {
+ append(",")
+ append(IPV6_ADDRESS)
+ }
+ }
+
+ val VpnOptions.dns
+ get(): String {
+ if (dnsHijacking) {
+ return NET_ANY
+ }
+ return buildString {
+ append(DNS)
+ if (ipv6) {
+ append(",")
+ append(DNS6)
+ }
+ }
+ }
+
+
+ override fun onLowMemory() {
+ Core.forceGC()
+ super.onLowMemory()
+ }
+
+ private val binder = LocalBinder()
+
+ inner class LocalBinder : Binder() {
+ fun getService(): VpnService = this@VpnService
+
+ override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
+ try {
+ val isSuccess = super.onTransact(code, data, reply, flags)
+ if (!isSuccess) {
+ GlobalState.log("onTransact error ===>")
+ BroadcastAction.STOP.sendBroadcast()
+ }
+ return isSuccess
+ } catch (e: RemoteException) {
+ throw e
+ }
+ }
+ }
+
+ override fun onBind(intent: Intent): IBinder {
+ return binder
+ }
+
+ private fun handleStart(options: VpnOptions) {
+ val fd = with(Builder()) {
+ val cidr = IPV4_ADDRESS.toCIDR()
+ addAddress(cidr.address, cidr.prefixLength)
+ Log.d(
+ "addAddress", "address: ${cidr.address} prefixLength:${cidr.prefixLength}"
+ )
+ val routeAddress = options.getIpv4RouteAddress()
+ if (routeAddress.isNotEmpty()) {
+ try {
+ routeAddress.forEach { i ->
+ Log.d(
+ "addRoute4", "address: ${i.address} prefixLength:${i.prefixLength}"
+ )
+ addRoute(i.address, i.prefixLength)
+ }
+ } catch (_: Exception) {
+ addRoute(NET_ANY, 0)
+ }
+ } else {
+ addRoute(NET_ANY, 0)
+ }
+ if (options.ipv6) {
+ try {
+ val cidr = IPV6_ADDRESS.toCIDR()
+ Log.d(
+ "addAddress6", "address: ${cidr.address} prefixLength:${cidr.prefixLength}"
+ )
+ addAddress(cidr.address, cidr.prefixLength)
+ } catch (_: Exception) {
+ Log.d(
+ "addAddress6", "IPv6 is not supported."
+ )
+ }
+
+ try {
+ val routeAddress = options.getIpv6RouteAddress()
+ if (routeAddress.isNotEmpty()) {
+ try {
+ routeAddress.forEach { i ->
+ Log.d(
+ "addRoute6",
+ "address: ${i.address} prefixLength:${i.prefixLength}"
+ )
+ addRoute(i.address, i.prefixLength)
+ }
+ } catch (_: Exception) {
+ addRoute("::", 0)
+ }
+ } else {
+ addRoute(NET_ANY6, 0)
+ }
+ } catch (_: Exception) {
+ addRoute(NET_ANY6, 0)
+ }
+ }
+ addDnsServer(DNS)
+ if (options.ipv6) {
+ addDnsServer(DNS6)
+ }
+ setMtu(9000)
+ options.accessControl.let { accessControl ->
+ if (accessControl.enable) {
+ when (accessControl.mode) {
+ AccessControlMode.ACCEPT_SELECTED -> {
+ (accessControl.acceptList + packageName).forEach {
+ addAllowedApplication(it)
+ }
+ }
+
+ AccessControlMode.REJECT_SELECTED -> {
+ (accessControl.rejectList - packageName).forEach {
+ addDisallowedApplication(it)
+ }
+ }
+ }
+ }
+ }
+ setSession("FlClash")
+ setBlocking(false)
+ if (Build.VERSION.SDK_INT >= 29) {
+ setMetered(false)
+ }
+ if (options.allowBypass) {
+ allowBypass()
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && options.systemProxy) {
+ setHttpProxy(
+ ProxyInfo.buildDirectProxy(
+ "127.0.0.1", options.port, options.bypassDomain
+ )
+ )
+ }
+ establish()?.detachFd()
+ ?: throw NullPointerException("Establish VPN rejected by system")
+ }
+ Core.startTun(
+ fd,
+ protect = this::protect,
+ resolverProcess = this::resolverProcess,
+ options.address,
+ options.dns
+ )
+ }
+
+ override fun start() {
+ loader.load()
+ State.options?.let {
+ handleStart(it)
+ }
+ }
+
+ override fun stop() {
+ loader.cancel()
+ Core.stopTun()
+ stopSelf()
+ }
+
+ companion object {
+ private const val IPV4_ADDRESS = "172.19.0.1/30"
+ private const val IPV6_ADDRESS = "fdfe:dcba:9876::1/126"
+ private const val DNS = "172.19.0.2"
+ private const val DNS6 = "fdfe:dcba:9876::2"
+ private const val NET_ANY = "0.0.0.0"
+ private const val NET_ANY6 = "::"
+ }
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/models/NotificationParams.kt b/android/service/src/main/java/com/follow/clash/service/models/NotificationParams.kt
new file mode 100644
index 0000000..7196005
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/models/NotificationParams.kt
@@ -0,0 +1,11 @@
+package com.follow.clash.service.models
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class NotificationParams(
+ val title: String = "FlClash",
+ val stopText: String = "STOP",
+ val onlyStatisticsProxy: Boolean = false,
+) : Parcelable
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/models/Traffic.kt b/android/service/src/main/java/com/follow/clash/service/models/Traffic.kt
new file mode 100644
index 0000000..0025a2a
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/models/Traffic.kt
@@ -0,0 +1,19 @@
+package com.follow.clash.service.models
+
+import com.follow.clash.common.formatBytes
+import com.follow.clash.core.Core
+import com.google.gson.Gson
+
+data class Traffic(
+ val up: Long,
+ val down: Long,
+)
+
+val Traffic.speedText: String
+ get() = "${up.formatBytes}/s↑ ${down.formatBytes}/s↓"
+
+fun Core.getSpeedTrafficText(onlyStatisticsProxy: Boolean): String {
+ val res = getTraffic(onlyStatisticsProxy)
+ val traffic = Gson().fromJson(res, Traffic::class.java)
+ return traffic.speedText
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/models/VpnOptions.kt b/android/service/src/main/java/com/follow/clash/service/models/VpnOptions.kt
new file mode 100644
index 0000000..cac6f71
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/models/VpnOptions.kt
@@ -0,0 +1,82 @@
+package com.follow.clash.service.models
+
+import android.os.Parcelable
+import com.follow.clash.common.AccessControlMode
+import kotlinx.parcelize.Parcelize
+import java.net.InetAddress
+
+@Parcelize
+data class AccessControl(
+ val enable: Boolean,
+ val mode: AccessControlMode,
+ val acceptList: List,
+ val rejectList: List,
+) : Parcelable
+
+@Parcelize
+data class VpnOptions(
+ val enable: Boolean,
+ val port: Int,
+ val ipv6: Boolean,
+ val dnsHijacking: Boolean,
+ val accessControl: AccessControl,
+ val allowBypass: Boolean,
+ val systemProxy: Boolean,
+ val bypassDomain: List,
+ val routeAddress: List,
+) : Parcelable
+
+data class CIDR(val address: InetAddress, val prefixLength: Int)
+
+fun VpnOptions.getIpv4RouteAddress(): List {
+ return routeAddress.filter {
+ it.isIpv4()
+ }.map {
+ it.toCIDR()
+ }
+}
+
+fun VpnOptions.getIpv6RouteAddress(): List {
+ return routeAddress.filter {
+ it.isIpv6()
+ }.map {
+ it.toCIDR()
+ }
+}
+
+fun String.isIpv4(): Boolean {
+ val parts = split("/")
+ if (parts.size != 2) {
+ throw IllegalArgumentException("Invalid CIDR format")
+ }
+ val address = InetAddress.getByName(parts[0])
+ return address.address.size == 4
+}
+
+fun String.isIpv6(): Boolean {
+ val parts = split("/")
+ if (parts.size != 2) {
+ throw IllegalArgumentException("Invalid CIDR format")
+ }
+ val address = InetAddress.getByName(parts[0])
+ return address.address.size == 16
+}
+
+fun String.toCIDR(): CIDR {
+ val parts = split("/")
+ if (parts.size != 2) {
+ throw IllegalArgumentException("Invalid CIDR format")
+ }
+ val ipAddress = parts[0]
+ val prefixLength =
+ parts[1].toIntOrNull() ?: throw IllegalArgumentException("Invalid prefix length")
+
+ val address = InetAddress.getByName(ipAddress)
+
+ val maxPrefix = if (address.address.size == 4) 32 else 128
+ if (prefixLength < 0 || prefixLength > maxPrefix) {
+ throw IllegalArgumentException("Invalid prefix length for IP version")
+ }
+
+ return CIDR(address, prefixLength)
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/modules/Module.kt b/android/service/src/main/java/com/follow/clash/service/modules/Module.kt
new file mode 100644
index 0000000..f2fb9cd
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/modules/Module.kt
@@ -0,0 +1,19 @@
+package com.follow.clash.service.modules
+
+abstract class Module {
+
+ private var isInstall: Boolean = false
+
+ protected abstract fun onInstall()
+ protected abstract fun onUninstall()
+
+ fun install() {
+ isInstall = true
+ onInstall()
+ }
+
+ fun uninstall() {
+ onUninstall()
+ isInstall = false
+ }
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/modules/ModuleLoader.kt b/android/service/src/main/java/com/follow/clash/service/modules/ModuleLoader.kt
new file mode 100644
index 0000000..d11215c
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/modules/ModuleLoader.kt
@@ -0,0 +1,51 @@
+package com.follow.clash.service.modules
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+
+interface ModuleLoaderScope {
+ fun install(module: T): T
+}
+
+interface ModuleLoader {
+ fun load()
+
+ fun cancel()
+}
+
+private val mutex = Mutex()
+fun CoroutineScope.moduleLoader(block: suspend ModuleLoaderScope.() -> Unit): ModuleLoader {
+ val modules = mutableListOf()
+ var job: Job? = null
+
+ return object : ModuleLoader {
+ override fun load() {
+ job = launch(Dispatchers.IO) {
+ mutex.withLock {
+ val scope = object : ModuleLoaderScope {
+ override fun install(module: T): T {
+ modules.add(module)
+ module.install()
+ return module
+ }
+ }
+ scope.block()
+ }
+ }
+ }
+
+ override fun cancel() {
+ launch(Dispatchers.IO) {
+ job?.cancel()
+ mutex.withLock {
+ modules.asReversed().forEach { it.uninstall() }
+ modules.clear()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/modules/NetworkObserveModule.kt b/android/service/src/main/java/com/follow/clash/service/modules/NetworkObserveModule.kt
new file mode 100644
index 0000000..c621003
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/modules/NetworkObserveModule.kt
@@ -0,0 +1,143 @@
+package com.follow.clash.service.modules
+
+import android.app.Service
+import android.net.ConnectivityManager
+import android.net.LinkProperties
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.TRANSPORT_SATELLITE
+import android.net.NetworkCapabilities.TRANSPORT_USB
+import android.net.NetworkRequest
+import android.os.Build
+import androidx.core.content.getSystemService
+import com.follow.clash.core.Core
+import java.net.Inet4Address
+import java.net.Inet6Address
+import java.net.InetAddress
+import java.util.concurrent.ConcurrentHashMap
+
+private data class NetworkInfo(
+ @Volatile var losingMs: Long = 0, @Volatile var dnsList: List = emptyList()
+) {
+ fun isAvailable(): Boolean = losingMs < System.currentTimeMillis()
+}
+
+class NetworkObserveModule(private val service: Service) : Module() {
+
+ private val networkInfos = ConcurrentHashMap()
+ private val connectivity by lazy {
+ service.getSystemService()
+ }
+
+ private val request = NetworkRequest.Builder().apply {
+ addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)
+ }
+ addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ }.build()
+
+ private val callback = object : ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ networkInfos[network] = NetworkInfo()
+ onUpdateNetwork()
+ super.onAvailable(network)
+ }
+
+ override fun onLosing(network: Network, maxMsToLive: Int) {
+ networkInfos[network]?.losingMs = System.currentTimeMillis() + maxMsToLive
+ onUpdateNetwork()
+ setUnderlyingNetworks(network)
+ super.onLosing(network, maxMsToLive)
+ }
+
+ override fun onLost(network: Network) {
+ networkInfos.remove(network)
+ onUpdateNetwork()
+ setUnderlyingNetworks(network)
+ super.onLost(network)
+ }
+
+ override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
+ networkInfos[network]?.dnsList = linkProperties.dnsServers
+ setUnderlyingNetworks(network)
+ super.onLinkPropertiesChanged(network, linkProperties)
+ }
+ }
+
+
+ override fun onInstall() {
+ onUpdateNetwork()
+ connectivity?.registerNetworkCallback(request, callback)
+ }
+
+ private fun networkToInt(entry: Map.Entry): Int {
+ val capabilities = connectivity?.getNetworkCapabilities(entry.key)
+ return when {
+ capabilities == null -> 100
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> 90
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 0
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 1
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && capabilities.hasTransport(
+ TRANSPORT_USB
+ ) -> 2
+
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> 3
+ capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 4
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && capabilities.hasTransport(
+ TRANSPORT_SATELLITE
+ ) -> 5
+
+ else -> 20
+ } + (if (entry.value.isAvailable()) 0 else 10)
+ }
+
+ fun onUpdateNetwork() {
+ val dnsList = (networkInfos.asSequence().minByOrNull { networkToInt(it) }?.value?.dnsList
+ ?: emptyList()).map { x -> x.asSocketAddressText(53) }
+ Core.updateDNS(dnsList.joinToString { "," })
+ }
+
+ fun setUnderlyingNetworks(network: Network) {
+// if (service is VpnService && Build.VERSION.SDK_INT in 22..28) {
+// service.setUnderlyingNetworks(arrayOf(network))
+// }
+ }
+
+ override fun onUninstall() {
+ connectivity?.unregisterNetworkCallback(callback)
+ networkInfos.clear()
+ onUpdateNetwork()
+ }
+}
+
+fun InetAddress.asSocketAddressText(port: Int): String {
+ return when (this) {
+ is Inet6Address -> "[${numericToTextFormat(this)}]:$port"
+
+ is Inet4Address -> "${this.hostAddress}:$port"
+
+ else -> throw IllegalArgumentException("Unsupported Inet type ${this.javaClass}")
+ }
+}
+
+private fun numericToTextFormat(address: Inet6Address): String {
+ val src = address.address
+ val sb = StringBuilder(39)
+ for (i in 0 until 8) {
+ sb.append(
+ Integer.toHexString(
+ src[i shl 1].toInt() shl 8 and 0xff00 or (src[(i shl 1) + 1].toInt() and 0xff)
+ )
+ )
+ if (i < 7) {
+ sb.append(":")
+ }
+ }
+ if (address.scopeId > 0) {
+ sb.append("%")
+ sb.append(address.scopeId)
+ }
+ return sb.toString()
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/modules/NotificationModule.kt b/android/service/src/main/java/com/follow/clash/service/modules/NotificationModule.kt
new file mode 100644
index 0000000..e031d96
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/modules/NotificationModule.kt
@@ -0,0 +1,114 @@
+package com.follow.clash.service.modules
+
+import android.app.Notification.FOREGROUND_SERVICE_IMMEDIATE
+import android.app.Service
+import android.app.Service.STOP_FOREGROUND_REMOVE
+import android.content.Intent
+import android.os.Build
+import android.os.PowerManager
+import androidx.core.app.NotificationCompat
+import androidx.core.content.getSystemService
+import com.follow.clash.common.Components
+import com.follow.clash.common.GlobalState
+import com.follow.clash.common.QuickAction
+import com.follow.clash.common.quickIntent
+import com.follow.clash.common.receiveBroadcastFlow
+import com.follow.clash.common.startForeground
+import com.follow.clash.common.tickerFlow
+import com.follow.clash.common.toPendingIntent
+import com.follow.clash.core.Core
+import com.follow.clash.service.R
+import com.follow.clash.service.State
+import com.follow.clash.service.models.NotificationParams
+import com.follow.clash.service.models.getSpeedTrafficText
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.zip
+import kotlinx.coroutines.launch
+
+class NotificationModule(private val service: Service) : Module() {
+ private val scope = CoroutineScope(Dispatchers.Default)
+
+ override fun onInstall() {
+ State.notificationParamsFlow.value?.let {
+ update(it)
+ }
+ scope.launch {
+ val screenFlow = service.receiveBroadcastFlow {
+ addAction(Intent.ACTION_SCREEN_ON)
+ addAction(Intent.ACTION_SCREEN_OFF)
+ }.map { intent ->
+ intent.action == Intent.ACTION_SCREEN_ON
+ }.onStart {
+ emit(isScreenOn())
+ }
+
+ tickerFlow(1000, 0)
+ .combine(State.notificationParamsFlow.zip(screenFlow) { params, screenOn ->
+ params to screenOn
+ }) { _, (params, screenOn) -> params to screenOn }
+ .filter { (params, screenOn) -> params != null && screenOn }
+ .collect { (params, _) ->
+ update(params!!)
+ }
+ }
+ }
+
+ private fun isScreenOn(): Boolean {
+ val pm = service.getSystemService()
+ return when (pm != null) {
+ true -> pm.isInteractive
+ false -> true
+ }
+ }
+
+ private val notificationBuilder: NotificationCompat.Builder by lazy {
+ val intent = Intent().setComponent(Components.MAIN_ACTIVITY)
+ with(
+ NotificationCompat.Builder(
+ service, GlobalState.NOTIFICATION_CHANNEL
+ )
+ ) {
+ setSmallIcon(R.drawable.ic)
+ setContentTitle("FlClash")
+ setContentIntent(intent.toPendingIntent)
+ setCategory(NotificationCompat.CATEGORY_SERVICE)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ foregroundServiceBehavior = FOREGROUND_SERVICE_IMMEDIATE
+ }
+ setOngoing(true)
+ setShowWhen(false)
+ setOnlyAlertOnce(true)
+ }
+ }
+
+ private fun update(params: NotificationParams) {
+ val contentText = Core.getSpeedTrafficText(params.onlyStatisticsProxy)
+ service.startForeground(
+ with(notificationBuilder) {
+ setContentTitle(params.title)
+ setContentText(contentText)
+ setPriority(NotificationCompat.PRIORITY_HIGH)
+ clearActions()
+ addAction(
+ 0,
+ params.stopText,
+ QuickAction.STOP.quickIntent.toPendingIntent
+ ).build()
+ })
+ }
+
+ override fun onUninstall() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ service.stopForeground(STOP_FOREGROUND_REMOVE)
+ } else {
+ service.stopForeground(true)
+ }
+ scope.cancel()
+ }
+}
\ No newline at end of file
diff --git a/android/service/src/main/java/com/follow/clash/service/modules/SuspendModule.kt b/android/service/src/main/java/com/follow/clash/service/modules/SuspendModule.kt
new file mode 100644
index 0000000..5fd8d59
--- /dev/null
+++ b/android/service/src/main/java/com/follow/clash/service/modules/SuspendModule.kt
@@ -0,0 +1,61 @@
+package com.follow.clash.service.modules
+
+import android.app.Service
+import android.content.Intent
+import android.os.PowerManager
+import androidx.core.content.getSystemService
+import com.follow.clash.common.receiveBroadcastFlow
+import com.follow.clash.core.Core
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+
+
+class SuspendModule(private val service: Service) : Module() {
+ private val scope = CoroutineScope(Dispatchers.Default)
+
+ private fun isScreenOn(): Boolean {
+ val pm = service.getSystemService()
+ return when (pm != null) {
+ true -> pm.isInteractive
+ false -> true
+ }
+ }
+
+ val isDeviceIdleMode: Boolean
+ get() {
+ return service.getSystemService()?.isDeviceIdleMode ?: true
+ }
+
+ private fun onUpdate(isScreenOn: Boolean) {
+ if (isScreenOn) {
+ Core.suspended(false)
+ return
+ }
+ Core.suspended(isDeviceIdleMode)
+ }
+
+ override fun onInstall() {
+ scope.launch {
+ val screenFlow = service.receiveBroadcastFlow {
+ addAction(Intent.ACTION_SCREEN_ON)
+ addAction(Intent.ACTION_SCREEN_OFF)
+ }.map { intent ->
+ intent.action == Intent.ACTION_SCREEN_ON
+ }.onStart {
+ emit(isScreenOn())
+ }
+
+ screenFlow.collect {
+ onUpdate(it)
+ }
+ }
+ }
+
+ override fun onUninstall() {
+ scope.cancel()
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/ic.xml b/android/service/src/main/res/drawable/ic.xml
similarity index 100%
rename from android/app/src/main/res/drawable/ic.xml
rename to android/service/src/main/res/drawable/ic.xml
diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts
index 8daaa66..f142b85 100644
--- a/android/settings.gradle.kts
+++ b/android/settings.gradle.kts
@@ -16,14 +16,14 @@ pluginManagement {
}
}
-
-
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
- id("com.android.application") version "8.9.2" apply false
- id("org.jetbrains.kotlin.android") version "1.9.22" apply false
+ id("com.android.application") version "8.12.1" apply false
+ id("org.jetbrains.kotlin.android") version "2.2.10" apply false
}
include(":app")
include(":core")
+include(":service")
+include(":common")
diff --git a/arb/intl_en.arb b/arb/intl_en.arb
index 74a0596..e7b450d 100644
--- a/arb/intl_en.arb
+++ b/arb/intl_en.arb
@@ -421,5 +421,12 @@
"proxyChains": "Proxy chains",
"log": "Log",
"connection": "Connection",
- "request": "Request"
+ "request": "Request",
+ "connected": "Connected",
+ "disconnected": "Disconnected",
+ "connecting": "Connecting...",
+ "restartCoreTip": "Are you sure you want to restart the core?",
+ "forceRestartCoreTip": "Are you sure you want to force restart the core?",
+ "dnsHijacking": "DNS hijacking",
+ "coreStatus": "Core status"
}
\ No newline at end of file
diff --git a/arb/intl_ja.arb b/arb/intl_ja.arb
index 3b89759..62b4868 100644
--- a/arb/intl_ja.arb
+++ b/arb/intl_ja.arb
@@ -422,5 +422,12 @@
"proxyChains": "プロキシチェーン",
"log": "ログ",
"connection": "接続",
- "request": "リクエスト"
+ "request": "リクエスト",
+ "connected": "接続済み",
+ "disconnected": "切断済み",
+ "connecting": "接続中...",
+ "restartCoreTip": "コアを再起動してもよろしいですか?",
+ "forceRestartCoreTip": "コアを強制再起動してもよろしいですか?",
+ "dnsHijacking": "DNSハイジャッキング",
+ "coreStatus": "コアステータス"
}
\ No newline at end of file
diff --git a/arb/intl_ru.arb b/arb/intl_ru.arb
index d0fff2b..ded51b9 100644
--- a/arb/intl_ru.arb
+++ b/arb/intl_ru.arb
@@ -422,5 +422,12 @@
"proxyChains": "Цепочки прокси",
"log": "Журнал",
"connection": "Соединение",
- "request": "Запрос"
+ "request": "Запрос",
+ "connected": "Подключено",
+ "disconnected": "Отключено",
+ "connecting": "Подключение...",
+ "restartCoreTip": "Вы уверены, что хотите перезапустить ядро?",
+ "forceRestartCoreTip": "Вы уверены, что хотите принудительно перезапустить ядро?",
+ "dnsHijacking": "DNS-перехват",
+ "coreStatus": "Основной статус"
}
\ No newline at end of file
diff --git a/arb/intl_zh_CN.arb b/arb/intl_zh_CN.arb
index 4a4a624..2495e6c 100644
--- a/arb/intl_zh_CN.arb
+++ b/arb/intl_zh_CN.arb
@@ -422,5 +422,12 @@
"proxyChains": "代理链",
"log": "日志",
"connection": "连接",
- "request": "请求"
+ "request": "请求",
+ "connected": "已连接",
+ "disconnected": "已断开",
+ "connecting": "连接中...",
+ "restartCoreTip": "您确定要重启核心吗?",
+ "forceRestartCoreTip": "您确定要强制重启核心吗?",
+ "dnsHijacking": "DNS劫持",
+ "coreStatus": "核心状态"
}
diff --git a/core/Clash.Meta b/core/Clash.Meta
index 34ccd12..6fe704a 160000
--- a/core/Clash.Meta
+++ b/core/Clash.Meta
@@ -1 +1 @@
-Subproject commit 34ccd1202bc18f638787791b9503cd014e7f21e0
+Subproject commit 6fe704ae118878db3766dbfa42247bf5fa8cbc7e
diff --git a/core/action.go b/core/action.go
index 61ba4b6..6a44cb0 100644
--- a/core/action.go
+++ b/core/action.go
@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
+ "unsafe"
)
type Action struct {
@@ -11,11 +12,11 @@ type Action struct {
}
type ActionResult struct {
- Id string `json:"id"`
- Method Method `json:"method"`
- Data interface{} `json:"data"`
- Code int `json:"code"`
- Port int64
+ Id string `json:"id"`
+ Method Method `json:"method"`
+ Data interface{} `json:"data"`
+ Code int `json:"code"`
+ callback unsafe.Pointer
}
func (result ActionResult) Json() ([]byte, error) {
@@ -45,7 +46,7 @@ func handleAction(action *Action, result ActionResult) {
result.success(handleGetIsInit())
return
case forceGcMethod:
- handleForceGc()
+ handleForceGC()
result.success(true)
return
case shutdownMethod:
@@ -73,10 +74,12 @@ func handleAction(action *Action, result ActionResult) {
})
return
case getTrafficMethod:
- result.success(handleGetTraffic())
+ data := action.Data.(bool)
+ result.success(handleGetTraffic(data))
return
case getTotalTrafficMethod:
- result.success(handleGetTotalTraffic())
+ data := action.Data.(bool)
+ result.success(handleGetTotalTraffic(data))
return
case resetTrafficMethod:
handleResetTraffic()
@@ -175,10 +178,6 @@ func handleAction(action *Action, result ActionResult) {
result.success(value)
})
return
- case setStateMethod:
- data := action.Data.(string)
- handleSetState(data)
- result.success(true)
case crashMethod:
result.success(true)
handleCrash()
diff --git a/core/android_bride.go b/core/android_bride.go
deleted file mode 100644
index 25290bc..0000000
--- a/core/android_bride.go
+++ /dev/null
@@ -1,77 +0,0 @@
-//go:build android && cgo
-
-package main
-
-/*
-#include
-
-typedef void (*release_object_func)(void *obj);
-
-typedef void (*protect_func)(void *tun_interface, int fd);
-
-typedef const char* (*resolve_process_func)(void *tun_interface, int protocol, const char *source, const char *target, int uid);
-
-static void protect(protect_func fn, void *tun_interface, int fd) {
- if (fn) {
- fn(tun_interface, fd);
- }
-}
-
-static const char* resolve_process(resolve_process_func fn, void *tun_interface, int protocol, const char *source, const char *target, int uid) {
- if (fn) {
- return fn(tun_interface, protocol, source, target, uid);
- }
- return "";
-}
-
-static void release_object(release_object_func fn, void *obj) {
- if (fn) {
- return fn(obj);
- }
-}
-*/
-import "C"
-import (
- "unsafe"
-)
-
-var (
- globalCallbacks struct {
- releaseObjectFunc C.release_object_func
- protectFunc C.protect_func
- resolveProcessFunc C.resolve_process_func
- }
-)
-
-func Protect(callback unsafe.Pointer, fd int) {
- if globalCallbacks.protectFunc != nil {
- C.protect(globalCallbacks.protectFunc, callback, C.int(fd))
- }
-}
-
-func ResolveProcess(callback unsafe.Pointer, protocol int, source, target string, uid int) string {
- if globalCallbacks.resolveProcessFunc == nil {
- return ""
- }
- s := C.CString(source)
- defer C.free(unsafe.Pointer(s))
- t := C.CString(target)
- defer C.free(unsafe.Pointer(t))
- res := C.resolve_process(globalCallbacks.resolveProcessFunc, callback, C.int(protocol), s, t, C.int(uid))
- defer C.free(unsafe.Pointer(res))
- return C.GoString(res)
-}
-
-func releaseObject(callback unsafe.Pointer) {
- if globalCallbacks.releaseObjectFunc == nil {
- return
- }
- C.release_object(globalCallbacks.releaseObjectFunc, callback)
-}
-
-//export registerCallbacks
-func registerCallbacks(markSocketFunc C.protect_func, resolveProcessFunc C.resolve_process_func, releaseObjectFunc C.release_object_func) {
- globalCallbacks.protectFunc = markSocketFunc
- globalCallbacks.resolveProcessFunc = resolveProcessFunc
- globalCallbacks.releaseObjectFunc = releaseObjectFunc
-}
diff --git a/core/bride.c b/core/bride.c
new file mode 100644
index 0000000..359d9a2
--- /dev/null
+++ b/core/bride.c
@@ -0,0 +1,25 @@
+#include "bride.h"
+
+void (*release_object_func)(void *obj);
+
+void (*protect_func)(void *tun_interface, int fd);
+
+char* (*resolve_process_func)(void *tun_interface,int protocol, const char *source, const char *target, int uid);
+
+void (*result_func)(void *invoke_Interface, const char *data);
+
+void protect(void *tun_interface, int fd) {
+ protect_func(tun_interface, fd);
+}
+
+char* resolve_process(void *tun_interface, int protocol, const char *source, const char *target, int uid) {
+ return resolve_process_func(tun_interface, protocol, source, target, uid);
+}
+
+void release_object(void *obj) {
+ release_object_func(obj);
+}
+
+void result(void *invoke_Interface, const char *data) {
+ return result_func(invoke_Interface, data);
+}
\ No newline at end of file
diff --git a/core/bride.go b/core/bride.go
new file mode 100644
index 0000000..64636c8
--- /dev/null
+++ b/core/bride.go
@@ -0,0 +1,35 @@
+//go:build android && cgo
+
+package main
+
+//#include "bride.h"
+import "C"
+import "unsafe"
+
+func protect(callback unsafe.Pointer, fd int) {
+ C.protect(callback, C.int(fd))
+}
+
+func resolveProcess(callback unsafe.Pointer, protocol int, source, target string, uid int) string {
+ s := C.CString(source)
+ defer C.free(unsafe.Pointer(s))
+ t := C.CString(target)
+ defer C.free(unsafe.Pointer(t))
+ res := C.resolve_process(callback, C.int(protocol), s, t, C.int(uid))
+ return parseCString(res)
+}
+
+func invokeResult(callback unsafe.Pointer, data string) {
+ s := C.CString(data)
+ defer C.free(unsafe.Pointer(s))
+ C.result(callback, s)
+}
+
+func releaseObject(callback unsafe.Pointer) {
+ C.release_object(callback)
+}
+
+func parseCString(s *C.char) string {
+ //defer C.free(unsafe.Pointer(s))
+ return C.GoString(s)
+}
diff --git a/core/bride.h b/core/bride.h
new file mode 100644
index 0000000..ecea31c
--- /dev/null
+++ b/core/bride.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+
+extern void (*release_object_func)(void *obj);
+
+extern void (*protect_func)(void *tun_interface, int fd);
+
+extern char* (*resolve_process_func)(void *tun_interface, int protocol, const char *source, const char *target, int uid);
+
+extern void (*result_func)(void *invoke_Interface, const char *data);
+
+extern void protect(void *tun_interface, int fd);
+
+extern char* resolve_process(void *tun_interface, int protocol, const char *source, const char *target, int uid);
+
+extern void release_object(void *obj);
+
+extern void result(void *invoke_Interface, const char *data);
\ No newline at end of file
diff --git a/core/constant.go b/core/constant.go
index 47039cf..40f40fc 100644
--- a/core/constant.go
+++ b/core/constant.go
@@ -98,10 +98,6 @@ const (
startListenerMethod Method = "startListener"
stopListenerMethod Method = "stopListener"
updateDnsMethod Method = "updateDns"
- setStateMethod Method = "setState"
- getAndroidVpnOptionsMethod Method = "getAndroidVpnOptions"
- getRunTimeMethod Method = "getRunTime"
- getCurrentProfileNameMethod Method = "getCurrentProfileName"
crashMethod Method = "crash"
setupConfigMethod Method = "setupConfig"
getConfigMethod Method = "getConfig"
diff --git a/core/dart-bridge/include/dart_api.h b/core/dart-bridge/include/dart_api.h
deleted file mode 100644
index 99dde6f..0000000
--- a/core/dart-bridge/include/dart_api.h
+++ /dev/null
@@ -1,4185 +0,0 @@
-/*
- * Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#ifndef RUNTIME_INCLUDE_DART_API_H_
-#define RUNTIME_INCLUDE_DART_API_H_
-
-/** \mainpage Dart Embedding API Reference
- *
- * This reference describes the Dart Embedding API, which is used to embed the
- * Dart Virtual Machine within C/C++ applications.
- *
- * This reference is generated from the header include/dart_api.h.
- */
-
-/* __STDC_FORMAT_MACROS has to be defined before including to
- * enable platform independent printf format specifiers. */
-#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
-#endif
-
-#include
-#include
-#include
-
-#if defined(__Fuchsia__)
-#include
-#endif
-
-#ifdef __cplusplus
-#define DART_EXTERN_C extern "C"
-#else
-#define DART_EXTERN_C extern
-#endif
-
-#if defined(__CYGWIN__)
-#error Tool chain and platform not supported.
-#elif defined(_WIN32)
-#if defined(DART_SHARED_LIB)
-#define DART_EXPORT DART_EXTERN_C __declspec(dllexport)
-#else
-#define DART_EXPORT DART_EXTERN_C
-#endif
-#else
-#if __GNUC__ >= 4
-#if defined(DART_SHARED_LIB)
-#define DART_EXPORT \
- DART_EXTERN_C __attribute__((visibility("default"))) __attribute((used))
-#else
-#define DART_EXPORT DART_EXTERN_C
-#endif
-#else
-#error Tool chain not supported.
-#endif
-#endif
-
-#if __GNUC__
-#define DART_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-#elif _MSC_VER
-#define DART_WARN_UNUSED_RESULT _Check_return_
-#else
-#define DART_WARN_UNUSED_RESULT
-#endif
-
-/*
- * =======
- * Handles
- * =======
- */
-
-/**
- * An isolate is the unit of concurrency in Dart. Each isolate has
- * its own memory and thread of control. No state is shared between
- * isolates. Instead, isolates communicate by message passing.
- *
- * Each thread keeps track of its current isolate, which is the
- * isolate which is ready to execute on the current thread. The
- * current isolate may be NULL, in which case no isolate is ready to
- * execute. Most of the Dart apis require there to be a current
- * isolate in order to function without error. The current isolate is
- * set by any call to Dart_CreateIsolateGroup or Dart_EnterIsolate.
- */
-typedef struct _Dart_Isolate* Dart_Isolate;
-typedef struct _Dart_IsolateGroup* Dart_IsolateGroup;
-
-/**
- * An object reference managed by the Dart VM garbage collector.
- *
- * Because the garbage collector may move objects, it is unsafe to
- * refer to objects directly. Instead, we refer to objects through
- * handles, which are known to the garbage collector and updated
- * automatically when the object is moved. Handles should be passed
- * by value (except in cases like out-parameters) and should never be
- * allocated on the heap.
- *
- * Most functions in the Dart Embedding API return a handle. When a
- * function completes normally, this will be a valid handle to an
- * object in the Dart VM heap. This handle may represent the result of
- * the operation or it may be a special valid handle used merely to
- * indicate successful completion. Note that a valid handle may in
- * some cases refer to the null object.
- *
- * --- Error handles ---
- *
- * When a function encounters a problem that prevents it from
- * completing normally, it returns an error handle (See Dart_IsError).
- * An error handle has an associated error message that gives more
- * details about the problem (See Dart_GetError).
- *
- * There are four kinds of error handles that can be produced,
- * depending on what goes wrong:
- *
- * - Api error handles are produced when an api function is misused.
- * This happens when a Dart embedding api function is called with
- * invalid arguments or in an invalid context.
- *
- * - Unhandled exception error handles are produced when, during the
- * execution of Dart code, an exception is thrown but not caught.
- * Prototypically this would occur during a call to Dart_Invoke, but
- * it can occur in any function which triggers the execution of Dart
- * code (for example, Dart_ToString).
- *
- * An unhandled exception error provides access to an exception and
- * stacktrace via the functions Dart_ErrorGetException and
- * Dart_ErrorGetStackTrace.
- *
- * - Compilation error handles are produced when, during the execution
- * of Dart code, a compile-time error occurs. As above, this can
- * occur in any function which triggers the execution of Dart code.
- *
- * - Fatal error handles are produced when the system wants to shut
- * down the current isolate.
- *
- * --- Propagating errors ---
- *
- * When an error handle is returned from the top level invocation of
- * Dart code in a program, the embedder must handle the error as they
- * see fit. Often, the embedder will print the error message produced
- * by Dart_Error and exit the program.
- *
- * When an error is returned while in the body of a native function,
- * it can be propagated up the call stack by calling
- * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException.
- * Errors should be propagated unless there is a specific reason not
- * to. If an error is not propagated then it is ignored. For
- * example, if an unhandled exception error is ignored, that
- * effectively "catches" the unhandled exception. Fatal errors must
- * always be propagated.
- *
- * When an error is propagated, any current scopes created by
- * Dart_EnterScope will be exited.
- *
- * Using Dart_SetReturnValue to propagate an exception is somewhat
- * more convenient than using Dart_PropagateError, and should be
- * preferred for reasons discussed below.
- *
- * Dart_PropagateError and Dart_ThrowException do not return. Instead
- * they transfer control non-locally using a setjmp-like mechanism.
- * This can be inconvenient if you have resources that you need to
- * clean up before propagating the error.
- *
- * When relying on Dart_PropagateError, we often return error handles
- * rather than propagating them from helper functions. Consider the
- * following contrived example:
- *
- * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) {
- * 2 intptr_t* length = 0;
- * 3 result = Dart_StringLength(arg, &length);
- * 4 if (Dart_IsError(result)) {
- * 5 return result;
- * 6 }
- * 7 return Dart_NewBoolean(length > 100);
- * 8 }
- * 9
- * 10 void NativeFunction_isLongString(Dart_NativeArguments args) {
- * 11 Dart_EnterScope();
- * 12 AllocateMyResource();
- * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0);
- * 14 Dart_Handle result = isLongStringHelper(arg);
- * 15 if (Dart_IsError(result)) {
- * 16 FreeMyResource();
- * 17 Dart_PropagateError(result);
- * 18 abort(); // will not reach here
- * 19 }
- * 20 Dart_SetReturnValue(result);
- * 21 FreeMyResource();
- * 22 Dart_ExitScope();
- * 23 }
- *
- * In this example, we have a native function which calls a helper
- * function to do its work. On line 5, the helper function could call
- * Dart_PropagateError, but that would not give the native function a
- * chance to call FreeMyResource(), causing a leak. Instead, the
- * helper function returns the error handle to the caller, giving the
- * caller a chance to clean up before propagating the error handle.
- *
- * When an error is propagated by calling Dart_SetReturnValue, the
- * native function will be allowed to complete normally and then the
- * exception will be propagated only once the native call
- * returns. This can be convenient, as it allows the C code to clean
- * up normally.
- *
- * The example can be written more simply using Dart_SetReturnValue to
- * propagate the error.
- *
- * 1 Dart_Handle isLongStringHelper(Dart_Handle arg) {
- * 2 intptr_t* length = 0;
- * 3 result = Dart_StringLength(arg, &length);
- * 4 if (Dart_IsError(result)) {
- * 5 return result
- * 6 }
- * 7 return Dart_NewBoolean(length > 100);
- * 8 }
- * 9
- * 10 void NativeFunction_isLongString(Dart_NativeArguments args) {
- * 11 Dart_EnterScope();
- * 12 AllocateMyResource();
- * 13 Dart_Handle arg = Dart_GetNativeArgument(args, 0);
- * 14 Dart_SetReturnValue(isLongStringHelper(arg));
- * 15 FreeMyResource();
- * 16 Dart_ExitScope();
- * 17 }
- *
- * In this example, the call to Dart_SetReturnValue on line 14 will
- * either return the normal return value or the error (potentially
- * generated on line 3). The call to FreeMyResource on line 15 will
- * execute in either case.
- *
- * --- Local and persistent handles ---
- *
- * Local handles are allocated within the current scope (see
- * Dart_EnterScope) and go away when the current scope exits. Unless
- * otherwise indicated, callers should assume that all functions in
- * the Dart embedding api return local handles.
- *
- * Persistent handles are allocated within the current isolate. They
- * can be used to store objects across scopes. Persistent handles have
- * the lifetime of the current isolate unless they are explicitly
- * deallocated (see Dart_DeletePersistentHandle).
- * The type Dart_Handle represents a handle (both local and persistent).
- * The type Dart_PersistentHandle is a Dart_Handle and it is used to
- * document that a persistent handle is expected as a parameter to a call
- * or the return value from a call is a persistent handle.
- *
- * FinalizableHandles are persistent handles which are auto deleted when
- * the object is garbage collected. It is never safe to use these handles
- * unless you know the object is still reachable.
- *
- * WeakPersistentHandles are persistent handles which are automatically set
- * to point Dart_Null when the object is garbage collected. They are not auto
- * deleted, so it is safe to use them after the object has become unreachable.
- */
-typedef struct _Dart_Handle* Dart_Handle;
-typedef Dart_Handle Dart_PersistentHandle;
-typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle;
-typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle;
-// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the
-// version when changing this struct.
-
-typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer);
-
-/**
- * Is this an error handle?
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsError(Dart_Handle handle);
-
-/**
- * Is this an api error handle?
- *
- * Api error handles are produced when an api function is misused.
- * This happens when a Dart embedding api function is called with
- * invalid arguments or in an invalid context.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsApiError(Dart_Handle handle);
-
-/**
- * Is this an unhandled exception error handle?
- *
- * Unhandled exception error handles are produced when, during the
- * execution of Dart code, an exception is thrown but not caught.
- * This can occur in any function which triggers the execution of Dart
- * code.
- *
- * See Dart_ErrorGetException and Dart_ErrorGetStackTrace.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle handle);
-
-/**
- * Is this a compilation error handle?
- *
- * Compilation error handles are produced when, during the execution
- * of Dart code, a compile-time error occurs. This can occur in any
- * function which triggers the execution of Dart code.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsCompilationError(Dart_Handle handle);
-
-/**
- * Is this a fatal error handle?
- *
- * Fatal error handles are produced when the system wants to shut down
- * the current isolate.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsFatalError(Dart_Handle handle);
-
-/**
- * Gets the error message from an error handle.
- *
- * Requires there to be a current isolate.
- *
- * \return A C string containing an error message if the handle is
- * error. An empty C string ("") if the handle is valid. This C
- * String is scope allocated and is only valid until the next call
- * to Dart_ExitScope.
-*/
-DART_EXPORT const char* Dart_GetError(Dart_Handle handle);
-
-/**
- * Is this an error handle for an unhandled exception?
- */
-DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle);
-
-/**
- * Gets the exception Object from an unhandled exception error handle.
- */
-DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle);
-
-/**
- * Gets the stack trace Object from an unhandled exception error handle.
- */
-DART_EXPORT Dart_Handle Dart_ErrorGetStackTrace(Dart_Handle handle);
-
-/**
- * Produces an api error handle with the provided error message.
- *
- * Requires there to be a current isolate.
- *
- * \param error the error message.
- */
-DART_EXPORT Dart_Handle Dart_NewApiError(const char* error);
-DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error);
-
-/**
- * Produces a new unhandled exception error handle.
- *
- * Requires there to be a current isolate.
- *
- * \param exception An instance of a Dart object to be thrown or
- * an ApiError or CompilationError handle.
- * When an ApiError or CompilationError handle is passed in
- * a string object of the error message is created and it becomes
- * the Dart object to be thrown.
- */
-DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception);
-
-/**
- * Propagates an error.
- *
- * If the provided handle is an unhandled exception error, this
- * function will cause the unhandled exception to be rethrown. This
- * will proceed in the standard way, walking up Dart frames until an
- * appropriate 'catch' block is found, executing 'finally' blocks,
- * etc.
- *
- * If the error is not an unhandled exception error, we will unwind
- * the stack to the next C frame. Intervening Dart frames will be
- * discarded; specifically, 'finally' blocks will not execute. This
- * is the standard way that compilation errors (and the like) are
- * handled by the Dart runtime.
- *
- * In either case, when an error is propagated any current scopes
- * created by Dart_EnterScope will be exited.
- *
- * See the additional discussion under "Propagating Errors" at the
- * beginning of this file.
- *
- * \param handle An error handle (See Dart_IsError)
- *
- * On success, this function does not return. On failure, the
- * process is terminated.
- */
-DART_EXPORT void Dart_PropagateError(Dart_Handle handle);
-
-/**
- * Converts an object to a string.
- *
- * May generate an unhandled exception error.
- *
- * \return The converted string if no error occurs during
- * the conversion. If an error does occur, an error handle is
- * returned.
- */
-DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object);
-
-/**
- * Checks to see if two handles refer to identically equal objects.
- *
- * If both handles refer to instances, this is equivalent to using the top-level
- * function identical() from dart:core. Otherwise, returns whether the two
- * argument handles refer to the same object.
- *
- * \param obj1 An object to be compared.
- * \param obj2 An object to be compared.
- *
- * \return True if the objects are identically equal. False otherwise.
- */
-DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2);
-
-/**
- * Allocates a handle in the current scope from a persistent handle.
- */
-DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object);
-
-/**
- * Allocates a handle in the current scope from a weak persistent handle.
- *
- * This will be a handle to Dart_Null if the object has been garbage collected.
- */
-DART_EXPORT Dart_Handle
-Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object);
-
-/**
- * Allocates a persistent handle for an object.
- *
- * This handle has the lifetime of the current isolate unless it is
- * explicitly deallocated by calling Dart_DeletePersistentHandle.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object);
-
-/**
- * Assign value of local handle to a persistent handle.
- *
- * Requires there to be a current isolate.
- *
- * \param obj1 A persistent handle whose value needs to be set.
- * \param obj2 An object whose value needs to be set to the persistent handle.
- */
-DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
- Dart_Handle obj2);
-
-/**
- * Deallocates a persistent handle.
- *
- * Requires there to be a current isolate group.
- */
-DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object);
-
-/**
- * Allocates a weak persistent handle for an object.
- *
- * This handle has the lifetime of the current isolate. The handle can also be
- * explicitly deallocated by calling Dart_DeleteWeakPersistentHandle.
- *
- * If the object becomes unreachable the callback is invoked with the peer as
- * argument. The callback can be executed on any thread, will have a current
- * isolate group, but will not have a current isolate. The callback can only
- * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This
- * gives the embedder the ability to cleanup data associated with the object.
- * The handle will point to the Dart_Null object after the finalizer has been
- * run. It is illegal to call into the VM with any other Dart_* functions from
- * the callback. If the handle is deleted before the object becomes
- * unreachable, the callback is never invoked.
- *
- * Requires there to be a current isolate.
- *
- * \param object An object with identity.
- * \param peer A pointer to a native object or NULL. This value is
- * provided to callback when it is invoked.
- * \param external_allocation_size The number of externally allocated
- * bytes for peer. Used to inform the garbage collector.
- * \param callback A function pointer that will be invoked sometime
- * after the object is garbage collected, unless the handle has been deleted.
- * A valid callback needs to be specified it cannot be NULL.
- *
- * \return The weak persistent handle or NULL. NULL is returned in case of bad
- * parameters.
- */
-DART_EXPORT Dart_WeakPersistentHandle
-Dart_NewWeakPersistentHandle(Dart_Handle object,
- void* peer,
- intptr_t external_allocation_size,
- Dart_HandleFinalizer callback);
-
-/**
- * Deletes the given weak persistent [object] handle.
- *
- * Requires there to be a current isolate group.
- */
-DART_EXPORT void Dart_DeleteWeakPersistentHandle(
- Dart_WeakPersistentHandle object);
-
-/**
- * Updates the external memory size for the given weak persistent handle.
- *
- * May trigger garbage collection.
- */
-DART_EXPORT void Dart_UpdateExternalSize(Dart_WeakPersistentHandle object,
- intptr_t external_allocation_size);
-
-/**
- * Allocates a finalizable handle for an object.
- *
- * This handle has the lifetime of the current isolate group unless the object
- * pointed to by the handle is garbage collected, in this case the VM
- * automatically deletes the handle after invoking the callback associated
- * with the handle. The handle can also be explicitly deallocated by
- * calling Dart_DeleteFinalizableHandle.
- *
- * If the object becomes unreachable the callback is invoked with the
- * the peer as argument. The callback can be executed on any thread, will have
- * an isolate group, but will not have a current isolate. The callback can only
- * call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle.
- * This gives the embedder the ability to cleanup data associated with the
- * object and clear out any cached references to the handle. All references to
- * this handle after the callback will be invalid. It is illegal to call into
- * the VM with any other Dart_* functions from the callback. If the handle is
- * deleted before the object becomes unreachable, the callback is never
- * invoked.
- *
- * Requires there to be a current isolate.
- *
- * \param object An object with identity.
- * \param peer A pointer to a native object or NULL. This value is
- * provided to callback when it is invoked.
- * \param external_allocation_size The number of externally allocated
- * bytes for peer. Used to inform the garbage collector.
- * \param callback A function pointer that will be invoked sometime
- * after the object is garbage collected, unless the handle has been deleted.
- * A valid callback needs to be specified it cannot be NULL.
- *
- * \return The finalizable handle or NULL. NULL is returned in case of bad
- * parameters.
- */
-DART_EXPORT Dart_FinalizableHandle
-Dart_NewFinalizableHandle(Dart_Handle object,
- void* peer,
- intptr_t external_allocation_size,
- Dart_HandleFinalizer callback);
-
-/**
- * Deletes the given finalizable [object] handle.
- *
- * The caller has to provide the actual Dart object the handle was created from
- * to prove the object (and therefore the finalizable handle) is still alive.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_DeleteFinalizableHandle(Dart_FinalizableHandle object,
- Dart_Handle strong_ref_to_object);
-
-/**
- * Updates the external memory size for the given finalizable handle.
- *
- * The caller has to provide the actual Dart object the handle was created from
- * to prove the object (and therefore the finalizable handle) is still alive.
- *
- * May trigger garbage collection.
- */
-DART_EXPORT void Dart_UpdateFinalizableExternalSize(
- Dart_FinalizableHandle object,
- Dart_Handle strong_ref_to_object,
- intptr_t external_allocation_size);
-
-/*
- * ==========================
- * Initialization and Globals
- * ==========================
- */
-
-/**
- * Gets the version string for the Dart VM.
- *
- * The version of the Dart VM can be accessed without initializing the VM.
- *
- * \return The version string for the embedded Dart VM.
- */
-DART_EXPORT const char* Dart_VersionString(void);
-
-/**
- * Isolate specific flags are set when creating a new isolate using the
- * Dart_IsolateFlags structure.
- *
- * Current version of flags is encoded in a 32-bit integer with 16 bits used
- * for each part.
- */
-
-#define DART_FLAGS_CURRENT_VERSION (0x0000000c)
-
-typedef struct {
- int32_t version;
- bool enable_asserts;
- bool use_field_guards;
- bool use_osr;
- bool obfuscate;
- bool load_vmservice_library;
- bool copy_parent_code;
- bool null_safety;
- bool is_system_isolate;
- bool snapshot_is_dontneed_safe;
- bool branch_coverage;
-} Dart_IsolateFlags;
-
-/**
- * Initialize Dart_IsolateFlags with correct version and default values.
- */
-DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags);
-
-/**
- * An isolate creation and initialization callback function.
- *
- * This callback, provided by the embedder, is called when the VM
- * needs to create an isolate. The callback should create an isolate
- * by calling Dart_CreateIsolateGroup and load any scripts required for
- * execution.
- *
- * This callback may be called on a different thread than the one
- * running the parent isolate.
- *
- * When the function returns NULL, it is the responsibility of this
- * function to ensure that Dart_ShutdownIsolate has been called if
- * required (for example, if the isolate was created successfully by
- * Dart_CreateIsolateGroup() but the root library fails to load
- * successfully, then the function should call Dart_ShutdownIsolate
- * before returning).
- *
- * When the function returns NULL, the function should set *error to
- * a malloc-allocated buffer containing a useful error message. The
- * caller of this function (the VM) will make sure that the buffer is
- * freed.
- *
- * \param script_uri The uri of the main source file or snapshot to load.
- * Either the URI of the parent isolate set in Dart_CreateIsolateGroup for
- * Isolate.spawn, or the argument to Isolate.spawnUri canonicalized by the
- * library tag handler of the parent isolate.
- * The callback is responsible for loading the program by a call to
- * Dart_LoadScriptFromKernel.
- * \param main The name of the main entry point this isolate will
- * eventually run. This is provided for advisory purposes only to
- * improve debugging messages. The main function is not invoked by
- * this function.
- * \param package_root Ignored.
- * \param package_config Uri of the package configuration file (either in format
- * of .packages or .dart_tool/package_config.json) for this isolate
- * to resolve package imports against. If this parameter is not passed the
- * package resolution of the parent isolate should be used.
- * \param flags Default flags for this isolate being spawned. Either inherited
- * from the spawning isolate or passed as parameters when spawning the
- * isolate from Dart code.
- * \param isolate_data The isolate data which was passed to the
- * parent isolate when it was created by calling Dart_CreateIsolateGroup().
- * \param error A structure into which the embedder can place a
- * C string containing an error message in the case of failures.
- *
- * \return The embedder returns NULL if the creation and
- * initialization was not successful and the isolate if successful.
- */
-typedef Dart_Isolate (*Dart_IsolateGroupCreateCallback)(
- const char* script_uri,
- const char* main,
- const char* package_root,
- const char* package_config,
- Dart_IsolateFlags* flags,
- void* isolate_data,
- char** error);
-
-/**
- * An isolate initialization callback function.
- *
- * This callback, provided by the embedder, is called when the VM has created an
- * isolate within an existing isolate group (i.e. from the same source as an
- * existing isolate).
- *
- * The callback should setup native resolvers and might want to set a custom
- * message handler via [Dart_SetMessageNotifyCallback] and mark the isolate as
- * runnable.
- *
- * This callback may be called on a different thread than the one
- * running the parent isolate.
- *
- * When the function returns `false`, it is the responsibility of this
- * function to ensure that `Dart_ShutdownIsolate` has been called.
- *
- * When the function returns `false`, the function should set *error to
- * a malloc-allocated buffer containing a useful error message. The
- * caller of this function (the VM) will make sure that the buffer is
- * freed.
- *
- * \param child_isolate_data The callback data to associate with the new
- * child isolate.
- * \param error A structure into which the embedder can place a
- * C string containing an error message in the case the initialization fails.
- *
- * \return The embedder returns true if the initialization was successful and
- * false otherwise (in which case the VM will terminate the isolate).
- */
-typedef bool (*Dart_InitializeIsolateCallback)(void** child_isolate_data,
- char** error);
-
-/**
- * An isolate shutdown callback function.
- *
- * This callback, provided by the embedder, is called before the vm
- * shuts down an isolate. The isolate being shutdown will be the current
- * isolate. It is safe to run Dart code.
- *
- * This function should be used to dispose of native resources that
- * are allocated to an isolate in order to avoid leaks.
- *
- * \param isolate_group_data The same callback data which was passed to the
- * isolate group when it was created.
- * \param isolate_data The same callback data which was passed to the isolate
- * when it was created.
- */
-typedef void (*Dart_IsolateShutdownCallback)(void* isolate_group_data,
- void* isolate_data);
-
-/**
- * An isolate cleanup callback function.
- *
- * This callback, provided by the embedder, is called after the vm
- * shuts down an isolate. There will be no current isolate and it is *not*
- * safe to run Dart code.
- *
- * This function should be used to dispose of native resources that
- * are allocated to an isolate in order to avoid leaks.
- *
- * \param isolate_group_data The same callback data which was passed to the
- * isolate group when it was created.
- * \param isolate_data The same callback data which was passed to the isolate
- * when it was created.
- */
-typedef void (*Dart_IsolateCleanupCallback)(void* isolate_group_data,
- void* isolate_data);
-
-/**
- * An isolate group cleanup callback function.
- *
- * This callback, provided by the embedder, is called after the vm
- * shuts down an isolate group.
- *
- * This function should be used to dispose of native resources that
- * are allocated to an isolate in order to avoid leaks.
- *
- * \param isolate_group_data The same callback data which was passed to the
- * isolate group when it was created.
- *
- */
-typedef void (*Dart_IsolateGroupCleanupCallback)(void* isolate_group_data);
-
-/**
- * A thread start callback function.
- * This callback, provided by the embedder, is called after a thread in the
- * vm thread pool starts.
- * This function could be used to adjust thread priority or attach native
- * resources to the thread.
- */
-typedef void (*Dart_ThreadStartCallback)(void);
-
-/**
- * A thread death callback function.
- * This callback, provided by the embedder, is called before a thread in the
- * vm thread pool exits.
- * This function could be used to dispose of native resources that
- * are associated and attached to the thread, in order to avoid leaks.
- */
-typedef void (*Dart_ThreadExitCallback)(void);
-
-/**
- * Opens a file for reading or writing.
- *
- * Callback provided by the embedder for file operations. If the
- * embedder does not allow file operations this callback can be
- * NULL.
- *
- * \param name The name of the file to open.
- * \param write A boolean variable which indicates if the file is to
- * opened for writing. If there is an existing file it needs to truncated.
- */
-typedef void* (*Dart_FileOpenCallback)(const char* name, bool write);
-
-/**
- * Read contents of file.
- *
- * Callback provided by the embedder for file operations. If the
- * embedder does not allow file operations this callback can be
- * NULL.
- *
- * \param data Buffer allocated in the callback into which the contents
- * of the file are read into. It is the responsibility of the caller to
- * free this buffer.
- * \param file_length A variable into which the length of the file is returned.
- * In the case of an error this value would be -1.
- * \param stream Handle to the opened file.
- */
-typedef void (*Dart_FileReadCallback)(uint8_t** data,
- intptr_t* file_length,
- void* stream);
-
-/**
- * Write data into file.
- *
- * Callback provided by the embedder for file operations. If the
- * embedder does not allow file operations this callback can be
- * NULL.
- *
- * \param data Buffer which needs to be written into the file.
- * \param length Length of the buffer.
- * \param stream Handle to the opened file.
- */
-typedef void (*Dart_FileWriteCallback)(const void* data,
- intptr_t length,
- void* stream);
-
-/**
- * Closes the opened file.
- *
- * Callback provided by the embedder for file operations. If the
- * embedder does not allow file operations this callback can be
- * NULL.
- *
- * \param stream Handle to the opened file.
- */
-typedef void (*Dart_FileCloseCallback)(void* stream);
-
-typedef bool (*Dart_EntropySource)(uint8_t* buffer, intptr_t length);
-
-/**
- * Callback provided by the embedder that is used by the vmservice isolate
- * to request the asset archive. The asset archive must be an uncompressed tar
- * archive that is stored in a Uint8List.
- *
- * If the embedder has no vmservice isolate assets, the callback can be NULL.
- *
- * \return The embedder must return a handle to a Uint8List containing an
- * uncompressed tar archive or null.
- */
-typedef Dart_Handle (*Dart_GetVMServiceAssetsArchive)(void);
-
-/**
- * The current version of the Dart_InitializeFlags. Should be incremented every
- * time Dart_InitializeFlags changes in a binary incompatible way.
- */
-#define DART_INITIALIZE_PARAMS_CURRENT_VERSION (0x00000008)
-
-/** Forward declaration */
-struct Dart_CodeObserver;
-
-/**
- * Callback provided by the embedder that is used by the VM to notify on code
- * object creation, *before* it is invoked the first time.
- * This is useful for embedders wanting to e.g. keep track of PCs beyond
- * the lifetime of the garbage collected code objects.
- * Note that an address range may be used by more than one code object over the
- * lifecycle of a process. Clients of this function should record timestamps for
- * these compilation events and when collecting PCs to disambiguate reused
- * address ranges.
- */
-typedef void (*Dart_OnNewCodeCallback)(struct Dart_CodeObserver* observer,
- const char* name,
- uintptr_t base,
- uintptr_t size);
-
-typedef struct Dart_CodeObserver {
- void* data;
-
- Dart_OnNewCodeCallback on_new_code;
-} Dart_CodeObserver;
-
-/**
- * Optional callback provided by the embedder that is used by the VM to
- * implement registration of kernel blobs for the subsequent Isolate.spawnUri
- * If no callback is provided, the registration of kernel blobs will throw
- * an error.
- *
- * \param kernel_buffer A buffer which contains a kernel program. Callback
- * should copy the contents of `kernel_buffer` as
- * it may be freed immediately after registration.
- * \param kernel_buffer_size The size of `kernel_buffer`.
- *
- * \return A C string representing URI which can be later used
- * to spawn a new isolate. This C String should be scope allocated
- * or owned by the embedder.
- * Returns NULL if embedder runs out of memory.
- */
-typedef const char* (*Dart_RegisterKernelBlobCallback)(
- const uint8_t* kernel_buffer,
- intptr_t kernel_buffer_size);
-
-/**
- * Optional callback provided by the embedder that is used by the VM to
- * unregister kernel blobs.
- * If no callback is provided, the unregistration of kernel blobs will throw
- * an error.
- *
- * \param kernel_blob_uri URI of the kernel blob to unregister.
- */
-typedef void (*Dart_UnregisterKernelBlobCallback)(const char* kernel_blob_uri);
-
-/**
- * Describes how to initialize the VM. Used with Dart_Initialize.
- */
-typedef struct {
- /**
- * Identifies the version of the struct used by the client.
- * should be initialized to DART_INITIALIZE_PARAMS_CURRENT_VERSION.
- */
- int32_t version;
-
- /**
- * A buffer containing snapshot data, or NULL if no snapshot is provided.
- *
- * If provided, the buffer must remain valid until Dart_Cleanup returns.
- */
- const uint8_t* vm_snapshot_data;
-
- /**
- * A buffer containing a snapshot of precompiled instructions, or NULL if
- * no snapshot is provided.
- *
- * If provided, the buffer must remain valid until Dart_Cleanup returns.
- */
- const uint8_t* vm_snapshot_instructions;
-
- /**
- * A function to be called during isolate group creation.
- * See Dart_IsolateGroupCreateCallback.
- */
- Dart_IsolateGroupCreateCallback create_group;
-
- /**
- * A function to be called during isolate
- * initialization inside an existing isolate group.
- * See Dart_InitializeIsolateCallback.
- */
- Dart_InitializeIsolateCallback initialize_isolate;
-
- /**
- * A function to be called right before an isolate is shutdown.
- * See Dart_IsolateShutdownCallback.
- */
- Dart_IsolateShutdownCallback shutdown_isolate;
-
- /**
- * A function to be called after an isolate was shutdown.
- * See Dart_IsolateCleanupCallback.
- */
- Dart_IsolateCleanupCallback cleanup_isolate;
-
- /**
- * A function to be called after an isolate group is
- * shutdown. See Dart_IsolateGroupCleanupCallback.
- */
- Dart_IsolateGroupCleanupCallback cleanup_group;
-
- Dart_ThreadStartCallback thread_start;
- Dart_ThreadExitCallback thread_exit;
- Dart_FileOpenCallback file_open;
- Dart_FileReadCallback file_read;
- Dart_FileWriteCallback file_write;
- Dart_FileCloseCallback file_close;
- Dart_EntropySource entropy_source;
-
- /**
- * A function to be called by the service isolate when it requires the
- * vmservice assets archive. See Dart_GetVMServiceAssetsArchive.
- */
- Dart_GetVMServiceAssetsArchive get_service_assets;
-
- bool start_kernel_isolate;
-
- /**
- * An external code observer callback function. The observer can be invoked
- * as early as during the Dart_Initialize() call.
- */
- Dart_CodeObserver* code_observer;
-
- /**
- * Kernel blob registration callback function. See Dart_RegisterKernelBlobCallback.
- */
- Dart_RegisterKernelBlobCallback register_kernel_blob;
-
- /**
- * Kernel blob unregistration callback function. See Dart_UnregisterKernelBlobCallback.
- */
- Dart_UnregisterKernelBlobCallback unregister_kernel_blob;
-
-#if defined(__Fuchsia__)
- /**
- * The resource needed to use zx_vmo_replace_as_executable. Can be
- * ZX_HANDLE_INVALID if the process has ambient-replace-as-executable or if
- * executable memory is not needed (e.g., this is an AOT runtime).
- */
- zx_handle_t vmex_resource;
-#endif
-} Dart_InitializeParams;
-
-/**
- * Initializes the VM.
- *
- * \param params A struct containing initialization information. The version
- * field of the struct must be DART_INITIALIZE_PARAMS_CURRENT_VERSION.
- *
- * \return NULL if initialization is successful. Returns an error message
- * otherwise. The caller is responsible for freeing the error message.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Initialize(
- Dart_InitializeParams* params);
-
-/**
- * Cleanup state in the VM before process termination.
- *
- * \return NULL if cleanup is successful. Returns an error message otherwise.
- * The caller is responsible for freeing the error message.
- *
- * NOTE: This function must not be called on a thread that was created by the VM
- * itself.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_Cleanup(void);
-
-/**
- * Sets command line flags. Should be called before Dart_Initialize.
- *
- * \param argc The length of the arguments array.
- * \param argv An array of arguments.
- *
- * \return NULL if successful. Returns an error message otherwise.
- * The caller is responsible for freeing the error message.
- *
- * NOTE: This call does not store references to the passed in c-strings.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_SetVMFlags(int argc,
- const char** argv);
-
-/**
- * Returns true if the named VM flag is of boolean type, specified, and set to
- * true.
- *
- * \param flag_name The name of the flag without leading punctuation
- * (example: "enable_asserts").
- */
-DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name);
-
-/*
- * ========
- * Isolates
- * ========
- */
-
-/**
- * Creates a new isolate. The new isolate becomes the current isolate.
- *
- * A snapshot can be used to restore the VM quickly to a saved state
- * and is useful for fast startup. If snapshot data is provided, the
- * isolate will be started using that snapshot data. Requires a core snapshot or
- * an app snapshot created by Dart_CreateSnapshot or
- * Dart_CreatePrecompiledSnapshot* from a VM with the same version.
- *
- * Requires there to be no current isolate.
- *
- * \param script_uri The main source file or snapshot this isolate will load.
- * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a
- * child isolate is created by Isolate.spawn. The embedder should use a URI
- * that allows it to load the same program into such a child isolate.
- * \param name A short name for the isolate to improve debugging messages.
- * Typically of the format 'foo.dart:main()'.
- * \param isolate_snapshot_data Buffer containing the snapshot data of the
- * isolate or NULL if no snapshot is provided. If provided, the buffer must
- * remain valid until the isolate shuts down.
- * \param isolate_snapshot_instructions Buffer containing the snapshot
- * instructions of the isolate or NULL if no snapshot is provided. If
- * provided, the buffer must remain valid until the isolate shuts down.
- * \param flags Pointer to VM specific flags or NULL for default flags.
- * \param isolate_group_data Embedder group data. This data can be obtained
- * by calling Dart_IsolateGroupData and will be passed to the
- * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and
- * Dart_IsolateGroupCleanupCallback.
- * \param isolate_data Embedder data. This data will be passed to
- * the Dart_IsolateGroupCreateCallback when new isolates are spawned from
- * this parent isolate.
- * \param error Returns NULL if creation is successful, an error message
- * otherwise. The caller is responsible for calling free() on the error
- * message.
- *
- * \return The new isolate on success, or NULL if isolate creation failed.
- */
-DART_EXPORT Dart_Isolate
-Dart_CreateIsolateGroup(const char* script_uri,
- const char* name,
- const uint8_t* isolate_snapshot_data,
- const uint8_t* isolate_snapshot_instructions,
- Dart_IsolateFlags* flags,
- void* isolate_group_data,
- void* isolate_data,
- char** error);
-/**
- * Creates a new isolate inside the isolate group of [group_member].
- *
- * Requires there to be no current isolate.
- *
- * \param group_member An isolate from the same group into which the newly created
- * isolate should be born into. Other threads may not have entered / enter this
- * member isolate.
- * \param name A short name for the isolate for debugging purposes.
- * \param shutdown_callback A callback to be called when the isolate is being
- * shutdown (may be NULL).
- * \param cleanup_callback A callback to be called when the isolate is being
- * cleaned up (may be NULL).
- * \param child_isolate_data The embedder-specific data associated with this isolate.
- * \param error Set to NULL if creation is successful, set to an error
- * message otherwise. The caller is responsible for calling free() on the
- * error message.
- *
- * \return The newly created isolate on success, or NULL if isolate creation
- * failed.
- *
- * If successful, the newly created isolate will become the current isolate.
- */
-DART_EXPORT Dart_Isolate
-Dart_CreateIsolateInGroup(Dart_Isolate group_member,
- const char* name,
- Dart_IsolateShutdownCallback shutdown_callback,
- Dart_IsolateCleanupCallback cleanup_callback,
- void* child_isolate_data,
- char** error);
-
-/* TODO(turnidge): Document behavior when there is already a current
- * isolate. */
-
-/**
- * Creates a new isolate from a Dart Kernel file. The new isolate
- * becomes the current isolate.
- *
- * Requires there to be no current isolate.
- *
- * \param script_uri The main source file or snapshot this isolate will load.
- * The VM will provide this URI to the Dart_IsolateGroupCreateCallback when a
- * child isolate is created by Isolate.spawn. The embedder should use a URI that
- * allows it to load the same program into such a child isolate.
- * \param name A short name for the isolate to improve debugging messages.
- * Typically of the format 'foo.dart:main()'.
- * \param kernel_buffer A buffer which contains a kernel/DIL program. Must
- * remain valid until isolate shutdown.
- * \param kernel_buffer_size The size of `kernel_buffer`.
- * \param flags Pointer to VM specific flags or NULL for default flags.
- * \param isolate_group_data Embedder group data. This data can be obtained
- * by calling Dart_IsolateGroupData and will be passed to the
- * Dart_IsolateShutdownCallback, Dart_IsolateCleanupCallback, and
- * Dart_IsolateGroupCleanupCallback.
- * \param isolate_data Embedder data. This data will be passed to
- * the Dart_IsolateGroupCreateCallback when new isolates are spawned from
- * this parent isolate.
- * \param error Returns NULL if creation is successful, an error message
- * otherwise. The caller is responsible for calling free() on the error
- * message.
- *
- * \return The new isolate on success, or NULL if isolate creation failed.
- */
-DART_EXPORT Dart_Isolate
-Dart_CreateIsolateGroupFromKernel(const char* script_uri,
- const char* name,
- const uint8_t* kernel_buffer,
- intptr_t kernel_buffer_size,
- Dart_IsolateFlags* flags,
- void* isolate_group_data,
- void* isolate_data,
- char** error);
-/**
- * Shuts down the current isolate. After this call, the current isolate is NULL.
- * Any current scopes created by Dart_EnterScope will be exited. Invokes the
- * shutdown callback and any callbacks of remaining weak persistent handles.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_ShutdownIsolate(void);
-/* TODO(turnidge): Document behavior when there is no current isolate. */
-
-/**
- * Returns the current isolate. Will return NULL if there is no
- * current isolate.
- */
-DART_EXPORT Dart_Isolate Dart_CurrentIsolate(void);
-
-/**
- * Returns the callback data associated with the current isolate. This
- * data was set when the isolate got created or initialized.
- */
-DART_EXPORT void* Dart_CurrentIsolateData(void);
-
-/**
- * Returns the callback data associated with the given isolate. This
- * data was set when the isolate got created or initialized.
- */
-DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate);
-
-/**
- * Returns the current isolate group. Will return NULL if there is no
- * current isolate group.
- */
-DART_EXPORT Dart_IsolateGroup Dart_CurrentIsolateGroup(void);
-
-/**
- * Returns the callback data associated with the current isolate group. This
- * data was passed to the isolate group when it was created.
- */
-DART_EXPORT void* Dart_CurrentIsolateGroupData(void);
-
-/**
- * Gets an id that uniquely identifies current isolate group.
- *
- * It is the responsibility of the caller to free the returned ID.
- */
-typedef int64_t Dart_IsolateGroupId;
-DART_EXPORT Dart_IsolateGroupId Dart_CurrentIsolateGroupId(void);
-
-/**
- * Returns the callback data associated with the specified isolate group. This
- * data was passed to the isolate when it was created.
- * The embedder is responsible for ensuring the consistency of this data
- * with respect to the lifecycle of an isolate group.
- */
-DART_EXPORT void* Dart_IsolateGroupData(Dart_Isolate isolate);
-
-/**
- * Returns the debugging name for the current isolate.
- *
- * This name is unique to each isolate and should only be used to make
- * debugging messages more comprehensible.
- */
-DART_EXPORT Dart_Handle Dart_DebugName(void);
-
-/**
- * Returns the debugging name for the current isolate.
- *
- * This name is unique to each isolate and should only be used to make
- * debugging messages more comprehensible.
- *
- * The returned string is scope allocated and is only valid until the next call
- * to Dart_ExitScope.
- */
-DART_EXPORT const char* Dart_DebugNameToCString(void);
-
-/**
- * Returns the ID for an isolate which is used to query the service protocol.
- *
- * It is the responsibility of the caller to free the returned ID.
- */
-DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate);
-
-/**
- * Enters an isolate. After calling this function,
- * the current isolate will be set to the provided isolate.
- *
- * Requires there to be no current isolate. Multiple threads may not be in
- * the same isolate at once.
- */
-DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate);
-
-/**
- * Kills the given isolate.
- *
- * This function has the same effect as dart:isolate's
- * Isolate.kill(priority:immediate).
- * It can interrupt ordinary Dart code but not native code. If the isolate is
- * in the middle of a long running native function, the isolate will not be
- * killed until control returns to Dart.
- *
- * Does not require a current isolate. It is safe to kill the current isolate if
- * there is one.
- */
-DART_EXPORT void Dart_KillIsolate(Dart_Isolate isolate);
-
-/**
- * Notifies the VM that the embedder expects to be idle until |deadline|. The VM
- * may use this time to perform garbage collection or other tasks to avoid
- * delays during execution of Dart code in the future.
- *
- * |deadline| is measured in microseconds against the system's monotonic time.
- * This clock can be accessed via Dart_TimelineGetMicros().
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_NotifyIdle(int64_t deadline);
-
-typedef void (*Dart_HeapSamplingReportCallback)(void* context,
- void* data);
-
-typedef void* (*Dart_HeapSamplingCreateCallback)(
- Dart_Isolate isolate,
- Dart_IsolateGroup isolate_group,
- const char* cls_name,
- intptr_t allocation_size);
-typedef void (*Dart_HeapSamplingDeleteCallback)(void* data);
-
-/**
- * Starts the heap sampling profiler for each thread in the VM.
- */
-DART_EXPORT void Dart_EnableHeapSampling(void);
-
-/*
- * Stops the heap sampling profiler for each thread in the VM.
- */
-DART_EXPORT void Dart_DisableHeapSampling(void);
-
-/* Registers callbacks are invoked once per sampled allocation upon object
- * allocation and garbage collection.
- *
- * |create_callback| can be used to associate additional data with the sampled
- * allocation, such as a stack trace. This data pointer will be passed to
- * |delete_callback| to allow for proper disposal when the object associated
- * with the allocation sample is collected.
- *
- * The provided callbacks must not call into the VM and should do as little
- * work as possible to avoid performance penalities during object allocation and
- * garbage collection.
- *
- * NOTE: It is a fatal error to set either callback to null once they have been
- * initialized.
- */
-DART_EXPORT void Dart_RegisterHeapSamplingCallback(
- Dart_HeapSamplingCreateCallback create_callback,
- Dart_HeapSamplingDeleteCallback delete_callback);
-
-/*
- * Reports the surviving allocation samples for all live isolate groups in the
- * VM.
- *
- * When the callback is invoked:
- * - |context| will be the context object provided when invoking
- * |Dart_ReportSurvivingAllocations|. This can be safely set to null if not
- * required.
- * - |heap_size| will be equal to the size of the allocated object associated
- * with the sample.
- * - |cls_name| will be a C String representing
- * the class name of the allocated object. This string is valid for the
- * duration of the call to Dart_ReportSurvivingAllocations and can be
- * freed by the VM at any point after the method returns.
- * - |data| will be set to the data associated with the sample by
- * |Dart_HeapSamplingCreateCallback|.
- *
- * If |force_gc| is true, a full GC will be performed before reporting the
- * allocations.
- */
-DART_EXPORT void Dart_ReportSurvivingAllocations(
- Dart_HeapSamplingReportCallback callback,
- void* context,
- bool force_gc);
-
-/*
- * Sets the average heap sampling rate based on a number of |bytes| for each
- * thread.
- *
- * In other words, approximately every |bytes| allocated will create a sample.
- * Defaults to 512 KiB.
- */
-DART_EXPORT void Dart_SetHeapSamplingPeriod(intptr_t bytes);
-
-/**
- * Notifies the VM that the embedder expects the application's working set has
- * recently shrunk significantly and is not expected to rise in the near future.
- * The VM may spend O(heap-size) time performing clean up work.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_NotifyDestroyed(void);
-
-/**
- * Notifies the VM that the system is running low on memory.
- *
- * Does not require a current isolate. Only valid after calling Dart_Initialize.
- */
-DART_EXPORT void Dart_NotifyLowMemory(void);
-
-typedef enum {
- /**
- * Balanced
- */
- Dart_PerformanceMode_Default,
- /**
- * Optimize for low latency, at the expense of throughput and memory overhead
- * by performing work in smaller batches (requiring more overhead) or by
- * delaying work (requiring more memory). An embedder should not remain in
- * this mode indefinitely.
- */
- Dart_PerformanceMode_Latency,
- /**
- * Optimize for high throughput, at the expense of latency and memory overhead
- * by performing work in larger batches with more intervening growth.
- */
- Dart_PerformanceMode_Throughput,
- /**
- * Optimize for low memory, at the expensive of throughput and latency by more
- * frequently performing work.
- */
- Dart_PerformanceMode_Memory,
-} Dart_PerformanceMode;
-
-/**
- * Set the desired performance trade-off.
- *
- * Requires a current isolate.
- *
- * Returns the previous performance mode.
- */
-DART_EXPORT Dart_PerformanceMode
-Dart_SetPerformanceMode(Dart_PerformanceMode mode);
-
-/**
- * Starts the CPU sampling profiler.
- */
-DART_EXPORT void Dart_StartProfiling(void);
-
-/**
- * Stops the CPU sampling profiler.
- *
- * Note that some profile samples might still be taken after this function
- * returns due to the asynchronous nature of the implementation on some
- * platforms.
- */
-DART_EXPORT void Dart_StopProfiling(void);
-
-/**
- * Notifies the VM that the current thread should not be profiled until a
- * matching call to Dart_ThreadEnableProfiling is made.
- *
- * NOTE: By default, if a thread has entered an isolate it will be profiled.
- * This function should be used when an embedder knows a thread is about
- * to make a blocking call and wants to avoid unnecessary interrupts by
- * the profiler.
- */
-DART_EXPORT void Dart_ThreadDisableProfiling(void);
-
-/**
- * Notifies the VM that the current thread should be profiled.
- *
- * NOTE: It is only legal to call this function *after* calling
- * Dart_ThreadDisableProfiling.
- *
- * NOTE: By default, if a thread has entered an isolate it will be profiled.
- */
-DART_EXPORT void Dart_ThreadEnableProfiling(void);
-
-/**
- * Register symbol information for the Dart VM's profiler and crash dumps.
- *
- * This consumes the output of //topaz/runtime/dart/profiler_symbols, which
- * should be treated as opaque.
- */
-DART_EXPORT void Dart_AddSymbols(const char* dso_name,
- void* buffer,
- intptr_t buffer_size);
-
-/**
- * Exits an isolate. After this call, Dart_CurrentIsolate will
- * return NULL.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_ExitIsolate(void);
-/* TODO(turnidge): We don't want users of the api to be able to exit a
- * "pure" dart isolate. Implement and document. */
-
-/**
- * Creates a full snapshot of the current isolate heap.
- *
- * A full snapshot is a compact representation of the dart vm isolate heap
- * and dart isolate heap states. These snapshots are used to initialize
- * the vm isolate on startup and fast initialization of an isolate.
- * A Snapshot of the heap is created before any dart code has executed.
- *
- * Requires there to be a current isolate. Not available in the precompiled
- * runtime (check Dart_IsPrecompiledRuntime).
- *
- * \param vm_snapshot_data_buffer Returns a pointer to a buffer containing the
- * vm snapshot. This buffer is scope allocated and is only valid
- * until the next call to Dart_ExitScope.
- * \param vm_snapshot_data_size Returns the size of vm_snapshot_data_buffer.
- * \param isolate_snapshot_data_buffer Returns a pointer to a buffer containing
- * the isolate snapshot. This buffer is scope allocated and is only valid
- * until the next call to Dart_ExitScope.
- * \param isolate_snapshot_data_size Returns the size of
- * isolate_snapshot_data_buffer.
- * \param is_core Create a snapshot containing core libraries.
- * Such snapshot should be agnostic to null safety mode.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
- intptr_t* vm_snapshot_data_size,
- uint8_t** isolate_snapshot_data_buffer,
- intptr_t* isolate_snapshot_data_size,
- bool is_core);
-
-/**
- * Returns whether the buffer contains a kernel file.
- *
- * \param buffer Pointer to a buffer that might contain a kernel binary.
- * \param buffer_size Size of the buffer.
- *
- * \return Whether the buffer contains a kernel binary (full or partial).
- */
-DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size);
-
-/**
- * Make isolate runnable.
- *
- * When isolates are spawned, this function is used to indicate that
- * the creation and initialization (including script loading) of the
- * isolate is complete and the isolate can start.
- * This function expects there to be no current isolate.
- *
- * \param isolate The isolate to be made runnable.
- *
- * \return NULL if successful. Returns an error message otherwise. The caller
- * is responsible for freeing the error message.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_IsolateMakeRunnable(
- Dart_Isolate isolate);
-
-/*
- * ==================
- * Messages and Ports
- * ==================
- */
-
-/**
- * A port is used to send or receive inter-isolate messages
- */
-typedef int64_t Dart_Port;
-
-/**
- * ILLEGAL_PORT is a port number guaranteed never to be associated with a valid
- * port.
- */
-#define ILLEGAL_PORT ((Dart_Port)0)
-
-/**
- * A message notification callback.
- *
- * This callback allows the embedder to provide a custom wakeup mechanism for
- * the delivery of inter-isolate messages. This function is called once per
- * message on an arbitrary thread. It is the responsibility of the embedder to
- * eventually call Dart_HandleMessage once per callback received with the
- * destination isolate set as the current isolate to process the message.
- */
-typedef void (*Dart_MessageNotifyCallback)(Dart_Isolate destination_isolate);
-
-/**
- * Allows embedders to provide a custom wakeup mechanism for the delivery of
- * inter-isolate messages. This setting only applies to the current isolate.
- *
- * This mechanism is optional: if not provided, the isolate will be scheduled on
- * a VM-managed thread pool. An embedder should provide this callback if it
- * wants to run an isolate on a specific thread or to interleave handling of
- * inter-isolate messages with other event sources.
- *
- * Most embedders will only call this function once, before isolate
- * execution begins. If this function is called after isolate
- * execution begins, the embedder is responsible for threading issues.
- */
-DART_EXPORT void Dart_SetMessageNotifyCallback(
- Dart_MessageNotifyCallback message_notify_callback);
-/* TODO(turnidge): Consider moving this to isolate creation so that it
- * is impossible to mess up. */
-
-/**
- * Query the current message notify callback for the isolate.
- *
- * \return The current message notify callback for the isolate.
- */
-DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback(void);
-
-/**
- * The VM's default message handler supports pausing an isolate before it
- * processes the first message and right after the it processes the isolate's
- * final message. This can be controlled for all isolates by two VM flags:
- *
- * `--pause-isolates-on-start`
- * `--pause-isolates-on-exit`
- *
- * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be
- * used to control this behaviour on a per-isolate basis.
- *
- * When an embedder is using a Dart_MessageNotifyCallback the embedder
- * needs to cooperate with the VM so that the service protocol can report
- * accurate information about isolates and so that tools such as debuggers
- * work reliably.
- *
- * The following functions can be used to implement pausing on start and exit.
- */
-
-/**
- * If the VM flag `--pause-isolates-on-start` was passed this will be true.
- *
- * \return A boolean value indicating if pause on start was requested.
- */
-DART_EXPORT bool Dart_ShouldPauseOnStart(void);
-
-/**
- * Override the VM flag `--pause-isolates-on-start` for the current isolate.
- *
- * \param should_pause Should the isolate be paused on start?
- *
- * NOTE: This must be called before Dart_IsolateMakeRunnable.
- */
-DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause);
-
-/**
- * Is the current isolate paused on start?
- *
- * \return A boolean value indicating if the isolate is paused on start.
- */
-DART_EXPORT bool Dart_IsPausedOnStart(void);
-
-/**
- * Called when the embedder has paused the current isolate on start and when
- * the embedder has resumed the isolate.
- *
- * \param paused Is the isolate paused on start?
- */
-DART_EXPORT void Dart_SetPausedOnStart(bool paused);
-
-/**
- * If the VM flag `--pause-isolates-on-exit` was passed this will be true.
- *
- * \return A boolean value indicating if pause on exit was requested.
- */
-DART_EXPORT bool Dart_ShouldPauseOnExit(void);
-
-/**
- * Override the VM flag `--pause-isolates-on-exit` for the current isolate.
- *
- * \param should_pause Should the isolate be paused on exit?
- *
- */
-DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause);
-
-/**
- * Is the current isolate paused on exit?
- *
- * \return A boolean value indicating if the isolate is paused on exit.
- */
-DART_EXPORT bool Dart_IsPausedOnExit(void);
-
-/**
- * Called when the embedder has paused the current isolate on exit and when
- * the embedder has resumed the isolate.
- *
- * \param paused Is the isolate paused on exit?
- */
-DART_EXPORT void Dart_SetPausedOnExit(bool paused);
-
-/**
- * Called when the embedder has caught a top level unhandled exception error
- * in the current isolate.
- *
- * NOTE: It is illegal to call this twice on the same isolate without first
- * clearing the sticky error to null.
- *
- * \param error The unhandled exception error.
- */
-DART_EXPORT void Dart_SetStickyError(Dart_Handle error);
-
-/**
- * Does the current isolate have a sticky error?
- */
-DART_EXPORT bool Dart_HasStickyError(void);
-
-/**
- * Gets the sticky error for the current isolate.
- *
- * \return A handle to the sticky error object or null.
- */
-DART_EXPORT Dart_Handle Dart_GetStickyError(void);
-
-/**
- * Handles the next pending message for the current isolate.
- *
- * May generate an unhandled exception error.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_HandleMessage(void);
-
-/**
- * Drains the microtask queue, then blocks the calling thread until the current
- * isolate receives a message, then handles all messages.
- *
- * \param timeout_millis When non-zero, the call returns after the indicated
- number of milliseconds even if no message was received.
- * \return A valid handle if no error occurs, otherwise an error handle.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_WaitForEvent(int64_t timeout_millis);
-
-/**
- * Handles any pending messages for the vm service for the current
- * isolate.
- *
- * This function may be used by an embedder at a breakpoint to avoid
- * pausing the vm service.
- *
- * This function can indirectly cause the message notify callback to
- * be called.
- *
- * \return true if the vm service requests the program resume
- * execution, false otherwise
- */
-DART_EXPORT bool Dart_HandleServiceMessages(void);
-
-/**
- * Does the current isolate have pending service messages?
- *
- * \return true if the isolate has pending service messages, false otherwise.
- */
-DART_EXPORT bool Dart_HasServiceMessages(void);
-
-/**
- * Processes any incoming messages for the current isolate.
- *
- * This function may only be used when the embedder has not provided
- * an alternate message delivery mechanism with
- * Dart_SetMessageCallbacks. It is provided for convenience.
- *
- * This function waits for incoming messages for the current
- * isolate. As new messages arrive, they are handled using
- * Dart_HandleMessage. The routine exits when all ports to the
- * current isolate are closed.
- *
- * \return A valid handle if the run loop exited successfully. If an
- * exception or other error occurs while processing messages, an
- * error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_RunLoop(void);
-
-/**
- * Lets the VM run message processing for the isolate.
- *
- * This function expects there to a current isolate and the current isolate
- * must not have an active api scope. The VM will take care of making the
- * isolate runnable (if not already), handles its message loop and will take
- * care of shutting the isolate down once it's done.
- *
- * \param errors_are_fatal Whether uncaught errors should be fatal.
- * \param on_error_port A port to notify on uncaught errors (or ILLEGAL_PORT).
- * \param on_exit_port A port to notify on exit (or ILLEGAL_PORT).
- * \param error A non-NULL pointer which will hold an error message if the call
- * fails. The error has to be free()ed by the caller.
- *
- * \return If successful the VM takes ownership of the isolate and takes care
- * of its message loop. If not successful the caller retains ownership of the
- * isolate.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT bool Dart_RunLoopAsync(
- bool errors_are_fatal,
- Dart_Port on_error_port,
- Dart_Port on_exit_port,
- char** error);
-
-/* TODO(turnidge): Should this be removed from the public api? */
-
-/**
- * Gets the main port id for the current isolate.
- */
-DART_EXPORT Dart_Port Dart_GetMainPortId(void);
-
-/**
- * Does the current isolate have live ReceivePorts?
- *
- * A ReceivePort is live when it has not been closed.
- */
-DART_EXPORT bool Dart_HasLivePorts(void);
-
-/**
- * Posts a message for some isolate. The message is a serialized
- * object.
- *
- * Requires there to be a current isolate.
- *
- * For posting messages outside of an isolate see \ref Dart_PostCObject.
- *
- * \param port_id The destination port.
- * \param object An object from the current isolate.
- *
- * \return True if the message was posted.
- */
-DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle object);
-
-/**
- * Returns a new SendPort with the provided port id.
- *
- * \param port_id The destination port.
- *
- * \return A new SendPort if no errors occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id);
-
-/**
- * Gets the SendPort id for the provided SendPort.
- * \param port A SendPort object whose id is desired.
- * \param port_id Returns the id of the SendPort.
- * \return Success if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
- Dart_Port* port_id);
-
-/*
- * ======
- * Scopes
- * ======
- */
-
-/**
- * Enters a new scope.
- *
- * All new local handles will be created in this scope. Additionally,
- * some functions may return "scope allocated" memory which is only
- * valid within this scope.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_EnterScope(void);
-
-/**
- * Exits a scope.
- *
- * The previous scope (if any) becomes the current scope.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT void Dart_ExitScope(void);
-
-/**
- * The Dart VM uses "zone allocation" for temporary structures. Zones
- * support very fast allocation of small chunks of memory. The chunks
- * cannot be deallocated individually, but instead zones support
- * deallocating all chunks in one fast operation.
- *
- * This function makes it possible for the embedder to allocate
- * temporary data in the VMs zone allocator.
- *
- * Zone allocation is possible:
- * 1. when inside a scope where local handles can be allocated
- * 2. when processing a message from a native port in a native port
- * handler
- *
- * All the memory allocated this way will be reclaimed either on the
- * next call to Dart_ExitScope or when the native port handler exits.
- *
- * \param size Size of the memory to allocate.
- *
- * \return A pointer to the allocated memory. NULL if allocation
- * failed. Failure might due to is no current VM zone.
- */
-DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size);
-
-/*
- * =======
- * Objects
- * =======
- */
-
-/**
- * Returns the null object.
- *
- * \return A handle to the null object.
- */
-DART_EXPORT Dart_Handle Dart_Null(void);
-
-/**
- * Is this object null?
- */
-DART_EXPORT bool Dart_IsNull(Dart_Handle object);
-
-/**
- * Returns the empty string object.
- *
- * \return A handle to the empty string object.
- */
-DART_EXPORT Dart_Handle Dart_EmptyString(void);
-
-/**
- * Returns types that are not classes, and which therefore cannot be looked up
- * as library members by Dart_GetType.
- *
- * \return A handle to the dynamic, void or Never type.
- */
-DART_EXPORT Dart_Handle Dart_TypeDynamic(void);
-DART_EXPORT Dart_Handle Dart_TypeVoid(void);
-DART_EXPORT Dart_Handle Dart_TypeNever(void);
-
-/**
- * Checks if the two objects are equal.
- *
- * The result of the comparison is returned through the 'equal'
- * parameter. The return value itself is used to indicate success or
- * failure, not equality.
- *
- * May generate an unhandled exception error.
- *
- * \param obj1 An object to be compared.
- * \param obj2 An object to be compared.
- * \param equal Returns the result of the equality comparison.
- *
- * \return A valid handle if no error occurs during the comparison.
- */
-DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1,
- Dart_Handle obj2,
- bool* equal);
-
-/**
- * Is this object an instance of some type?
- *
- * The result of the test is returned through the 'instanceof' parameter.
- * The return value itself is used to indicate success or failure.
- *
- * \param object An object.
- * \param type A type.
- * \param instanceof Return true if 'object' is an instance of type 'type'.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object,
- Dart_Handle type,
- bool* instanceof);
-
-/**
- * Query object type.
- *
- * \param object Some Object.
- *
- * \return true if Object is of the specified type.
- */
-DART_EXPORT bool Dart_IsInstance(Dart_Handle object);
-DART_EXPORT bool Dart_IsNumber(Dart_Handle object);
-DART_EXPORT bool Dart_IsInteger(Dart_Handle object);
-DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
-DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
-DART_EXPORT bool Dart_IsString(Dart_Handle object);
-DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */
-DART_EXPORT bool Dart_IsExternalString(Dart_Handle object);
-DART_EXPORT bool Dart_IsList(Dart_Handle object);
-DART_EXPORT bool Dart_IsMap(Dart_Handle object);
-DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
-DART_EXPORT bool Dart_IsType(Dart_Handle handle);
-DART_EXPORT bool Dart_IsFunction(Dart_Handle handle);
-DART_EXPORT bool Dart_IsVariable(Dart_Handle handle);
-DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle);
-DART_EXPORT bool Dart_IsClosure(Dart_Handle object);
-DART_EXPORT bool Dart_IsTypedData(Dart_Handle object);
-DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle object);
-DART_EXPORT bool Dart_IsFuture(Dart_Handle object);
-
-/*
- * =========
- * Instances
- * =========
- */
-
-/*
- * For the purposes of the embedding api, not all objects returned are
- * Dart language objects. Within the api, we use the term 'Instance'
- * to indicate handles which refer to true Dart language objects.
- *
- * TODO(turnidge): Reorganize the "Object" section above, pulling down
- * any functions that more properly belong here. */
-
-/**
- * Gets the type of a Dart language object.
- *
- * \param instance Some Dart object.
- *
- * \return If no error occurs, the type is returned. Otherwise an
- * error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance);
-
-/**
- * Returns the name for the provided class type.
- *
- * \return A valid string handle if no error occurs during the
- * operation.
- */
-DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type);
-
-/**
- * Returns the name for the provided function or method.
- *
- * \return A valid string handle if no error occurs during the
- * operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function);
-
-/**
- * Returns a handle to the owner of a function.
- *
- * The owner of an instance method or a static method is its defining
- * class. The owner of a top-level function is its defining
- * library. The owner of the function of a non-implicit closure is the
- * function of the method or closure that defines the non-implicit
- * closure.
- *
- * \return A valid handle to the owner of the function, or an error
- * handle if the argument is not a valid handle to a function.
- */
-DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function);
-
-/**
- * Determines whether a function handle refers to a static function
- * of method.
- *
- * For the purposes of the embedding API, a top-level function is
- * implicitly declared static.
- *
- * \param function A handle to a function or method declaration.
- * \param is_static Returns whether the function or method is declared static.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
- bool* is_static);
-
-/**
- * Is this object a closure resulting from a tear-off (closurized method)?
- *
- * Returns true for closures produced when an ordinary method is accessed
- * through a getter call. Returns false otherwise, in particular for closures
- * produced from local function declarations.
- *
- * \param object Some Object.
- *
- * \return true if Object is a tear-off.
- */
-DART_EXPORT bool Dart_IsTearOff(Dart_Handle object);
-
-/**
- * Retrieves the function of a closure.
- *
- * \return A handle to the function of the closure, or an error handle if the
- * argument is not a closure.
- */
-DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure);
-
-/**
- * Returns a handle to the library which contains class.
- *
- * \return A valid handle to the library with owns class, null if the class
- * has no library or an error handle if the argument is not a valid handle
- * to a class type.
- */
-DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type);
-
-/*
- * =============================
- * Numbers, Integers and Doubles
- * =============================
- */
-
-/**
- * Does this Integer fit into a 64-bit signed integer?
- *
- * \param integer An integer.
- * \param fits Returns true if the integer fits into a 64-bit signed integer.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
- bool* fits);
-
-/**
- * Does this Integer fit into a 64-bit unsigned integer?
- *
- * \param integer An integer.
- * \param fits Returns true if the integer fits into a 64-bit unsigned integer.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer,
- bool* fits);
-
-/**
- * Returns an Integer with the provided value.
- *
- * \param value The value of the integer.
- *
- * \return The Integer object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value);
-
-/**
- * Returns an Integer with the provided value.
- *
- * \param value The unsigned value of the integer.
- *
- * \return The Integer object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value);
-
-/**
- * Returns an Integer with the provided value.
- *
- * \param value The value of the integer represented as a C string
- * containing a hexadecimal number.
- *
- * \return The Integer object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value);
-
-/**
- * Gets the value of an Integer.
- *
- * The integer must fit into a 64-bit signed integer, otherwise an error occurs.
- *
- * \param integer An Integer.
- * \param value Returns the value of the Integer.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer,
- int64_t* value);
-
-/**
- * Gets the value of an Integer.
- *
- * The integer must fit into a 64-bit unsigned integer, otherwise an
- * error occurs.
- *
- * \param integer An Integer.
- * \param value Returns the value of the Integer.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer,
- uint64_t* value);
-
-/**
- * Gets the value of an integer as a hexadecimal C string.
- *
- * \param integer An Integer.
- * \param value Returns the value of the Integer as a hexadecimal C
- * string. This C string is scope allocated and is only valid until
- * the next call to Dart_ExitScope.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
- const char** value);
-
-/**
- * Returns a Double with the provided value.
- *
- * \param value A double.
- *
- * \return The Double object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewDouble(double value);
-
-/**
- * Gets the value of a Double
- *
- * \param double_obj A Double
- * \param value Returns the value of the Double.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, double* value);
-
-/**
- * Returns a closure of static function 'function_name' in the class 'class_name'
- * in the exported namespace of specified 'library'.
- *
- * \param library Library object
- * \param cls_type Type object representing a Class
- * \param function_name Name of the static function in the class
- *
- * \return A valid Dart instance if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
- Dart_Handle cls_type,
- Dart_Handle function_name);
-
-/*
- * ========
- * Booleans
- * ========
- */
-
-/**
- * Returns the True object.
- *
- * Requires there to be a current isolate.
- *
- * \return A handle to the True object.
- */
-DART_EXPORT Dart_Handle Dart_True(void);
-
-/**
- * Returns the False object.
- *
- * Requires there to be a current isolate.
- *
- * \return A handle to the False object.
- */
-DART_EXPORT Dart_Handle Dart_False(void);
-
-/**
- * Returns a Boolean with the provided value.
- *
- * \param value true or false.
- *
- * \return The Boolean object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewBoolean(bool value);
-
-/**
- * Gets the value of a Boolean
- *
- * \param boolean_obj A Boolean
- * \param value Returns the value of the Boolean.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool* value);
-
-/*
- * =======
- * Strings
- * =======
- */
-
-/**
- * Gets the length of a String.
- *
- * \param str A String.
- * \param length Returns the length of the String.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length);
-
-/**
- * Returns a String built from the provided C string
- * (There is an implicit assumption that the C string passed in contains
- * UTF-8 encoded characters and '\0' is considered as a termination
- * character).
- *
- * \param str A C String
- *
- * \return The String object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str);
-/* TODO(turnidge): Document what happens when we run out of memory
- * during this call. */
-
-/**
- * Returns a String built from an array of UTF-8 encoded characters.
- *
- * \param utf8_array An array of UTF-8 encoded characters.
- * \param length The length of the codepoints array.
- *
- * \return The String object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array,
- intptr_t length);
-
-/**
- * Returns a String built from an array of UTF-16 encoded characters.
- *
- * \param utf16_array An array of UTF-16 encoded characters.
- * \param length The length of the codepoints array.
- *
- * \return The String object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array,
- intptr_t length);
-
-/**
- * Returns a String built from an array of UTF-32 encoded characters.
- *
- * \param utf32_array An array of UTF-32 encoded characters.
- * \param length The length of the codepoints array.
- *
- * \return The String object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
- intptr_t length);
-
-/**
- * Returns a String which references an external array of
- * Latin-1 (ISO-8859-1) encoded characters.
- *
- * \param latin1_array Array of Latin-1 encoded characters. This must not move.
- * \param length The length of the characters array.
- * \param peer An external pointer to associate with this string.
- * \param external_allocation_size The number of externally allocated
- * bytes for peer. Used to inform the garbage collector.
- * \param callback A callback to be called when this string is finalized.
- *
- * \return The String object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle
-Dart_NewExternalLatin1String(const uint8_t* latin1_array,
- intptr_t length,
- void* peer,
- intptr_t external_allocation_size,
- Dart_HandleFinalizer callback);
-
-/**
- * Returns a String which references an external array of UTF-16 encoded
- * characters.
- *
- * \param utf16_array An array of UTF-16 encoded characters. This must not move.
- * \param length The length of the characters array.
- * \param peer An external pointer to associate with this string.
- * \param external_allocation_size The number of externally allocated
- * bytes for peer. Used to inform the garbage collector.
- * \param callback A callback to be called when this string is finalized.
- *
- * \return The String object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle
-Dart_NewExternalUTF16String(const uint16_t* utf16_array,
- intptr_t length,
- void* peer,
- intptr_t external_allocation_size,
- Dart_HandleFinalizer callback);
-
-/**
- * Gets the C string representation of a String.
- * (It is a sequence of UTF-8 encoded values with a '\0' termination.)
- *
- * \param str A string.
- * \param cstr Returns the String represented as a C string.
- * This C string is scope allocated and is only valid until
- * the next call to Dart_ExitScope.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle str,
- const char** cstr);
-
-/**
- * Gets a UTF-8 encoded representation of a String.
- *
- * Any unpaired surrogate code points in the string will be converted as
- * replacement characters (U+FFFD, 0xEF 0xBF 0xBD in UTF-8). If you need
- * to preserve unpaired surrogates, use the Dart_StringToUTF16 function.
- *
- * \param str A string.
- * \param utf8_array Returns the String represented as UTF-8 code
- * units. This UTF-8 array is scope allocated and is only valid
- * until the next call to Dart_ExitScope.
- * \param length Used to return the length of the array which was
- * actually used.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str,
- uint8_t** utf8_array,
- intptr_t* length);
-
-/**
- * Gets the data corresponding to the string object. This function returns
- * the data only for Latin-1 (ISO-8859-1) string objects. For all other
- * string objects it returns an error.
- *
- * \param str A string.
- * \param latin1_array An array allocated by the caller, used to return
- * the string data.
- * \param length Used to pass in the length of the provided array.
- * Used to return the length of the array which was actually used.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str,
- uint8_t* latin1_array,
- intptr_t* length);
-
-/**
- * Gets the UTF-16 encoded representation of a string.
- *
- * \param str A string.
- * \param utf16_array An array allocated by the caller, used to return
- * the array of UTF-16 encoded characters.
- * \param length Used to pass in the length of the provided array.
- * Used to return the length of the array which was actually used.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str,
- uint16_t* utf16_array,
- intptr_t* length);
-
-/**
- * Gets the storage size in bytes of a String.
- *
- * \param str A String.
- * \param size Returns the storage size in bytes of the String.
- * This is the size in bytes needed to store the String.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, intptr_t* size);
-
-/**
- * Retrieves some properties associated with a String.
- * Properties retrieved are:
- * - character size of the string (one or two byte)
- * - length of the string
- * - peer pointer of string if it is an external string.
- * \param str A String.
- * \param char_size Returns the character size of the String.
- * \param str_len Returns the length of the String.
- * \param peer Returns the peer pointer associated with the String or 0 if
- * there is no peer pointer for it.
- * \return Success if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle str,
- intptr_t* char_size,
- intptr_t* str_len,
- void** peer);
-
-/*
- * =====
- * Lists
- * =====
- */
-
-/**
- * Returns a List of the desired length.
- *
- * \param length The length of the list.
- *
- * \return The List object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewList(intptr_t length);
-
-typedef enum {
- Dart_CoreType_Dynamic,
- Dart_CoreType_Int,
- Dart_CoreType_String,
-} Dart_CoreType_Id;
-
-// TODO(bkonyi): convert this to use nullable types once NNBD is enabled.
-/**
- * Returns a List of the desired length with the desired legacy element type.
- *
- * \param element_type_id The type of elements of the list.
- * \param length The length of the list.
- *
- * \return The List object if no error occurs. Otherwise returns an error
- * handle.
- */
-DART_EXPORT Dart_Handle Dart_NewListOf(Dart_CoreType_Id element_type_id,
- intptr_t length);
-
-/**
- * Returns a List of the desired length with the desired element type.
- *
- * \param element_type Handle to a nullable type object. E.g., from
- * Dart_GetType or Dart_GetNullableType.
- *
- * \param length The length of the list.
- *
- * \return The List object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewListOfType(Dart_Handle element_type,
- intptr_t length);
-
-/**
- * Returns a List of the desired length with the desired element type, filled
- * with the provided object.
- *
- * \param element_type Handle to a type object. E.g., from Dart_GetType.
- *
- * \param fill_object Handle to an object of type 'element_type' that will be
- * used to populate the list. This parameter can only be Dart_Null() if the
- * length of the list is 0 or 'element_type' is a nullable type.
- *
- * \param length The length of the list.
- *
- * \return The List object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewListOfTypeFilled(Dart_Handle element_type,
- Dart_Handle fill_object,
- intptr_t length);
-
-/**
- * Gets the length of a List.
- *
- * May generate an unhandled exception error.
- *
- * \param list A List.
- * \param length Returns the length of the List.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* length);
-
-/**
- * Gets the Object at some index of a List.
- *
- * If the index is out of bounds, an error occurs.
- *
- * May generate an unhandled exception error.
- *
- * \param list A List.
- * \param index A valid index into the List.
- *
- * \return The Object in the List at the specified index if no error
- * occurs. Otherwise returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index);
-
-/**
-* Gets a range of Objects from a List.
-*
-* If any of the requested index values are out of bounds, an error occurs.
-*
-* May generate an unhandled exception error.
-*
-* \param list A List.
-* \param offset The offset of the first item to get.
-* \param length The number of items to get.
-* \param result A pointer to fill with the objects.
-*
-* \return Success if no error occurs during the operation.
-*/
-DART_EXPORT Dart_Handle Dart_ListGetRange(Dart_Handle list,
- intptr_t offset,
- intptr_t length,
- Dart_Handle* result);
-
-/**
- * Sets the Object at some index of a List.
- *
- * If the index is out of bounds, an error occurs.
- *
- * May generate an unhandled exception error.
- *
- * \param list A List.
- * \param index A valid index into the List.
- * \param value The Object to put in the List.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list,
- intptr_t index,
- Dart_Handle value);
-
-/**
- * May generate an unhandled exception error.
- */
-DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
- intptr_t offset,
- uint8_t* native_array,
- intptr_t length);
-
-/**
- * May generate an unhandled exception error.
- */
-DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list,
- intptr_t offset,
- const uint8_t* native_array,
- intptr_t length);
-
-/*
- * ====
- * Maps
- * ====
- */
-
-/**
- * Gets the Object at some key of a Map.
- *
- * May generate an unhandled exception error.
- *
- * \param map A Map.
- * \param key An Object.
- *
- * \return The value in the map at the specified key, null if the map does not
- * contain the key, or an error handle.
- */
-DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key);
-
-/**
- * Returns whether the Map contains a given key.
- *
- * May generate an unhandled exception error.
- *
- * \param map A Map.
- *
- * \return A handle on a boolean indicating whether map contains the key.
- * Otherwise returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key);
-
-/**
- * Gets the list of keys of a Map.
- *
- * May generate an unhandled exception error.
- *
- * \param map A Map.
- *
- * \return The list of key Objects if no error occurs. Otherwise returns an
- * error handle.
- */
-DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map);
-
-/*
- * ==========
- * Typed Data
- * ==========
- */
-
-typedef enum {
- Dart_TypedData_kByteData = 0,
- Dart_TypedData_kInt8,
- Dart_TypedData_kUint8,
- Dart_TypedData_kUint8Clamped,
- Dart_TypedData_kInt16,
- Dart_TypedData_kUint16,
- Dart_TypedData_kInt32,
- Dart_TypedData_kUint32,
- Dart_TypedData_kInt64,
- Dart_TypedData_kUint64,
- Dart_TypedData_kFloat32,
- Dart_TypedData_kFloat64,
- Dart_TypedData_kInt32x4,
- Dart_TypedData_kFloat32x4,
- Dart_TypedData_kFloat64x2,
- Dart_TypedData_kInvalid
-} Dart_TypedData_Type;
-
-/**
- * Return type if this object is a TypedData object.
- *
- * \return kInvalid if the object is not a TypedData object or the appropriate
- * Dart_TypedData_Type.
- */
-DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object);
-
-/**
- * Return type if this object is an external TypedData object.
- *
- * \return kInvalid if the object is not an external TypedData object or
- * the appropriate Dart_TypedData_Type.
- */
-DART_EXPORT Dart_TypedData_Type
-Dart_GetTypeOfExternalTypedData(Dart_Handle object);
-
-/**
- * Returns a TypedData object of the desired length and type.
- *
- * \param type The type of the TypedData object.
- * \param length The length of the TypedData object (length in type units).
- *
- * \return The TypedData object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
- intptr_t length);
-
-/**
- * Returns a TypedData object which references an external data array.
- *
- * \param type The type of the data array.
- * \param data A data array. This array must not move.
- * \param length The length of the data array (length in type units).
- *
- * \return The TypedData object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type,
- void* data,
- intptr_t length);
-
-/**
- * Returns a TypedData object which references an external data array.
- *
- * \param type The type of the data array.
- * \param data A data array. This array must not move.
- * \param length The length of the data array (length in type units).
- * \param peer A pointer to a native object or NULL. This value is
- * provided to callback when it is invoked.
- * \param external_allocation_size The number of externally allocated
- * bytes for peer. Used to inform the garbage collector.
- * \param callback A function pointer that will be invoked sometime
- * after the object is garbage collected, unless the handle has been deleted.
- * A valid callback needs to be specified it cannot be NULL.
- *
- * \return The TypedData object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle
-Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type,
- void* data,
- intptr_t length,
- void* peer,
- intptr_t external_allocation_size,
- Dart_HandleFinalizer callback);
-DART_EXPORT Dart_Handle Dart_NewUnmodifiableExternalTypedDataWithFinalizer(
- Dart_TypedData_Type type,
- const void* data,
- intptr_t length,
- void* peer,
- intptr_t external_allocation_size,
- Dart_HandleFinalizer callback);
-
-/**
- * Returns a ByteBuffer object for the typed data.
- *
- * \param typed_data The TypedData object.
- *
- * \return The ByteBuffer object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data);
-
-/**
- * Acquires access to the internal data address of a TypedData object.
- *
- * \param object The typed data object whose internal data address is to
- * be accessed.
- * \param type The type of the object is returned here.
- * \param data The internal data address is returned here.
- * \param len Size of the typed array is returned here.
- *
- * Notes:
- * When the internal address of the object is acquired any calls to a
- * Dart API function that could potentially allocate an object or run
- * any Dart code will return an error.
- *
- * Any Dart API functions for accessing the data should not be called
- * before the corresponding release. In particular, the object should
- * not be acquired again before its release. This leads to undefined
- * behavior.
- *
- * \return Success if the internal data address is acquired successfully.
- * Otherwise, returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object,
- Dart_TypedData_Type* type,
- void** data,
- intptr_t* len);
-
-/**
- * Releases access to the internal data address that was acquired earlier using
- * Dart_TypedDataAcquireData.
- *
- * \param object The typed data object whose internal data address is to be
- * released.
- *
- * \return Success if the internal data address is released successfully.
- * Otherwise, returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object);
-
-/**
- * Returns the TypedData object associated with the ByteBuffer object.
- *
- * \param byte_buffer The ByteBuffer object.
- *
- * \return The TypedData object if no error occurs. Otherwise returns
- * an error handle.
- */
-DART_EXPORT Dart_Handle Dart_GetDataFromByteBuffer(Dart_Handle byte_buffer);
-
-/*
- * ============================================================
- * Invoking Constructors, Methods, Closures and Field accessors
- * ============================================================
- */
-
-/**
- * Invokes a constructor, creating a new object.
- *
- * This function allows hidden constructors (constructors with leading
- * underscores) to be called.
- *
- * \param type Type of object to be constructed.
- * \param constructor_name The name of the constructor to invoke. Use
- * Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor.
- * This name should not include the name of the class.
- * \param number_of_arguments Size of the arguments array.
- * \param arguments An array of arguments to the constructor.
- *
- * \return If the constructor is called and completes successfully,
- * then the new object. If an error occurs during execution, then an
- * error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_New(Dart_Handle type,
- Dart_Handle constructor_name,
- int number_of_arguments,
- Dart_Handle* arguments);
-
-/**
- * Allocate a new object without invoking a constructor.
- *
- * \param type The type of an object to be allocated.
- *
- * \return The new object. If an error occurs during execution, then an
- * error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Allocate(Dart_Handle type);
-
-/**
- * Allocate a new object without invoking a constructor, and sets specified
- * native fields.
- *
- * \param type The type of an object to be allocated.
- * \param num_native_fields The number of native fields to set.
- * \param native_fields An array containing the value of native fields.
- *
- * \return The new object. If an error occurs during execution, then an
- * error handle is returned.
- */
-DART_EXPORT Dart_Handle
-Dart_AllocateWithNativeFields(Dart_Handle type,
- intptr_t num_native_fields,
- const intptr_t* native_fields);
-
-/**
- * Invokes a method or function.
- *
- * The 'target' parameter may be an object, type, or library. If
- * 'target' is an object, then this function will invoke an instance
- * method. If 'target' is a type, then this function will invoke a
- * static method. If 'target' is a library, then this function will
- * invoke a top-level function from that library.
- * NOTE: This API call cannot be used to invoke methods of a type object.
- *
- * This function ignores visibility (leading underscores in names).
- *
- * May generate an unhandled exception error.
- *
- * \param target An object, type, or library.
- * \param name The name of the function or method to invoke.
- * \param number_of_arguments Size of the arguments array.
- * \param arguments An array of arguments to the function.
- *
- * \return If the function or method is called and completes
- * successfully, then the return value is returned. If an error
- * occurs during execution, then an error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_Invoke(Dart_Handle target,
- Dart_Handle name,
- int number_of_arguments,
- Dart_Handle* arguments);
-/* TODO(turnidge): Document how to invoke operators. */
-
-/**
- * Invokes a Closure with the given arguments.
- *
- * May generate an unhandled exception error.
- *
- * \return If no error occurs during execution, then the result of
- * invoking the closure is returned. If an error occurs during
- * execution, then an error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_InvokeClosure(Dart_Handle closure,
- int number_of_arguments,
- Dart_Handle* arguments);
-
-/**
- * Invokes a Generative Constructor on an object that was previously
- * allocated using Dart_Allocate/Dart_AllocateWithNativeFields.
- *
- * The 'object' parameter must be an object.
- *
- * This function ignores visibility (leading underscores in names).
- *
- * May generate an unhandled exception error.
- *
- * \param object An object.
- * \param name The name of the constructor to invoke.
- * Use Dart_Null() or Dart_EmptyString() to invoke the unnamed constructor.
- * \param number_of_arguments Size of the arguments array.
- * \param arguments An array of arguments to the function.
- *
- * \return If the constructor is called and completes
- * successfully, then the object is returned. If an error
- * occurs during execution, then an error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_InvokeConstructor(Dart_Handle object,
- Dart_Handle name,
- int number_of_arguments,
- Dart_Handle* arguments);
-
-/**
- * Gets the value of a field.
- *
- * The 'container' parameter may be an object, type, or library. If
- * 'container' is an object, then this function will access an
- * instance field. If 'container' is a type, then this function will
- * access a static field. If 'container' is a library, then this
- * function will access a top-level variable.
- * NOTE: This API call cannot be used to access fields of a type object.
- *
- * This function ignores field visibility (leading underscores in names).
- *
- * May generate an unhandled exception error.
- *
- * \param container An object, type, or library.
- * \param name A field name.
- *
- * \return If no error occurs, then the value of the field is
- * returned. Otherwise an error handle is returned.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_GetField(Dart_Handle container, Dart_Handle name);
-
-/**
- * Sets the value of a field.
- *
- * The 'container' parameter may actually be an object, type, or
- * library. If 'container' is an object, then this function will
- * access an instance field. If 'container' is a type, then this
- * function will access a static field. If 'container' is a library,
- * then this function will access a top-level variable.
- * NOTE: This API call cannot be used to access fields of a type object.
- *
- * This function ignores field visibility (leading underscores in names).
- *
- * May generate an unhandled exception error.
- *
- * \param container An object, type, or library.
- * \param name A field name.
- * \param value The new field value.
- *
- * \return A valid handle if no error occurs.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value);
-
-/*
- * ==========
- * Exceptions
- * ==========
- */
-
-/*
- * TODO(turnidge): Remove these functions from the api and replace all
- * uses with Dart_NewUnhandledExceptionError. */
-
-/**
- * Throws an exception.
- *
- * This function causes a Dart language exception to be thrown. This
- * will proceed in the standard way, walking up Dart frames until an
- * appropriate 'catch' block is found, executing 'finally' blocks,
- * etc.
- *
- * If an error handle is passed into this function, the error is
- * propagated immediately. See Dart_PropagateError for a discussion
- * of error propagation.
- *
- * If successful, this function does not return. Note that this means
- * that the destructors of any stack-allocated C++ objects will not be
- * called. If there are no Dart frames on the stack, an error occurs.
- *
- * \return An error handle if the exception was not thrown.
- * Otherwise the function does not return.
- */
-DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception);
-
-/**
- * Rethrows an exception.
- *
- * Rethrows an exception, unwinding all dart frames on the stack. If
- * successful, this function does not return. Note that this means
- * that the destructors of any stack-allocated C++ objects will not be
- * called. If there are no Dart frames on the stack, an error occurs.
- *
- * \return An error handle if the exception was not thrown.
- * Otherwise the function does not return.
- */
-DART_EXPORT Dart_Handle Dart_ReThrowException(Dart_Handle exception,
- Dart_Handle stacktrace);
-
-/*
- * ===========================
- * Native fields and functions
- * ===========================
- */
-
-/**
- * Gets the number of native instance fields in an object.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj,
- int* count);
-
-/**
- * Gets the value of a native field.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj,
- int index,
- intptr_t* value);
-
-/**
- * Sets the value of a native field.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
- int index,
- intptr_t value);
-
-/**
- * The arguments to a native function.
- *
- * This object is passed to a native function to represent its
- * arguments and return value. It allows access to the arguments to a
- * native function by index. It also allows the return value of a
- * native function to be set.
- */
-typedef struct _Dart_NativeArguments* Dart_NativeArguments;
-
-/**
- * Extracts current isolate group data from the native arguments structure.
- */
-DART_EXPORT void* Dart_GetNativeIsolateGroupData(Dart_NativeArguments args);
-
-typedef enum {
- Dart_NativeArgument_kBool = 0,
- Dart_NativeArgument_kInt32,
- Dart_NativeArgument_kUint32,
- Dart_NativeArgument_kInt64,
- Dart_NativeArgument_kUint64,
- Dart_NativeArgument_kDouble,
- Dart_NativeArgument_kString,
- Dart_NativeArgument_kInstance,
- Dart_NativeArgument_kNativeFields,
-} Dart_NativeArgument_Type;
-
-typedef struct _Dart_NativeArgument_Descriptor {
- uint8_t type;
- uint8_t index;
-} Dart_NativeArgument_Descriptor;
-
-typedef union _Dart_NativeArgument_Value {
- bool as_bool;
- int32_t as_int32;
- uint32_t as_uint32;
- int64_t as_int64;
- uint64_t as_uint64;
- double as_double;
- struct {
- Dart_Handle dart_str;
- void* peer;
- } as_string;
- struct {
- intptr_t num_fields;
- intptr_t* values;
- } as_native_fields;
- Dart_Handle as_instance;
-} Dart_NativeArgument_Value;
-
-enum {
- kNativeArgNumberPos = 0,
- kNativeArgNumberSize = 8,
- kNativeArgTypePos = kNativeArgNumberPos + kNativeArgNumberSize,
- kNativeArgTypeSize = 8,
-};
-
-#define BITMASK(size) ((1 << size) - 1)
-#define DART_NATIVE_ARG_DESCRIPTOR(type, position) \
- (((type & BITMASK(kNativeArgTypeSize)) << kNativeArgTypePos) | \
- (position & BITMASK(kNativeArgNumberSize)))
-
-/**
- * Gets the native arguments based on the types passed in and populates
- * the passed arguments buffer with appropriate native values.
- *
- * \param args the Native arguments block passed into the native call.
- * \param num_arguments length of argument descriptor array and argument
- * values array passed in.
- * \param arg_descriptors an array that describes the arguments that
- * need to be retrieved. For each argument to be retrieved the descriptor
- * contains the argument number (0, 1 etc.) and the argument type
- * described using Dart_NativeArgument_Type, e.g:
- * DART_NATIVE_ARG_DESCRIPTOR(Dart_NativeArgument_kBool, 1) indicates
- * that the first argument is to be retrieved and it should be a boolean.
- * \param arg_values array into which the native arguments need to be
- * extracted into, the array is allocated by the caller (it could be
- * stack allocated to avoid the malloc/free performance overhead).
- *
- * \return Success if all the arguments could be extracted correctly,
- * returns an error handle if there were any errors while extracting the
- * arguments (mismatched number of arguments, incorrect types, etc.).
- */
-DART_EXPORT Dart_Handle
-Dart_GetNativeArguments(Dart_NativeArguments args,
- int num_arguments,
- const Dart_NativeArgument_Descriptor* arg_descriptors,
- Dart_NativeArgument_Value* arg_values);
-
-/**
- * Gets the native argument at some index.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args,
- int index);
-/* TODO(turnidge): Specify the behavior of an out-of-bounds access. */
-
-/**
- * Gets the number of native arguments.
- */
-DART_EXPORT int Dart_GetNativeArgumentCount(Dart_NativeArguments args);
-
-/**
- * Gets all the native fields of the native argument at some index.
- * \param args Native arguments structure.
- * \param arg_index Index of the desired argument in the structure above.
- * \param num_fields size of the intptr_t array 'field_values' passed in.
- * \param field_values intptr_t array in which native field values are returned.
- * \return Success if the native fields where copied in successfully. Otherwise
- * returns an error handle. On success the native field values are copied
- * into the 'field_values' array, if the argument at 'arg_index' is a
- * null object then 0 is copied as the native field values into the
- * 'field_values' array.
- */
-DART_EXPORT Dart_Handle
-Dart_GetNativeFieldsOfArgument(Dart_NativeArguments args,
- int arg_index,
- int num_fields,
- intptr_t* field_values);
-
-/**
- * Gets the native field of the receiver.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeReceiver(Dart_NativeArguments args,
- intptr_t* value);
-
-/**
- * Gets a string native argument at some index.
- * \param args Native arguments structure.
- * \param arg_index Index of the desired argument in the structure above.
- * \param peer Returns the peer pointer if the string argument has one.
- * \return Success if the string argument has a peer, if it does not
- * have a peer then the String object is returned. Otherwise returns
- * an error handle (argument is not a String object).
- */
-DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
- int arg_index,
- void** peer);
-
-/**
- * Gets an integer native argument at some index.
- * \param args Native arguments structure.
- * \param index Index of the desired argument in the structure above.
- * \param value Returns the integer value if the argument is an Integer.
- * \return Success if no error occurs. Otherwise returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeIntegerArgument(Dart_NativeArguments args,
- int index,
- int64_t* value);
-
-/**
- * Gets a boolean native argument at some index.
- * \param args Native arguments structure.
- * \param index Index of the desired argument in the structure above.
- * \param value Returns the boolean value if the argument is a Boolean.
- * \return Success if no error occurs. Otherwise returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeBooleanArgument(Dart_NativeArguments args,
- int index,
- bool* value);
-
-/**
- * Gets a double native argument at some index.
- * \param args Native arguments structure.
- * \param index Index of the desired argument in the structure above.
- * \param value Returns the double value if the argument is a double.
- * \return Success if no error occurs. Otherwise returns an error handle.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeDoubleArgument(Dart_NativeArguments args,
- int index,
- double* value);
-
-/**
- * Sets the return value for a native function.
- *
- * If retval is an Error handle, then error will be propagated once
- * the native functions exits. See Dart_PropagateError for a
- * discussion of how different types of errors are propagated.
- */
-DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
- Dart_Handle retval);
-
-DART_EXPORT void Dart_SetWeakHandleReturnValue(Dart_NativeArguments args,
- Dart_WeakPersistentHandle rval);
-
-DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args,
- bool retval);
-
-DART_EXPORT void Dart_SetIntegerReturnValue(Dart_NativeArguments args,
- int64_t retval);
-
-DART_EXPORT void Dart_SetDoubleReturnValue(Dart_NativeArguments args,
- double retval);
-
-/**
- * A native function.
- */
-typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments);
-
-/**
- * Native entry resolution callback.
- *
- * For libraries and scripts which have native functions, the embedder
- * can provide a native entry resolver. This callback is used to map a
- * name/arity to a Dart_NativeFunction. If no function is found, the
- * callback should return NULL.
- *
- * The parameters to the native resolver function are:
- * \param name a Dart string which is the name of the native function.
- * \param num_of_arguments is the number of arguments expected by the
- * native function.
- * \param auto_setup_scope is a boolean flag that can be set by the resolver
- * to indicate if this function needs a Dart API scope (see Dart_EnterScope/
- * Dart_ExitScope) to be setup automatically by the VM before calling into
- * the native function. By default most native functions would require this
- * to be true but some light weight native functions which do not call back
- * into the VM through the Dart API may not require a Dart scope to be
- * setup automatically.
- *
- * \return A valid Dart_NativeFunction which resolves to a native entry point
- * for the native function.
- *
- * See Dart_SetNativeResolver.
- */
-typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name,
- int num_of_arguments,
- bool* auto_setup_scope);
-/* TODO(turnidge): Consider renaming to NativeFunctionResolver or
- * NativeResolver. */
-
-/**
- * Native entry symbol lookup callback.
- *
- * For libraries and scripts which have native functions, the embedder
- * can provide a callback for mapping a native entry to a symbol. This callback
- * maps a native function entry PC to the native function name. If no native
- * entry symbol can be found, the callback should return NULL.
- *
- * The parameters to the native reverse resolver function are:
- * \param nf A Dart_NativeFunction.
- *
- * \return A const UTF-8 string containing the symbol name or NULL.
- *
- * See Dart_SetNativeResolver.
- */
-typedef const uint8_t* (*Dart_NativeEntrySymbol)(Dart_NativeFunction nf);
-
-/**
- * FFI Native C function pointer resolver callback.
- *
- * See Dart_SetFfiNativeResolver.
- */
-typedef void* (*Dart_FfiNativeResolver)(const char* name, uintptr_t args_n);
-
-/*
- * ===========
- * Environment
- * ===========
- */
-
-/**
- * An environment lookup callback function.
- *
- * \param name The name of the value to lookup in the environment.
- *
- * \return A valid handle to a string if the name exists in the
- * current environment or Dart_Null() if not.
- */
-typedef Dart_Handle (*Dart_EnvironmentCallback)(Dart_Handle name);
-
-/**
- * Sets the environment callback for the current isolate. This
- * callback is used to lookup environment values by name in the
- * current environment. This enables the embedder to supply values for
- * the const constructors bool.fromEnvironment, int.fromEnvironment
- * and String.fromEnvironment.
- */
-DART_EXPORT Dart_Handle
-Dart_SetEnvironmentCallback(Dart_EnvironmentCallback callback);
-
-/**
- * Sets the callback used to resolve native functions for a library.
- *
- * \param library A library.
- * \param resolver A native entry resolver.
- *
- * \return A valid handle if the native resolver was set successfully.
- */
-DART_EXPORT Dart_Handle
-Dart_SetNativeResolver(Dart_Handle library,
- Dart_NativeEntryResolver resolver,
- Dart_NativeEntrySymbol symbol);
-/* TODO(turnidge): Rename to Dart_LibrarySetNativeResolver? */
-
-/**
- * Returns the callback used to resolve native functions for a library.
- *
- * \param library A library.
- * \param resolver a pointer to a Dart_NativeEntryResolver
- *
- * \return A valid handle if the library was found.
- */
-DART_EXPORT Dart_Handle
-Dart_GetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver* resolver);
-
-/**
- * Returns the callback used to resolve native function symbols for a library.
- *
- * \param library A library.
- * \param resolver a pointer to a Dart_NativeEntrySymbol.
- *
- * \return A valid handle if the library was found.
- */
-DART_EXPORT Dart_Handle Dart_GetNativeSymbol(Dart_Handle library,
- Dart_NativeEntrySymbol* resolver);
-
-/**
- * Sets the callback used to resolve FFI native functions for a library.
- * The resolved functions are expected to be a C function pointer of the
- * correct signature (as specified in the `@FfiNative()` function
- * annotation in Dart code).
- *
- * NOTE: This is an experimental feature and might change in the future.
- *
- * \param library A library.
- * \param resolver A native function resolver.
- *
- * \return A valid handle if the native resolver was set successfully.
- */
-DART_EXPORT Dart_Handle
-Dart_SetFfiNativeResolver(Dart_Handle library, Dart_FfiNativeResolver resolver);
-
-/*
- * =====================
- * Scripts and Libraries
- * =====================
- */
-
-typedef enum {
- Dart_kCanonicalizeUrl = 0,
- Dart_kImportTag,
- Dart_kKernelTag,
-} Dart_LibraryTag;
-
-/**
- * The library tag handler is a multi-purpose callback provided by the
- * embedder to the Dart VM. The embedder implements the tag handler to
- * provide the ability to load Dart scripts and imports.
- *
- * -- TAGS --
- *
- * Dart_kCanonicalizeUrl
- *
- * This tag indicates that the embedder should canonicalize 'url' with
- * respect to 'library'. For most embedders, the
- * Dart_DefaultCanonicalizeUrl function is a sufficient implementation
- * of this tag. The return value should be a string holding the
- * canonicalized url.
- *
- * Dart_kImportTag
- *
- * This tag is used to load a library from IsolateMirror.loadUri. The embedder
- * should call Dart_LoadLibraryFromKernel to provide the library to the VM. The
- * return value should be an error or library (the result from
- * Dart_LoadLibraryFromKernel).
- *
- * Dart_kKernelTag
- *
- * This tag is used to load the intermediate file (kernel) generated by
- * the Dart front end. This tag is typically used when a 'hot-reload'
- * of an application is needed and the VM is 'use dart front end' mode.
- * The dart front end typically compiles all the scripts, imports and part
- * files into one intermediate file hence we don't use the source/import or
- * script tags. The return value should be an error or a TypedData containing
- * the kernel bytes.
- *
- */
-typedef Dart_Handle (*Dart_LibraryTagHandler)(
- Dart_LibraryTag tag,
- Dart_Handle library_or_package_map_url,
- Dart_Handle url);
-
-/**
- * Sets library tag handler for the current isolate. This handler is
- * used to handle the various tags encountered while loading libraries
- * or scripts in the isolate.
- *
- * \param handler Handler code to be used for handling the various tags
- * encountered while loading libraries or scripts in the isolate.
- *
- * \return If no error occurs, the handler is set for the isolate.
- * Otherwise an error handle is returned.
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT Dart_Handle
-Dart_SetLibraryTagHandler(Dart_LibraryTagHandler handler);
-
-/**
- * Handles deferred loading requests. When this handler is invoked, it should
- * eventually load the deferred loading unit with the given id and call
- * Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError. It is
- * recommended that the loading occur asynchronously, but it is permitted to
- * call Dart_DeferredLoadComplete or Dart_DeferredLoadCompleteError before the
- * handler returns.
- *
- * If an error is returned, it will be propagated through
- * `prefix.loadLibrary()`. This is useful for synchronous
- * implementations, which must propagate any unwind errors from
- * Dart_DeferredLoadComplete or Dart_DeferredLoadComplete. Otherwise the handler
- * should return a non-error such as `Dart_Null()`.
- */
-typedef Dart_Handle (*Dart_DeferredLoadHandler)(intptr_t loading_unit_id);
-
-/**
- * Sets the deferred load handler for the current isolate. This handler is
- * used to handle loading deferred imports in an AppJIT or AppAOT program.
- */
-DART_EXPORT Dart_Handle
-Dart_SetDeferredLoadHandler(Dart_DeferredLoadHandler handler);
-
-/**
- * Notifies the VM that a deferred load completed successfully. This function
- * will eventually cause the corresponding `prefix.loadLibrary()` futures to
- * complete.
- *
- * Requires the current isolate to be the same current isolate during the
- * invocation of the Dart_DeferredLoadHandler.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_DeferredLoadComplete(intptr_t loading_unit_id,
- const uint8_t* snapshot_data,
- const uint8_t* snapshot_instructions);
-
-/**
- * Notifies the VM that a deferred load failed. This function
- * will eventually cause the corresponding `prefix.loadLibrary()` futures to
- * complete with an error.
- *
- * If `transient` is true, future invocations of `prefix.loadLibrary()` will
- * trigger new load requests. If false, futures invocation will complete with
- * the same error.
- *
- * Requires the current isolate to be the same current isolate during the
- * invocation of the Dart_DeferredLoadHandler.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_DeferredLoadCompleteError(intptr_t loading_unit_id,
- const char* error_message,
- bool transient);
-
-/**
- * Canonicalizes a url with respect to some library.
- *
- * The url is resolved with respect to the library's url and some url
- * normalizations are performed.
- *
- * This canonicalization function should be sufficient for most
- * embedders to implement the Dart_kCanonicalizeUrl tag.
- *
- * \param base_url The base url relative to which the url is
- * being resolved.
- * \param url The url being resolved and canonicalized. This
- * parameter is a string handle.
- *
- * \return If no error occurs, a String object is returned. Otherwise
- * an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_DefaultCanonicalizeUrl(Dart_Handle base_url,
- Dart_Handle url);
-
-/**
- * Loads the root library for the current isolate.
- *
- * Requires there to be no current root library.
- *
- * \param kernel_buffer A buffer which contains a kernel binary (see
- * pkg/kernel/binary.md). Must remain valid until isolate group shutdown.
- * \param kernel_size Length of the passed in buffer.
- *
- * \return A handle to the root library, or an error.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_LoadScriptFromKernel(const uint8_t* kernel_buffer, intptr_t kernel_size);
-
-/**
- * Gets the library for the root script for the current isolate.
- *
- * If the root script has not yet been set for the current isolate,
- * this function returns Dart_Null(). This function never returns an
- * error handle.
- *
- * \return Returns the root Library for the current isolate or Dart_Null().
- */
-DART_EXPORT Dart_Handle Dart_RootLibrary(void);
-
-/**
- * Sets the root library for the current isolate.
- *
- * \return Returns an error handle if `library` is not a library handle.
- */
-DART_EXPORT Dart_Handle Dart_SetRootLibrary(Dart_Handle library);
-
-/**
- * Lookup or instantiate a legacy type by name and type arguments from a
- * Library.
- *
- * \param library The library containing the class or interface.
- * \param class_name The class name for the type.
- * \param number_of_type_arguments Number of type arguments.
- * For non parametric types the number of type arguments would be 0.
- * \param type_arguments Pointer to an array of type arguments.
- * For non parametric types a NULL would be passed in for this argument.
- *
- * \return If no error occurs, the type is returned.
- * Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_GetType(Dart_Handle library,
- Dart_Handle class_name,
- intptr_t number_of_type_arguments,
- Dart_Handle* type_arguments);
-
-/**
- * Lookup or instantiate a nullable type by name and type arguments from
- * Library.
- *
- * \param library The library containing the class or interface.
- * \param class_name The class name for the type.
- * \param number_of_type_arguments Number of type arguments.
- * For non parametric types the number of type arguments would be 0.
- * \param type_arguments Pointer to an array of type arguments.
- * For non parametric types a NULL would be passed in for this argument.
- *
- * \return If no error occurs, the type is returned.
- * Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_GetNullableType(Dart_Handle library,
- Dart_Handle class_name,
- intptr_t number_of_type_arguments,
- Dart_Handle* type_arguments);
-
-/**
- * Lookup or instantiate a non-nullable type by name and type arguments from
- * Library.
- *
- * \param library The library containing the class or interface.
- * \param class_name The class name for the type.
- * \param number_of_type_arguments Number of type arguments.
- * For non parametric types the number of type arguments would be 0.
- * \param type_arguments Pointer to an array of type arguments.
- * For non parametric types a NULL would be passed in for this argument.
- *
- * \return If no error occurs, the type is returned.
- * Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle
-Dart_GetNonNullableType(Dart_Handle library,
- Dart_Handle class_name,
- intptr_t number_of_type_arguments,
- Dart_Handle* type_arguments);
-
-/**
- * Creates a nullable version of the provided type.
- *
- * \param type The type to be converted to a nullable type.
- *
- * \return If no error occurs, a nullable type is returned.
- * Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_TypeToNullableType(Dart_Handle type);
-
-/**
- * Creates a non-nullable version of the provided type.
- *
- * \param type The type to be converted to a non-nullable type.
- *
- * \return If no error occurs, a non-nullable type is returned.
- * Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_TypeToNonNullableType(Dart_Handle type);
-
-/**
- * A type's nullability.
- *
- * \param type A Dart type.
- * \param result An out parameter containing the result of the check. True if
- * the type is of the specified nullability, false otherwise.
- *
- * \return Returns an error handle if type is not of type Type.
- */
-DART_EXPORT Dart_Handle Dart_IsNullableType(Dart_Handle type, bool* result);
-DART_EXPORT Dart_Handle Dart_IsNonNullableType(Dart_Handle type, bool* result);
-DART_EXPORT Dart_Handle Dart_IsLegacyType(Dart_Handle type, bool* result);
-
-/**
- * Lookup a class or interface by name from a Library.
- *
- * \param library The library containing the class or interface.
- * \param class_name The name of the class or interface.
- *
- * \return If no error occurs, the class or interface is
- * returned. Otherwise an error handle is returned.
- */
-DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library,
- Dart_Handle class_name);
-/* TODO(asiva): The above method needs to be removed once all uses
- * of it are removed from the embedder code. */
-
-/**
- * Returns an import path to a Library, such as "file:///test.dart" or
- * "dart:core".
- */
-DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library);
-
-/**
- * Returns a URL from which a Library was loaded.
- */
-DART_EXPORT Dart_Handle Dart_LibraryResolvedUrl(Dart_Handle library);
-
-/**
- * \return An array of libraries.
- */
-DART_EXPORT Dart_Handle Dart_GetLoadedLibraries(void);
-
-DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url);
-/* TODO(turnidge): Consider returning Dart_Null() when the library is
- * not found to distinguish that from a true error case. */
-
-/**
- * Report an loading error for the library.
- *
- * \param library The library that failed to load.
- * \param error The Dart error instance containing the load error.
- *
- * \return If the VM handles the error, the return value is
- * a null handle. If it doesn't handle the error, the error
- * object is returned.
- */
-DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library,
- Dart_Handle error);
-
-/**
- * Called by the embedder to load a partial program. Does not set the root
- * library.
- *
- * \param kernel_buffer A buffer which contains a kernel binary (see
- * pkg/kernel/binary.md). Must remain valid until isolate shutdown.
- * \param kernel_buffer_size Length of the passed in buffer.
- *
- * \return A handle to the main library of the compilation unit, or an error.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer,
- intptr_t kernel_buffer_size);
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_LoadLibrary(Dart_Handle kernel_buffer);
-
-/**
- * Indicates that all outstanding load requests have been satisfied.
- * This finalizes all the new classes loaded and optionally completes
- * deferred library futures.
- *
- * Requires there to be a current isolate.
- *
- * \param complete_futures Specify true if all deferred library
- * futures should be completed, false otherwise.
- *
- * \return Success if all classes have been finalized and deferred library
- * futures are completed. Otherwise, returns an error.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_FinalizeLoading(bool complete_futures);
-
-/*
- * =====
- * Peers
- * =====
- */
-
-/**
- * The peer field is a lazily allocated field intended for storage of
- * an uncommonly used values. Most instances types can have a peer
- * field allocated. The exceptions are subtypes of Null, num, and
- * bool.
- */
-
-/**
- * Returns the value of peer field of 'object' in 'peer'.
- *
- * \param object An object.
- * \param peer An out parameter that returns the value of the peer
- * field.
- *
- * \return Returns an error if 'object' is a subtype of Null, num, or
- * bool.
- */
-DART_EXPORT Dart_Handle Dart_GetPeer(Dart_Handle object, void** peer);
-
-/**
- * Sets the value of the peer field of 'object' to the value of
- * 'peer'.
- *
- * \param object An object.
- * \param peer A value to store in the peer field.
- *
- * \return Returns an error if 'object' is a subtype of Null, num, or
- * bool.
- */
-DART_EXPORT Dart_Handle Dart_SetPeer(Dart_Handle object, void* peer);
-
-/*
- * ======
- * Kernel
- * ======
- */
-
-/**
- * Experimental support for Dart to Kernel parser isolate.
- *
- * TODO(hausner): Document finalized interface.
- *
- */
-
-// TODO(33433): Remove kernel service from the embedding API.
-
-typedef enum {
- Dart_KernelCompilationStatus_Unknown = -1,
- Dart_KernelCompilationStatus_Ok = 0,
- Dart_KernelCompilationStatus_Error = 1,
- Dart_KernelCompilationStatus_Crash = 2,
- Dart_KernelCompilationStatus_MsgFailed = 3,
-} Dart_KernelCompilationStatus;
-
-typedef struct {
- Dart_KernelCompilationStatus status;
- bool null_safety;
- char* error;
- uint8_t* kernel;
- intptr_t kernel_size;
-} Dart_KernelCompilationResult;
-
-typedef enum {
- Dart_KernelCompilationVerbosityLevel_Error = 0,
- Dart_KernelCompilationVerbosityLevel_Warning,
- Dart_KernelCompilationVerbosityLevel_Info,
- Dart_KernelCompilationVerbosityLevel_All,
-} Dart_KernelCompilationVerbosityLevel;
-
-DART_EXPORT bool Dart_IsKernelIsolate(Dart_Isolate isolate);
-DART_EXPORT bool Dart_KernelIsolateIsRunning(void);
-DART_EXPORT Dart_Port Dart_KernelPort(void);
-
-/**
- * Compiles the given `script_uri` to a kernel file.
- *
- * \param platform_kernel A buffer containing the kernel of the platform (e.g.
- * `vm_platform_strong.dill`). The VM does not take ownership of this memory.
- *
- * \param platform_kernel_size The length of the platform_kernel buffer.
- *
- * \param snapshot_compile Set to `true` when the compilation is for a snapshot.
- * This is used by the frontend to determine if compilation related information
- * should be printed to console (e.g., null safety mode).
- *
- * \param verbosity Specifies the logging behavior of the kernel compilation
- * service.
- *
- * \return Returns the result of the compilation.
- *
- * On a successful compilation the returned [Dart_KernelCompilationResult] has
- * a status of [Dart_KernelCompilationStatus_Ok] and the `kernel`/`kernel_size`
- * fields are set. The caller takes ownership of the malloc()ed buffer.
- *
- * On a failed compilation the `error` might be set describing the reason for
- * the failed compilation. The caller takes ownership of the malloc()ed
- * error.
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT Dart_KernelCompilationResult
-Dart_CompileToKernel(const char* script_uri,
- const uint8_t* platform_kernel,
- const intptr_t platform_kernel_size,
- bool incremental_compile,
- bool snapshot_compile,
- const char* package_config,
- Dart_KernelCompilationVerbosityLevel verbosity);
-
-typedef struct {
- const char* uri;
- const char* source;
-} Dart_SourceFile;
-
-DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies(void);
-
-/**
- * Sets the kernel buffer which will be used to load Dart SDK sources
- * dynamically at runtime.
- *
- * \param platform_kernel A buffer containing kernel which has sources for the
- * Dart SDK populated. Note: The VM does not take ownership of this memory.
- *
- * \param platform_kernel_size The length of the platform_kernel buffer.
- */
-DART_EXPORT void Dart_SetDartLibrarySourcesKernel(
- const uint8_t* platform_kernel,
- const intptr_t platform_kernel_size);
-
-/**
- * Detect the null safety opt-in status.
- *
- * When running from source, it is based on the opt-in status of `script_uri`.
- * When running from a kernel buffer, it is based on the mode used when
- * generating `kernel_buffer`.
- * When running from an appJIT or AOT snapshot, it is based on the mode used
- * when generating `snapshot_data`.
- *
- * \param script_uri Uri of the script that contains the source code
- *
- * \param package_config Uri of the package configuration file (either in format
- * of .packages or .dart_tool/package_config.json) for the null safety
- * detection to resolve package imports against. If this parameter is not
- * passed the package resolution of the parent isolate should be used.
- *
- * \param original_working_directory current working directory when the VM
- * process was launched, this is used to correctly resolve the path specified
- * for package_config.
- *
- * \param snapshot_data Buffer containing the snapshot data of the
- * isolate or NULL if no snapshot is provided. If provided, the buffers must
- * remain valid until the isolate shuts down.
- *
- * \param snapshot_instructions Buffer containing the snapshot instructions of
- * the isolate or NULL if no snapshot is provided. If provided, the buffers
- * must remain valid until the isolate shuts down.
- *
- * \param kernel_buffer A buffer which contains a kernel/DIL program. Must
- * remain valid until isolate shutdown.
- *
- * \param kernel_buffer_size The size of `kernel_buffer`.
- *
- * \return Returns true if the null safety is opted in by the input being
- * run `script_uri`, `snapshot_data` or `kernel_buffer`.
- *
- */
-DART_EXPORT bool Dart_DetectNullSafety(const char* script_uri,
- const char* package_config,
- const char* original_working_directory,
- const uint8_t* snapshot_data,
- const uint8_t* snapshot_instructions,
- const uint8_t* kernel_buffer,
- intptr_t kernel_buffer_size);
-
-#define DART_KERNEL_ISOLATE_NAME "kernel-service"
-
-/*
- * =======
- * Service
- * =======
- */
-
-#define DART_VM_SERVICE_ISOLATE_NAME "vm-service"
-
-/**
- * Returns true if isolate is the service isolate.
- *
- * \param isolate An isolate
- *
- * \return Returns true if 'isolate' is the service isolate.
- */
-DART_EXPORT bool Dart_IsServiceIsolate(Dart_Isolate isolate);
-
-/**
- * Writes the CPU profile to the timeline as a series of 'instant' events.
- *
- * Note that this is an expensive operation.
- *
- * \param main_port The main port of the Isolate whose profile samples to write.
- * \param error An optional error, must be free()ed by caller.
- *
- * \return Returns true if the profile is successfully written and false
- * otherwise.
- */
-DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char** error);
-
-/*
- * ==============
- * Precompilation
- * ==============
- */
-
-/**
- * Compiles all functions reachable from entry points and marks
- * the isolate to disallow future compilation.
- *
- * Entry points should be specified using `@pragma("vm:entry-point")`
- * annotation.
- *
- * \return An error handle if a compilation error or runtime error running const
- * constructors was encountered.
- */
-DART_EXPORT Dart_Handle Dart_Precompile(void);
-
-typedef void (*Dart_CreateLoadingUnitCallback)(
- void* callback_data,
- intptr_t loading_unit_id,
- void** write_callback_data,
- void** write_debug_callback_data);
-typedef void (*Dart_StreamingWriteCallback)(void* callback_data,
- const uint8_t* buffer,
- intptr_t size);
-typedef void (*Dart_StreamingCloseCallback)(void* callback_data);
-
-DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id);
-
-// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name.
-// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual
-// symbol names in the objects are given by the '...AsmSymbol' definitions.
-#if defined(__APPLE__)
-#define kSnapshotBuildIdCSymbol "kDartSnapshotBuildId"
-#define kVmSnapshotDataCSymbol "kDartVmSnapshotData"
-#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions"
-#define kVmSnapshotBssCSymbol "kDartVmSnapshotBss"
-#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData"
-#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions"
-#define kIsolateSnapshotBssCSymbol "kDartIsolateSnapshotBss"
-#else
-#define kSnapshotBuildIdCSymbol "_kDartSnapshotBuildId"
-#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData"
-#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions"
-#define kVmSnapshotBssCSymbol "_kDartVmSnapshotBss"
-#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData"
-#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions"
-#define kIsolateSnapshotBssCSymbol "_kDartIsolateSnapshotBss"
-#endif
-
-#define kSnapshotBuildIdAsmSymbol "_kDartSnapshotBuildId"
-#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData"
-#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions"
-#define kVmSnapshotBssAsmSymbol "_kDartVmSnapshotBss"
-#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData"
-#define kIsolateSnapshotInstructionsAsmSymbol \
- "_kDartIsolateSnapshotInstructions"
-#define kIsolateSnapshotBssAsmSymbol "_kDartIsolateSnapshotBss"
-
-/**
- * Creates a precompiled snapshot.
- * - A root library must have been loaded.
- * - Dart_Precompile must have been called.
- *
- * Outputs an assembly file defining the symbols listed in the definitions
- * above.
- *
- * The assembly should be compiled as a static or shared library and linked or
- * loaded by the embedder. Running this snapshot requires a VM compiled with
- * DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and
- * kDartVmSnapshotInstructions should be passed to Dart_Initialize. The
- * kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be
- * passed to Dart_CreateIsolateGroup.
- *
- * The callback will be invoked one or more times to provide the assembly code.
- *
- * If stripped is true, then the assembly code will not include DWARF
- * debugging sections.
- *
- * If debug_callback_data is provided, debug_callback_data will be used with
- * the callback to provide separate debugging information.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
- void* callback_data,
- bool stripped,
- void* debug_callback_data);
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateAppAOTSnapshotAsAssemblies(
- Dart_CreateLoadingUnitCallback next_callback,
- void* next_callback_data,
- bool stripped,
- Dart_StreamingWriteCallback write_callback,
- Dart_StreamingCloseCallback close_callback);
-
-/**
- * Creates a precompiled snapshot.
- * - A root library must have been loaded.
- * - Dart_Precompile must have been called.
- *
- * Outputs an ELF shared library defining the symbols
- * - _kDartVmSnapshotData
- * - _kDartVmSnapshotInstructions
- * - _kDartIsolateSnapshotData
- * - _kDartIsolateSnapshotInstructions
- *
- * The shared library should be dynamically loaded by the embedder.
- * Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT.
- * The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to
- * Dart_Initialize. The kDartIsolateSnapshotData and
- * kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolate.
- *
- * The callback will be invoked one or more times to provide the binary output.
- *
- * If stripped is true, then the binary output will not include DWARF
- * debugging sections.
- *
- * If debug_callback_data is provided, debug_callback_data will be used with
- * the callback to provide separate debugging information.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateAppAOTSnapshotAsElf(Dart_StreamingWriteCallback callback,
- void* callback_data,
- bool stripped,
- void* debug_callback_data);
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateAppAOTSnapshotAsElfs(Dart_CreateLoadingUnitCallback next_callback,
- void* next_callback_data,
- bool stripped,
- Dart_StreamingWriteCallback write_callback,
- Dart_StreamingCloseCallback close_callback);
-
-/**
- * Like Dart_CreateAppAOTSnapshotAsAssembly, but only includes
- * kDartVmSnapshotData and kDartVmSnapshotInstructions. It also does
- * not strip DWARF information from the generated assembly or allow for
- * separate debug information.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
- void* callback_data);
-
-/**
- * Sorts the class-ids in depth first traversal order of the inheritance
- * tree. This is a costly operation, but it can make method dispatch
- * more efficient and is done before writing snapshots.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_SortClasses(void);
-
-/**
- * Creates a snapshot that caches compiled code and type feedback for faster
- * startup and quicker warmup in a subsequent process.
- *
- * Outputs a snapshot in two pieces. The pieces should be passed to
- * Dart_CreateIsolateGroup in a VM using the same VM snapshot pieces used in the
- * current VM. The instructions piece must be loaded with read and execute
- * permissions; the data piece may be loaded as read-only.
- *
- * - Requires the VM to have not been started with --precompilation.
- * - Not supported when targeting IA32.
- * - The VM writing the snapshot and the VM reading the snapshot must be the
- * same version, must be built in the same DEBUG/RELEASE/PRODUCT mode, must
- * be targeting the same architecture, and must both be in checked mode or
- * both in unchecked mode.
- *
- * The buffers are scope allocated and are only valid until the next call to
- * Dart_ExitScope.
- *
- * \return A valid handle if no error occurs during the operation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer,
- intptr_t* isolate_snapshot_data_size,
- uint8_t** isolate_snapshot_instructions_buffer,
- intptr_t* isolate_snapshot_instructions_size);
-
-/**
- * Like Dart_CreateAppJITSnapshotAsBlobs, but also creates a new VM snapshot.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_CreateCoreJITSnapshotAsBlobs(
- uint8_t** vm_snapshot_data_buffer,
- intptr_t* vm_snapshot_data_size,
- uint8_t** vm_snapshot_instructions_buffer,
- intptr_t* vm_snapshot_instructions_size,
- uint8_t** isolate_snapshot_data_buffer,
- intptr_t* isolate_snapshot_data_size,
- uint8_t** isolate_snapshot_instructions_buffer,
- intptr_t* isolate_snapshot_instructions_size);
-
-/**
- * Get obfuscation map for precompiled code.
- *
- * Obfuscation map is encoded as a JSON array of pairs (original name,
- * obfuscated name).
- *
- * \return Returns an error handler if the VM was built in a mode that does not
- * support obfuscation.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
-Dart_GetObfuscationMap(uint8_t** buffer, intptr_t* buffer_length);
-
-/**
- * Returns whether the VM only supports running from precompiled snapshots and
- * not from any other kind of snapshot or from source (that is, the VM was
- * compiled with DART_PRECOMPILED_RUNTIME).
- */
-DART_EXPORT bool Dart_IsPrecompiledRuntime(void);
-
-/**
- * Print a native stack trace. Used for crash handling.
- *
- * If context is NULL, prints the current stack trace. Otherwise, context
- * should be a CONTEXT* (Windows) or ucontext_t* (POSIX) from a signal handler
- * running on the current thread.
- */
-DART_EXPORT void Dart_DumpNativeStackTrace(void* context);
-
-/**
- * Indicate that the process is about to abort, and the Dart VM should not
- * attempt to cleanup resources.
- */
-DART_EXPORT void Dart_PrepareToAbort(void);
-
-/**
- * Callback provided by the embedder that is used by the VM to
- * produce footnotes appended to DWARF stack traces.
- *
- * Whenever VM formats a stack trace as a string it would call this callback
- * passing raw program counters for each frame in the stack trace.
- *
- * Embedder can then return a string which if not-null will be appended to the
- * formatted stack trace.
- *
- * Returned string is expected to be `malloc()` allocated. VM takes ownership
- * of the returned string and will `free()` it.
- *
- * \param addresses raw program counter addresses for each frame
- * \param count number of elements in the addresses array
- */
-typedef char* (*Dart_DwarfStackTraceFootnoteCallback)(void* addresses[],
- intptr_t count);
-
-/**
- * Configure DWARF stack trace footnote callback.
- */
-DART_EXPORT void Dart_SetDwarfStackTraceFootnoteCallback(
- Dart_DwarfStackTraceFootnoteCallback callback);
-
-#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */
diff --git a/core/dart-bridge/include/dart_api_dl.c b/core/dart-bridge/include/dart_api_dl.c
deleted file mode 100644
index c4a68f4..0000000
--- a/core/dart-bridge/include/dart_api_dl.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#include "dart_api_dl.h" /* NOLINT */
-#include "dart_version.h" /* NOLINT */
-#include "internal/dart_api_dl_impl.h" /* NOLINT */
-
-#include
-
-#define DART_API_DL_DEFINITIONS(name, R, A) name##_Type name##_DL = NULL;
-
-DART_API_ALL_DL_SYMBOLS(DART_API_DL_DEFINITIONS)
-
-#undef DART_API_DL_DEFINITIONS
-
-typedef void* DartApiEntry_function;
-
-DartApiEntry_function FindFunctionPointer(const DartApiEntry* entries,
- const char* name) {
- while (entries->name != NULL) {
- if (strcmp(entries->name, name) == 0) return entries->function;
- entries++;
- }
- return NULL;
-}
-
-intptr_t Dart_InitializeApiDL(void* data) {
- DartApi* dart_api_data = (DartApi*)data;
-
- if (dart_api_data->major != DART_API_DL_MAJOR_VERSION) {
- // If the DartVM we're running on does not have the same version as this
- // file was compiled against, refuse to initialize. The symbols are not
- // compatible.
- return -1;
- }
- // Minor versions are allowed to be different.
- // If the DartVM has a higher minor version, it will provide more symbols
- // than we initialize here.
- // If the DartVM has a lower minor version, it will not provide all symbols.
- // In that case, we leave the missing symbols un-initialized. Those symbols
- // should not be used by the Dart and native code. The client is responsible
- // for checking the minor version number himself based on which symbols it
- // is using.
- // (If we would error out on this case, recompiling native code against a
- // newer SDK would break all uses on older SDKs, which is too strict.)
-
- const DartApiEntry* dart_api_function_pointers = dart_api_data->functions;
-
-#define DART_API_DL_INIT(name, R, A) \
- name##_DL = \
- (name##_Type)(FindFunctionPointer(dart_api_function_pointers, #name));
- DART_API_ALL_DL_SYMBOLS(DART_API_DL_INIT)
-#undef DART_API_DL_INIT
-
- return 0;
-}
diff --git a/core/dart-bridge/include/dart_api_dl.h b/core/dart-bridge/include/dart_api_dl.h
deleted file mode 100644
index cce3450..0000000
--- a/core/dart-bridge/include/dart_api_dl.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#ifndef RUNTIME_INCLUDE_DART_API_DL_H_
-#define RUNTIME_INCLUDE_DART_API_DL_H_
-
-#include "dart_api.h" /* NOLINT */
-#include "dart_native_api.h" /* NOLINT */
-
-/** \mainpage Dynamically Linked Dart API
- *
- * This exposes a subset of symbols from dart_api.h and dart_native_api.h
- * available in every Dart embedder through dynamic linking.
- *
- * All symbols are postfixed with _DL to indicate that they are dynamically
- * linked and to prevent conflicts with the original symbol.
- *
- * Link `dart_api_dl.c` file into your library and invoke
- * `Dart_InitializeApiDL` with `NativeApi.initializeApiDLData`.
- */
-
-DART_EXPORT intptr_t Dart_InitializeApiDL(void* data);
-
-// ============================================================================
-// IMPORTANT! Never update these signatures without properly updating
-// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION.
-//
-// Verbatim copy of `dart_native_api.h` and `dart_api.h` symbol names and types
-// to trigger compile-time errors if the symbols in those files are updated
-// without updating these.
-//
-// Function return and argument types, and typedefs are carbon copied. Structs
-// are typechecked nominally in C/C++, so they are not copied, instead a
-// comment is added to their definition.
-typedef int64_t Dart_Port_DL;
-
-typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id,
- Dart_CObject* message);
-
-// dart_native_api.h symbols can be called on any thread.
-#define DART_NATIVE_API_DL_SYMBOLS(F) \
- /***** dart_native_api.h *****/ \
- /* Dart_Port */ \
- F(Dart_PostCObject, bool, (Dart_Port_DL port_id, Dart_CObject * message)) \
- F(Dart_PostInteger, bool, (Dart_Port_DL port_id, int64_t message)) \
- F(Dart_NewNativePort, Dart_Port_DL, \
- (const char* name, Dart_NativeMessageHandler_DL handler, \
- bool handle_concurrently)) \
- F(Dart_CloseNativePort, bool, (Dart_Port_DL native_port_id))
-
-// dart_api.h symbols can only be called on Dart threads.
-#define DART_API_DL_SYMBOLS(F) \
- /***** dart_api.h *****/ \
- /* Errors */ \
- F(Dart_IsError, bool, (Dart_Handle handle)) \
- F(Dart_IsApiError, bool, (Dart_Handle handle)) \
- F(Dart_IsUnhandledExceptionError, bool, (Dart_Handle handle)) \
- F(Dart_IsCompilationError, bool, (Dart_Handle handle)) \
- F(Dart_IsFatalError, bool, (Dart_Handle handle)) \
- F(Dart_GetError, const char*, (Dart_Handle handle)) \
- F(Dart_ErrorHasException, bool, (Dart_Handle handle)) \
- F(Dart_ErrorGetException, Dart_Handle, (Dart_Handle handle)) \
- F(Dart_ErrorGetStackTrace, Dart_Handle, (Dart_Handle handle)) \
- F(Dart_NewApiError, Dart_Handle, (const char* error)) \
- F(Dart_NewCompilationError, Dart_Handle, (const char* error)) \
- F(Dart_NewUnhandledExceptionError, Dart_Handle, (Dart_Handle exception)) \
- F(Dart_PropagateError, void, (Dart_Handle handle)) \
- /* Dart_Handle, Dart_PersistentHandle, Dart_WeakPersistentHandle */ \
- F(Dart_HandleFromPersistent, Dart_Handle, (Dart_PersistentHandle object)) \
- F(Dart_HandleFromWeakPersistent, Dart_Handle, \
- (Dart_WeakPersistentHandle object)) \
- F(Dart_NewPersistentHandle, Dart_PersistentHandle, (Dart_Handle object)) \
- F(Dart_SetPersistentHandle, void, \
- (Dart_PersistentHandle obj1, Dart_Handle obj2)) \
- F(Dart_DeletePersistentHandle, void, (Dart_PersistentHandle object)) \
- F(Dart_NewWeakPersistentHandle, Dart_WeakPersistentHandle, \
- (Dart_Handle object, void* peer, intptr_t external_allocation_size, \
- Dart_HandleFinalizer callback)) \
- F(Dart_DeleteWeakPersistentHandle, void, (Dart_WeakPersistentHandle object)) \
- F(Dart_UpdateExternalSize, void, \
- (Dart_WeakPersistentHandle object, intptr_t external_allocation_size)) \
- F(Dart_NewFinalizableHandle, Dart_FinalizableHandle, \
- (Dart_Handle object, void* peer, intptr_t external_allocation_size, \
- Dart_HandleFinalizer callback)) \
- F(Dart_DeleteFinalizableHandle, void, \
- (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object)) \
- F(Dart_UpdateFinalizableExternalSize, void, \
- (Dart_FinalizableHandle object, Dart_Handle strong_ref_to_object, \
- intptr_t external_allocation_size)) \
- /* Isolates */ \
- F(Dart_CurrentIsolate, Dart_Isolate, (void)) \
- F(Dart_ExitIsolate, void, (void)) \
- F(Dart_EnterIsolate, void, (Dart_Isolate)) \
- /* Dart_Port */ \
- F(Dart_Post, bool, (Dart_Port_DL port_id, Dart_Handle object)) \
- F(Dart_NewSendPort, Dart_Handle, (Dart_Port_DL port_id)) \
- F(Dart_SendPortGetId, Dart_Handle, \
- (Dart_Handle port, Dart_Port_DL * port_id)) \
- /* Scopes */ \
- F(Dart_EnterScope, void, (void)) \
- F(Dart_ExitScope, void, (void)) \
- /* Objects */ \
- F(Dart_IsNull, bool, (Dart_Handle))
-
-#define DART_API_ALL_DL_SYMBOLS(F) \
- DART_NATIVE_API_DL_SYMBOLS(F) \
- DART_API_DL_SYMBOLS(F)
-// IMPORTANT! Never update these signatures without properly updating
-// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION.
-//
-// End of verbatim copy.
-// ============================================================================
-
-// Copy of definition of DART_EXPORT without 'used' attribute.
-//
-// The 'used' attribute cannot be used with DART_API_ALL_DL_SYMBOLS because
-// they are not function declarations, but variable declarations with a
-// function pointer type.
-//
-// The function pointer variables are initialized with the addresses of the
-// functions in the VM. If we were to use function declarations instead, we
-// would need to forward the call to the VM adding indirection.
-#if defined(__CYGWIN__)
-#error Tool chain and platform not supported.
-#elif defined(_WIN32)
-#if defined(DART_SHARED_LIB)
-#define DART_EXPORT_DL DART_EXTERN_C __declspec(dllexport)
-#else
-#define DART_EXPORT_DL DART_EXTERN_C
-#endif
-#else
-#if __GNUC__ >= 4
-#if defined(DART_SHARED_LIB)
-#define DART_EXPORT_DL DART_EXTERN_C __attribute__((visibility("default")))
-#else
-#define DART_EXPORT_DL DART_EXTERN_C
-#endif
-#else
-#error Tool chain not supported.
-#endif
-#endif
-
-#define DART_API_DL_DECLARATIONS(name, R, A) \
- typedef R(*name##_Type) A; \
- DART_EXPORT_DL name##_Type name##_DL;
-
-DART_API_ALL_DL_SYMBOLS(DART_API_DL_DECLARATIONS)
-
-#undef DART_API_DL_DECLARATIONS
-
-#undef DART_EXPORT_DL
-
-#endif /* RUNTIME_INCLUDE_DART_API_DL_H_ */ /* NOLINT */
diff --git a/core/dart-bridge/include/dart_native_api.h b/core/dart-bridge/include/dart_native_api.h
deleted file mode 100644
index 79194e0..0000000
--- a/core/dart-bridge/include/dart_native_api.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#ifndef RUNTIME_INCLUDE_DART_NATIVE_API_H_
-#define RUNTIME_INCLUDE_DART_NATIVE_API_H_
-
-#include "dart_api.h" /* NOLINT */
-
-/*
- * ==========================================
- * Message sending/receiving from native code
- * ==========================================
- */
-
-/**
- * A Dart_CObject is used for representing Dart objects as native C
- * data outside the Dart heap. These objects are totally detached from
- * the Dart heap. Only a subset of the Dart objects have a
- * representation as a Dart_CObject.
- *
- * The string encoding in the 'value.as_string' is UTF-8.
- *
- * All the different types from dart:typed_data are exposed as type
- * kTypedData. The specific type from dart:typed_data is in the type
- * field of the as_typed_data structure. The length in the
- * as_typed_data structure is always in bytes.
- *
- * The data for kTypedData is copied on message send and ownership remains with
- * the caller. The ownership of data for kExternalTyped is passed to the VM on
- * message send and returned when the VM invokes the
- * Dart_HandleFinalizer callback; a non-NULL callback must be provided.
- *
- * Note that Dart_CObject_kNativePointer is intended for internal use by
- * dart:io implementation and has no connection to dart:ffi Pointer class.
- * It represents a pointer to a native resource of a known type.
- * The receiving side will only see this pointer as an integer and will not
- * see the specified finalizer.
- * The specified finalizer will only be invoked if the message is not delivered.
- */
-typedef enum {
- Dart_CObject_kNull = 0,
- Dart_CObject_kBool,
- Dart_CObject_kInt32,
- Dart_CObject_kInt64,
- Dart_CObject_kDouble,
- Dart_CObject_kString,
- Dart_CObject_kArray,
- Dart_CObject_kTypedData,
- Dart_CObject_kExternalTypedData,
- Dart_CObject_kSendPort,
- Dart_CObject_kCapability,
- Dart_CObject_kNativePointer,
- Dart_CObject_kUnsupported,
- Dart_CObject_kUnmodifiableExternalTypedData,
- Dart_CObject_kNumberOfTypes
-} Dart_CObject_Type;
-// This enum is versioned by DART_API_DL_MAJOR_VERSION, only add at the end
-// and bump the DART_API_DL_MINOR_VERSION.
-
-typedef struct _Dart_CObject {
- Dart_CObject_Type type;
- union {
- bool as_bool;
- int32_t as_int32;
- int64_t as_int64;
- double as_double;
- const char* as_string;
- struct {
- Dart_Port id;
- Dart_Port origin_id;
- } as_send_port;
- struct {
- int64_t id;
- } as_capability;
- struct {
- intptr_t length;
- struct _Dart_CObject** values;
- } as_array;
- struct {
- Dart_TypedData_Type type;
- intptr_t length; /* in elements, not bytes */
- const uint8_t* values;
- } as_typed_data;
- struct {
- Dart_TypedData_Type type;
- intptr_t length; /* in elements, not bytes */
- uint8_t* data;
- void* peer;
- Dart_HandleFinalizer callback;
- } as_external_typed_data;
- struct {
- intptr_t ptr;
- intptr_t size;
- Dart_HandleFinalizer callback;
- } as_native_pointer;
- } value;
-} Dart_CObject;
-// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when
-// changing this struct.
-
-/**
- * Posts a message on some port. The message will contain the Dart_CObject
- * object graph rooted in 'message'.
- *
- * While the message is being sent the state of the graph of Dart_CObject
- * structures rooted in 'message' should not be accessed, as the message
- * generation will make temporary modifications to the data. When the message
- * has been sent the graph will be fully restored.
- *
- * If true is returned, the message was enqueued, and finalizers for external
- * typed data will eventually run, even if the receiving isolate shuts down
- * before processing the message. If false is returned, the message was not
- * enqueued and ownership of external typed data in the message remains with the
- * caller.
- *
- * This function may be called on any thread when the VM is running (that is,
- * after Dart_Initialize has returned and before Dart_Cleanup has been called).
- *
- * \param port_id The destination port.
- * \param message The message to send.
- *
- * \return True if the message was posted.
- */
-DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message);
-
-/**
- * Posts a message on some port. The message will contain the integer 'message'.
- *
- * \param port_id The destination port.
- * \param message The message to send.
- *
- * \return True if the message was posted.
- */
-DART_EXPORT bool Dart_PostInteger(Dart_Port port_id, int64_t message);
-
-/**
- * A native message handler.
- *
- * This handler is associated with a native port by calling
- * Dart_NewNativePort.
- *
- * The message received is decoded into the message structure. The
- * lifetime of the message data is controlled by the caller. All the
- * data references from the message are allocated by the caller and
- * will be reclaimed when returning to it.
- */
-typedef void (*Dart_NativeMessageHandler)(Dart_Port dest_port_id,
- Dart_CObject* message);
-
-/**
- * Creates a new native port. When messages are received on this
- * native port, then they will be dispatched to the provided native
- * message handler.
- *
- * \param name The name of this port in debugging messages.
- * \param handler The C handler to run when messages arrive on the port.
- * \param handle_concurrently Is it okay to process requests on this
- * native port concurrently?
- *
- * \return If successful, returns the port id for the native port. In
- * case of error, returns ILLEGAL_PORT.
- */
-DART_EXPORT Dart_Port Dart_NewNativePort(const char* name,
- Dart_NativeMessageHandler handler,
- bool handle_concurrently);
-/* TODO(turnidge): Currently handle_concurrently is ignored. */
-
-/**
- * Closes the native port with the given id.
- *
- * The port must have been allocated by a call to Dart_NewNativePort.
- *
- * \param native_port_id The id of the native port to close.
- *
- * \return Returns true if the port was closed successfully.
- */
-DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id);
-
-/*
- * ==================
- * Verification Tools
- * ==================
- */
-
-/**
- * Forces all loaded classes and functions to be compiled eagerly in
- * the current isolate..
- *
- * TODO(turnidge): Document.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll(void);
-
-/**
- * Finalizes all classes.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_FinalizeAllClasses(void);
-
-/* This function is intentionally undocumented.
- *
- * It should not be used outside internal tests.
- */
-DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg);
-
-#endif /* INCLUDE_DART_NATIVE_API_H_ */ /* NOLINT */
diff --git a/core/dart-bridge/include/dart_tools_api.h b/core/dart-bridge/include/dart_tools_api.h
deleted file mode 100644
index 7b706bc..0000000
--- a/core/dart-bridge/include/dart_tools_api.h
+++ /dev/null
@@ -1,658 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef RUNTIME_INCLUDE_DART_TOOLS_API_H_
-#define RUNTIME_INCLUDE_DART_TOOLS_API_H_
-
-#include "dart_api.h" /* NOLINT */
-
-/** \mainpage Dart Tools Embedding API Reference
- *
- * This reference describes the Dart embedding API for tools. Tools include
- * a debugger, service protocol, and timeline.
- *
- * NOTE: The APIs described in this file are unstable and subject to change.
- *
- * This reference is generated from the header include/dart_tools_api.h.
- */
-
-/*
- * ========
- * Debugger
- * ========
- */
-
-/**
- * ILLEGAL_ISOLATE_ID is a number guaranteed never to be associated with a
- * valid isolate.
- */
-#define ILLEGAL_ISOLATE_ID ILLEGAL_PORT
-
-/**
- * ILLEGAL_ISOLATE_GROUP_ID is a number guaranteed never to be associated with a
- * valid isolate group.
- */
-#define ILLEGAL_ISOLATE_GROUP_ID 0
-
-/*
- * =======
- * Service
- * =======
- */
-
-/**
- * A service request callback function.
- *
- * These callbacks, registered by the embedder, are called when the VM receives
- * a service request it can't handle and the service request command name
- * matches one of the embedder registered handlers.
- *
- * The return value of the callback indicates whether the response
- * should be used as a regular result or an error result.
- * Specifically, if the callback returns true, a regular JSON-RPC
- * response is built in the following way:
- *
- * {
- * "jsonrpc": "2.0",
- * "result": ,
- * "id": ,
- * }
- *
- * If the callback returns false, a JSON-RPC error is built like this:
- *
- * {
- * "jsonrpc": "2.0",
- * "error": ,
- * "id": ,
- * }
- *
- * \param method The rpc method name.
- * \param param_keys Service requests can have key-value pair parameters. The
- * keys and values are flattened and stored in arrays.
- * \param param_values The values associated with the keys.
- * \param num_params The length of the param_keys and param_values arrays.
- * \param user_data The user_data pointer registered with this handler.
- * \param result A C string containing a valid JSON object. The returned
- * pointer will be freed by the VM by calling free.
- *
- * \return True if the result is a regular JSON-RPC response, false if the
- * result is a JSON-RPC error.
- */
-typedef bool (*Dart_ServiceRequestCallback)(const char* method,
- const char** param_keys,
- const char** param_values,
- intptr_t num_params,
- void* user_data,
- const char** json_object);
-
-/**
- * Register a Dart_ServiceRequestCallback to be called to handle
- * requests for the named rpc on a specific isolate. The callback will
- * be invoked with the current isolate set to the request target.
- *
- * \param method The name of the method that this callback is responsible for.
- * \param callback The callback to invoke.
- * \param user_data The user data passed to the callback.
- *
- * NOTE: If multiple callbacks with the same name are registered, only
- * the last callback registered will be remembered.
- */
-DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback(
- const char* method,
- Dart_ServiceRequestCallback callback,
- void* user_data);
-
-/**
- * Register a Dart_ServiceRequestCallback to be called to handle
- * requests for the named rpc. The callback will be invoked without a
- * current isolate.
- *
- * \param method The name of the command that this callback is responsible for.
- * \param callback The callback to invoke.
- * \param user_data The user data passed to the callback.
- *
- * NOTE: If multiple callbacks with the same name are registered, only
- * the last callback registered will be remembered.
- */
-DART_EXPORT void Dart_RegisterRootServiceRequestCallback(
- const char* method,
- Dart_ServiceRequestCallback callback,
- void* user_data);
-
-/**
- * Embedder information which can be requested by the VM for internal or
- * reporting purposes.
- *
- * The pointers in this structure are not going to be cached or freed by the VM.
- */
-
- #define DART_EMBEDDER_INFORMATION_CURRENT_VERSION (0x00000001)
-
-typedef struct {
- int32_t version;
- const char* name; // [optional] The name of the embedder
- int64_t current_rss; // [optional] the current RSS of the embedder
- int64_t max_rss; // [optional] the maximum RSS of the embedder
-} Dart_EmbedderInformation;
-
-/**
- * Callback provided by the embedder that is used by the VM to request
- * information.
- *
- * \return Returns a pointer to a Dart_EmbedderInformation structure.
- * The embedder keeps the ownership of the structure and any field in it.
- * The embedder must ensure that the structure will remain valid until the
- * next invocation of the callback.
- */
-typedef void (*Dart_EmbedderInformationCallback)(
- Dart_EmbedderInformation* info);
-
-/**
- * Register a Dart_ServiceRequestCallback to be called to handle
- * requests for the named rpc. The callback will be invoked without a
- * current isolate.
- *
- * \param method The name of the command that this callback is responsible for.
- * \param callback The callback to invoke.
- * \param user_data The user data passed to the callback.
- *
- * NOTE: If multiple callbacks are registered, only the last callback registered
- * will be remembered.
- */
-DART_EXPORT void Dart_SetEmbedderInformationCallback(
- Dart_EmbedderInformationCallback callback);
-
-/**
- * Invoke a vm-service method and wait for its result.
- *
- * \param request_json The utf8-encoded json-rpc request.
- * \param request_json_length The length of the json-rpc request.
- *
- * \param response_json The returned utf8-encoded json response, must be
- * free()ed by caller.
- * \param response_json_length The length of the returned json response.
- * \param error An optional error, must be free()ed by caller.
- *
- * \return Whether the call was successfully performed.
- *
- * NOTE: This method does not need a current isolate and must not have the
- * vm-isolate being the current isolate. It must be called after
- * Dart_Initialize() and before Dart_Cleanup().
- */
-DART_EXPORT bool Dart_InvokeVMServiceMethod(uint8_t* request_json,
- intptr_t request_json_length,
- uint8_t** response_json,
- intptr_t* response_json_length,
- char** error);
-
-/*
- * ========
- * Event Streams
- * ========
- */
-
-/**
- * A callback invoked when the VM service gets a request to listen to
- * some stream.
- *
- * \return Returns true iff the embedder supports the named stream id.
- */
-typedef bool (*Dart_ServiceStreamListenCallback)(const char* stream_id);
-
-/**
- * A callback invoked when the VM service gets a request to cancel
- * some stream.
- */
-typedef void (*Dart_ServiceStreamCancelCallback)(const char* stream_id);
-
-/**
- * Adds VM service stream callbacks.
- *
- * \param listen_callback A function pointer to a listen callback function.
- * A listen callback function should not be already set when this function
- * is called. A NULL value removes the existing listen callback function
- * if any.
- *
- * \param cancel_callback A function pointer to a cancel callback function.
- * A cancel callback function should not be already set when this function
- * is called. A NULL value removes the existing cancel callback function
- * if any.
- *
- * \return Success if the callbacks were added. Otherwise, returns an
- * error handle.
- */
-DART_EXPORT char* Dart_SetServiceStreamCallbacks(
- Dart_ServiceStreamListenCallback listen_callback,
- Dart_ServiceStreamCancelCallback cancel_callback);
-
-/**
- * Sends a data event to clients of the VM Service.
- *
- * A data event is used to pass an array of bytes to subscribed VM
- * Service clients. For example, in the standalone embedder, this is
- * function used to provide WriteEvents on the Stdout and Stderr
- * streams.
- *
- * If the embedder passes in a stream id for which no client is
- * subscribed, then the event is ignored.
- *
- * \param stream_id The id of the stream on which to post the event.
- *
- * \param event_kind A string identifying what kind of event this is.
- * For example, 'WriteEvent'.
- *
- * \param bytes A pointer to an array of bytes.
- *
- * \param bytes_length The length of the byte array.
- *
- * \return NULL if the arguments are well formed. Otherwise, returns an
- * error string. The caller is responsible for freeing the error message.
- */
-DART_EXPORT char* Dart_ServiceSendDataEvent(const char* stream_id,
- const char* event_kind,
- const uint8_t* bytes,
- intptr_t bytes_length);
-
-/*
- * ========
- * Reload support
- * ========
- *
- * These functions are used to implement reloading in the Dart VM.
- * This is an experimental feature, so embedders should be prepared
- * for these functions to change.
- */
-
-/**
- * A callback which determines whether the file at some url has been
- * modified since some time. If the file cannot be found, true should
- * be returned.
- */
-typedef bool (*Dart_FileModifiedCallback)(const char* url, int64_t since);
-
-DART_EXPORT char* Dart_SetFileModifiedCallback(
- Dart_FileModifiedCallback file_modified_callback);
-
-/**
- * Returns true if isolate is currently reloading.
- */
-DART_EXPORT bool Dart_IsReloading();
-
-/*
- * ========
- * Timeline
- * ========
- */
-
-/**
- * Enable tracking of specified timeline category. This is operational
- * only when systrace timeline functionality is turned on.
- *
- * \param categories A comma separated list of categories that need to
- * be enabled, the categories are
- * "all" : All categories
- * "API" - Execution of Dart C API functions
- * "Compiler" - Execution of Dart JIT compiler
- * "CompilerVerbose" - More detailed Execution of Dart JIT compiler
- * "Dart" - Execution of Dart code
- * "Debugger" - Execution of Dart debugger
- * "Embedder" - Execution of Dart embedder code
- * "GC" - Execution of Dart Garbage Collector
- * "Isolate" - Dart Isolate lifecycle execution
- * "VM" - Execution in Dart VM runtime code
- * "" - None
- *
- * When "all" is specified all the categories are enabled.
- * When a comma separated list of categories is specified, the categories
- * that are specified will be enabled and the rest will be disabled.
- * When "" is specified all the categories are disabled.
- * The category names are case sensitive.
- * eg: Dart_EnableTimelineCategory("all");
- * Dart_EnableTimelineCategory("GC,API,Isolate");
- * Dart_EnableTimelineCategory("GC,Debugger,Dart");
- *
- * \return True if the categories were successfully enabled, False otherwise.
- */
-DART_EXPORT bool Dart_SetEnabledTimelineCategory(const char* categories);
-
-/**
- * Returns a timestamp in microseconds. This timestamp is suitable for
- * passing into the timeline system, and uses the same monotonic clock
- * as dart:developer's Timeline.now.
- *
- * \return A timestamp that can be passed to the timeline system.
- */
-DART_EXPORT int64_t Dart_TimelineGetMicros();
-
-/**
- * Returns a raw timestamp in from the monotonic clock.
- *
- * \return A raw timestamp from the monotonic clock.
- */
-DART_EXPORT int64_t Dart_TimelineGetTicks();
-
-/**
- * Returns the frequency of the monotonic clock.
- *
- * \return The frequency of the monotonic clock.
- */
-DART_EXPORT int64_t Dart_TimelineGetTicksFrequency();
-
-typedef enum {
- Dart_Timeline_Event_Begin, // Phase = 'B'.
- Dart_Timeline_Event_End, // Phase = 'E'.
- Dart_Timeline_Event_Instant, // Phase = 'i'.
- Dart_Timeline_Event_Duration, // Phase = 'X'.
- Dart_Timeline_Event_Async_Begin, // Phase = 'b'.
- Dart_Timeline_Event_Async_End, // Phase = 'e'.
- Dart_Timeline_Event_Async_Instant, // Phase = 'n'.
- Dart_Timeline_Event_Counter, // Phase = 'C'.
- Dart_Timeline_Event_Flow_Begin, // Phase = 's'.
- Dart_Timeline_Event_Flow_Step, // Phase = 't'.
- Dart_Timeline_Event_Flow_End, // Phase = 'f'.
-} Dart_Timeline_Event_Type;
-
-/**
- * Add a timeline event to the embedder stream.
- *
- * DEPRECATED: this function will be removed in Dart SDK v3.2.
- *
- * \param label The name of the event. Its lifetime must extend at least until
- * Dart_Cleanup.
- * \param timestamp0 The first timestamp of the event.
- * \param timestamp1_or_id When reporting an event of type
- * |Dart_Timeline_Event_Duration|, the second (end) timestamp of the event
- * should be passed through |timestamp1_or_id|. When reporting an event of
- * type |Dart_Timeline_Event_Async_Begin|, |Dart_Timeline_Event_Async_End|,
- * or |Dart_Timeline_Event_Async_Instant|, the async ID associated with the
- * event should be passed through |timestamp1_or_id|. When reporting an
- * event of type |Dart_Timeline_Event_Flow_Begin|,
- * |Dart_Timeline_Event_Flow_Step|, or |Dart_Timeline_Event_Flow_End|, the
- * flow ID associated with the event should be passed through
- * |timestamp1_or_id|. When reporting an event of type
- * |Dart_Timeline_Event_Begin| or |Dart_Timeline_Event_End|, the event ID
- * associated with the event should be passed through |timestamp1_or_id|.
- * Note that this event ID will only be used by the MacOS recorder. The
- * argument to |timestamp1_or_id| will not be used when reporting events of
- * other types.
- * \param argument_count The number of argument names and values.
- * \param argument_names An array of names of the arguments. The lifetime of the
- * names must extend at least until Dart_Cleanup. The array may be reclaimed
- * when this call returns.
- * \param argument_values An array of values of the arguments. The values and
- * the array may be reclaimed when this call returns.
- */
-DART_EXPORT void Dart_TimelineEvent(const char* label,
- int64_t timestamp0,
- int64_t timestamp1_or_id,
- Dart_Timeline_Event_Type type,
- intptr_t argument_count,
- const char** argument_names,
- const char** argument_values);
-
-/**
- * Add a timeline event to the embedder stream.
- *
- * Note regarding flow events: events must be associated with flow IDs in two
- * different ways to allow flow events to be serialized correctly in both
- * Chrome's JSON trace event format and Perfetto's proto trace format. Events
- * of type |Dart_Timeline_Event_Flow_Begin|, |Dart_Timeline_Event_Flow_Step|,
- * and |Dart_Timeline_Event_Flow_End| must be reported to support serialization
- * in Chrome's trace format. The |flow_ids| argument must be supplied when
- * reporting events of type |Dart_Timeline_Event_Begin|,
- * |Dart_Timeline_Event_Duration|, |Dart_Timeline_Event_Instant|,
- * |Dart_Timeline_Event_Async_Begin|, and |Dart_Timeline_Event_Async_Instant| to
- * support serialization in Perfetto's proto format.
- *
- * \param label The name of the event. Its lifetime must extend at least until
- * Dart_Cleanup.
- * \param timestamp0 The first timestamp of the event.
- * \param timestamp1_or_id When reporting an event of type
- * |Dart_Timeline_Event_Duration|, the second (end) timestamp of the event
- * should be passed through |timestamp1_or_id|. When reporting an event of
- * type |Dart_Timeline_Event_Async_Begin|, |Dart_Timeline_Event_Async_End|,
- * or |Dart_Timeline_Event_Async_Instant|, the async ID associated with the
- * event should be passed through |timestamp1_or_id|. When reporting an
- * event of type |Dart_Timeline_Event_Flow_Begin|,
- * |Dart_Timeline_Event_Flow_Step|, or |Dart_Timeline_Event_Flow_End|, the
- * flow ID associated with the event should be passed through
- * |timestamp1_or_id|. When reporting an event of type
- * |Dart_Timeline_Event_Begin| or |Dart_Timeline_Event_End|, the event ID
- * associated with the event should be passed through |timestamp1_or_id|.
- * Note that this event ID will only be used by the MacOS recorder. The
- * argument to |timestamp1_or_id| will not be used when reporting events of
- * other types.
- * \param flow_id_count The number of flow IDs associated with this event.
- * \param flow_ids An array of flow IDs associated with this event. The array
- * may be reclaimed when this call returns.
- * \param argument_count The number of argument names and values.
- * \param argument_names An array of names of the arguments. The lifetime of the
- * names must extend at least until Dart_Cleanup. The array may be reclaimed
- * when this call returns.
- * \param argument_values An array of values of the arguments. The values and
- * the array may be reclaimed when this call returns.
- */
-DART_EXPORT void Dart_RecordTimelineEvent(const char* label,
- int64_t timestamp0,
- int64_t timestamp1_or_id,
- intptr_t flow_id_count,
- const int64_t* flow_ids,
- Dart_Timeline_Event_Type type,
- intptr_t argument_count,
- const char** argument_names,
- const char** argument_values);
-
-/**
- * Associates a name with the current thread. This name will be used to name
- * threads in the timeline. Can only be called after a call to Dart_Initialize.
- *
- * \param name The name of the thread.
- */
-DART_EXPORT void Dart_SetThreadName(const char* name);
-
-typedef struct {
- const char* name;
- const char* value;
-} Dart_TimelineRecorderEvent_Argument;
-
-#define DART_TIMELINE_RECORDER_CURRENT_VERSION (0x00000002)
-
-typedef struct {
- /* Set to DART_TIMELINE_RECORDER_CURRENT_VERSION */
- int32_t version;
-
- /* The event's type / phase. */
- Dart_Timeline_Event_Type type;
-
- /* The event's timestamp according to the same clock as
- * Dart_TimelineGetMicros. For a duration event, this is the beginning time.
- */
- int64_t timestamp0;
-
- /**
- * For a duration event, this is the end time. For an async event, this is the
- * async ID. For a flow event, this is the flow ID. For a begin or end event,
- * this is the event ID (which is only referenced by the MacOS recorder).
- */
- int64_t timestamp1_or_id;
-
- /* The current isolate of the event, as if by Dart_GetMainPortId, or
- * ILLEGAL_PORT if the event had no current isolate. */
- Dart_Port isolate;
-
- /* The current isolate group of the event, as if by
- * Dart_CurrentIsolateGroupId, or ILLEGAL_PORT if the event had no current
- * isolate group. */
- Dart_IsolateGroupId isolate_group;
-
- /* The callback data associated with the isolate if any. */
- void* isolate_data;
-
- /* The callback data associated with the isolate group if any. */
- void* isolate_group_data;
-
- /* The name / label of the event. */
- const char* label;
-
- /* The stream / category of the event. */
- const char* stream;
-
- intptr_t argument_count;
- Dart_TimelineRecorderEvent_Argument* arguments;
-} Dart_TimelineRecorderEvent;
-
-/**
- * Callback provided by the embedder to handle the completion of timeline
- * events.
- *
- * \param event A timeline event that has just been completed. The VM keeps
- * ownership of the event and any field in it (i.e., the embedder should copy
- * any values it needs after the callback returns).
- */
-typedef void (*Dart_TimelineRecorderCallback)(
- Dart_TimelineRecorderEvent* event);
-
-/**
- * Register a `Dart_TimelineRecorderCallback` to be called as timeline events
- * are completed.
- *
- * The callback will be invoked without a current isolate.
- *
- * The callback will be invoked on the thread completing the event. Because
- * `Dart_TimelineEvent` may be called by any thread, the callback may be called
- * on any thread.
- *
- * The callback may be invoked at any time after `Dart_Initialize` is called and
- * before `Dart_Cleanup` returns.
- *
- * If multiple callbacks are registered, only the last callback registered
- * will be remembered. Providing a NULL callback will clear the registration
- * (i.e., a NULL callback produced a no-op instead of a crash).
- *
- * Setting a callback is insufficient to receive events through the callback. The
- * VM flag `timeline_recorder` must also be set to `callback`.
- */
-DART_EXPORT void Dart_SetTimelineRecorderCallback(
- Dart_TimelineRecorderCallback callback);
-
-/*
- * =======
- * Metrics
- * =======
- */
-
-/**
- * Return metrics gathered for the VM and individual isolates.
- */
-DART_EXPORT int64_t
-Dart_IsolateGroupHeapOldUsedMetric(Dart_IsolateGroup group); // Byte
-DART_EXPORT int64_t
-Dart_IsolateGroupHeapOldCapacityMetric(Dart_IsolateGroup group); // Byte
-DART_EXPORT int64_t
-Dart_IsolateGroupHeapOldExternalMetric(Dart_IsolateGroup group); // Byte
-DART_EXPORT int64_t
-Dart_IsolateGroupHeapNewUsedMetric(Dart_IsolateGroup group); // Byte
-DART_EXPORT int64_t
-Dart_IsolateGroupHeapNewCapacityMetric(Dart_IsolateGroup group); // Byte
-DART_EXPORT int64_t
-Dart_IsolateGroupHeapNewExternalMetric(Dart_IsolateGroup group); // Byte
-
-/*
- * ========
- * UserTags
- * ========
- */
-
-/*
- * Gets the current isolate's currently set UserTag instance.
- *
- * \return The currently set UserTag instance.
- */
-DART_EXPORT Dart_Handle Dart_GetCurrentUserTag();
-
-/*
- * Gets the current isolate's default UserTag instance.
- *
- * \return The default UserTag with label 'Default'
- */
-DART_EXPORT Dart_Handle Dart_GetDefaultUserTag();
-
-/*
- * Creates a new UserTag instance.
- *
- * \param label The name of the new UserTag.
- *
- * \return The newly created UserTag instance or an error handle.
- */
-DART_EXPORT Dart_Handle Dart_NewUserTag(const char* label);
-
-/*
- * Updates the current isolate's UserTag to a new value.
- *
- * \param user_tag The UserTag to be set as the current UserTag.
- *
- * \return The previously set UserTag instance or an error handle.
- */
-DART_EXPORT Dart_Handle Dart_SetCurrentUserTag(Dart_Handle user_tag);
-
-/*
- * Returns the label of a given UserTag instance.
- *
- * \param user_tag The UserTag from which the label will be retrieved.
- *
- * \return The UserTag's label. NULL if the user_tag is invalid. The caller is
- * responsible for freeing the returned label.
- */
-DART_EXPORT DART_WARN_UNUSED_RESULT char* Dart_GetUserTagLabel(
- Dart_Handle user_tag);
-
-/*
- * =======
- * Heap Snapshot
- * =======
- */
-
-/**
- * Callback provided by the caller of `Dart_WriteHeapSnapshot` which is
- * used to write out chunks of the requested heap snapshot.
- *
- * \param context An opaque context which was passed to `Dart_WriteHeapSnapshot`
- * together with this callback.
- *
- * \param buffer Pointer to the buffer containing a chunk of the snapshot.
- * The callback owns the buffer and needs to `free` it.
- *
- * \param size Number of bytes in the `buffer` to be written.
- *
- * \param is_last Set to `true` for the last chunk. The callback will not
- * be invoked again after it was invoked once with `is_last` set to `true`.
- */
-typedef void (*Dart_HeapSnapshotWriteChunkCallback)(void* context,
- uint8_t* buffer,
- intptr_t size,
- bool is_last);
-
-/**
- * Generate heap snapshot of the current isolate group and stream it into the
- * given `callback`. VM would produce snapshot in chunks and send these chunks
- * one by one back to the embedder by invoking the provided `callback`.
- *
- * This API enables embedder to stream snapshot into a file or socket without
- * allocating a buffer to hold the whole snapshot in memory.
- *
- * The isolate group will be paused for the duration of this operation.
- *
- * \param write Callback used to write chunks of the heap snapshot.
- *
- * \param context Opaque context which would be passed on each invocation of
- * `write` callback.
- *
- * \returns `nullptr` if the operation is successful otherwise error message.
- * Caller owns error message string and needs to `free` it.
- */
-DART_EXPORT char* Dart_WriteHeapSnapshot(
- Dart_HeapSnapshotWriteChunkCallback write,
- void* context);
-
-#endif // RUNTIME_INCLUDE_DART_TOOLS_API_H_
diff --git a/core/dart-bridge/include/dart_version.h b/core/dart-bridge/include/dart_version.h
deleted file mode 100644
index e2d3651..0000000
--- a/core/dart-bridge/include/dart_version.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#ifndef RUNTIME_INCLUDE_DART_VERSION_H_
-#define RUNTIME_INCLUDE_DART_VERSION_H_
-
-// On breaking changes the major version is increased.
-// On backwards compatible changes the minor version is increased.
-// The versioning covers the symbols exposed in dart_api_dl.h
-#define DART_API_DL_MAJOR_VERSION 2
-#define DART_API_DL_MINOR_VERSION 3
-
-#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */
diff --git a/core/dart-bridge/include/internal/dart_api_dl_impl.h b/core/dart-bridge/include/internal/dart_api_dl_impl.h
deleted file mode 100644
index e4a5689..0000000
--- a/core/dart-bridge/include/internal/dart_api_dl_impl.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
- * for details. All rights reserved. Use of this source code is governed by a
- * BSD-style license that can be found in the LICENSE file.
- */
-
-#ifndef RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_
-#define RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_
-
-typedef struct {
- const char* name;
- void (*function)(void);
-} DartApiEntry;
-
-typedef struct {
- const int major;
- const int minor;
- const DartApiEntry* const functions;
-} DartApi;
-
-#endif /* RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ */ /* NOLINT */
diff --git a/core/dart-bridge/lib.go b/core/dart-bridge/lib.go
deleted file mode 100644
index 36847f1..0000000
--- a/core/dart-bridge/lib.go
+++ /dev/null
@@ -1,42 +0,0 @@
-//go:build cgo
-
-package dart_bridge
-
-/*
-#include
-#include "stdint.h"
-#include "include/dart_api_dl.h"
-#include "include/dart_api_dl.c"
-#include "include/dart_native_api.h"
-
-bool GoDart_PostCObject(Dart_Port_DL port, Dart_CObject* obj) {
- return Dart_PostCObject_DL(port, obj);
-}
-*/
-import "C"
-import (
- "fmt"
- "unsafe"
-)
-
-func InitDartApi(api unsafe.Pointer) {
- if C.Dart_InitializeApiDL(api) != 0 {
- panic("failed to create dart bridge")
- } else {
- fmt.Println("Dart Api DL is initialized")
- }
-}
-
-func SendToPort(port int64, msg string) bool {
- var obj C.Dart_CObject
- obj._type = C.Dart_CObject_kString
- msgString := C.CString(msg)
- defer C.free(unsafe.Pointer(msgString))
- ptr := unsafe.Pointer(&obj.value[0])
- *(**C.char)(ptr) = msgString
- isSuccess := C.GoDart_PostCObject(C.Dart_Port_DL(port), &obj)
- if !isSuccess {
- return false
- }
- return true
-}
diff --git a/core/dart-bridge/lib_common.go b/core/dart-bridge/lib_common.go
deleted file mode 100644
index f347549..0000000
--- a/core/dart-bridge/lib_common.go
+++ /dev/null
@@ -1,7 +0,0 @@
-//go:build !cgo
-
-package dart_bridge
-
-func SendToPort(port int64, msg string) bool {
- return false
-}
diff --git a/core/go.mod b/core/go.mod
index 992a2bc..c788b8f 100644
--- a/core/go.mod
+++ b/core/go.mod
@@ -17,18 +17,17 @@ require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
- github.com/cloudflare/circl v1.3.7 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/ebitengine/purego v0.8.3 // indirect
- github.com/enfein/mieru/v3 v3.13.0 // indirect
+ github.com/enfein/mieru/v3 v3.16.1 // indirect
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gaukas/godicttls v0.0.4 // indirect
- github.com/go-chi/chi/v5 v5.2.1 // indirect
+ github.com/go-chi/chi/v5 v5.2.2 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
@@ -51,26 +50,26 @@ require (
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // indirect
github.com/metacubex/bart v0.20.5 // indirect
- github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 // indirect
+ github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b // indirect
github.com/metacubex/chacha v0.1.5 // indirect
github.com/metacubex/fswatch v0.1.1 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
- github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639 // indirect
+ github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c // indirect
github.com/metacubex/randv2 v0.2.0 // indirect
- github.com/metacubex/sing v0.5.4-0.20250605054047-54dc6097da29 // indirect
+ github.com/metacubex/sing v0.5.4 // indirect
github.com/metacubex/sing-mux v0.3.2 // indirect
- github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f // indirect
- github.com/metacubex/sing-shadowsocks v0.2.11-0.20250621023810-0e9ef9dd0c92 // indirect
- github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d // indirect
+ github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb // indirect
+ github.com/metacubex/sing-shadowsocks v0.2.11 // indirect
+ github.com/metacubex/sing-shadowsocks2 v0.2.5 // indirect
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect
- github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8 // indirect
- github.com/metacubex/sing-vmess v0.2.2 // indirect
+ github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 // indirect
+ github.com/metacubex/sing-vmess v0.2.3 // indirect
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee // indirect
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect
- github.com/metacubex/utls v1.7.4-0.20250610022031-808d767c8c73 // indirect
+ github.com/metacubex/utls v1.8.0 // indirect
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
@@ -80,11 +79,10 @@ require (
github.com/oschwald/maxminddb-golang v1.12.0 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
- github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/sagernet/cors v1.2.1 // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
- github.com/samber/lo v1.50.0 // indirect
+ github.com/samber/lo v1.51.0 // indirect
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect
diff --git a/core/go.sum b/core/go.sum
index 5334aac..b8cf649 100644
--- a/core/go.sum
+++ b/core/go.sum
@@ -17,8 +17,6 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
-github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc=
github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -28,8 +26,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
-github.com/enfein/mieru/v3 v3.13.0 h1:eGyxLGkb+lut9ebmx+BGwLJ5UMbEc/wGIYO0AXEKy98=
-github.com/enfein/mieru/v3 v3.13.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
+github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
+github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -43,8 +41,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
-github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
-github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
+github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
+github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
@@ -84,7 +82,6 @@ github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
@@ -99,8 +96,8 @@ github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI=
github.com/metacubex/bart v0.20.5 h1:XkgLZ17QxfxkqKdGsojoM2Zu01mmHyyQSFzt2/calTM=
github.com/metacubex/bart v0.20.5/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
-github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 h1:oBowHVKZycNtAFbZ6avaCSZJYeme2Nrj+4RpV2cNJig=
-github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399/go.mod h1:4xcieuIK+M4bGQmQYZVqEaIYqjS1ahO4kXG7EmDgEro=
+github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b h1:j7dadXD8I2KTmMt8jg1JcaP1ANL3JEObJPdANKcSYPY=
+github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b/go.mod h1:+WmP0VJZDkDszvpa83HzfUp6QzARl/IKkMorH4+nODw=
github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M=
github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU=
@@ -111,42 +108,41 @@ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
-github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639 h1:L+1brQNzBhCCxWlicwfK1TlceemCRmrDE4HmcVHc29w=
-github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639/go.mod h1:Kc6h++Q/zf3AxcUCevJhJwgrskJumv+pZdR8g/E/10k=
+github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c h1:ABQzmOaZddM3q0OYeoZEc0XF+KW+dUdPNvY/c5rsunI=
+github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c/go.mod h1:eWlAK3zsKI0P8UhYpXlIsl3mtW4D6MpMNuYLIu8CKWI=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
-github.com/metacubex/sing v0.5.4-0.20250605054047-54dc6097da29 h1:SD9q025FNTaepuFXFOKDhnGLVu6PQYChBvw2ZYPXeLo=
-github.com/metacubex/sing v0.5.4-0.20250605054047-54dc6097da29/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
+github.com/metacubex/sing v0.5.4 h1:a4kAOZmF+OXosbzPEcrSc5QD35/ex+MNuZsrcuWskHk=
+github.com/metacubex/sing v0.5.4/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
-github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f h1:mP3vIm+9hRFI0C0Vl3pE0NESF/L85FDbuB0tGgUii6I=
-github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f/go.mod h1:JPTpf7fpnojsSuwRJExhSZSy63pVbp3VM39+zj+sAJM=
-github.com/metacubex/sing-shadowsocks v0.2.11-0.20250621023810-0e9ef9dd0c92 h1:Y9ebcKya6ow7VHoESCN5+l4zZvg5eaL2IhI5LLCQxQA=
-github.com/metacubex/sing-shadowsocks v0.2.11-0.20250621023810-0e9ef9dd0c92/go.mod h1:/squZ38pXrYjqtg8qn+joVvwbpGNYQNp8yxKsMVbCto=
-github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d h1:Ey3A1tA8lVkRbK1FDmwuWj/57Nr8JMdpoVqe45mFzJg=
-github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d/go.mod h1:+ukTd0OPFglT3bnKAYTJWYPbuox6HYNXE235r5tHdUk=
+github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb h1:U/m3h8lp/j7i8zFgfvScLdZa1/Y8dd74oO7iZaQq80s=
+github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb/go.mod h1:B60FxaPHjR1SeQB0IiLrgwgvKsaoASfOWdiqhLjmMGA=
+github.com/metacubex/sing-shadowsocks v0.2.11 h1:p2NGNOdF95e6XvdDKipLj1FRRqR8dnbfC/7pw2CCTlw=
+github.com/metacubex/sing-shadowsocks v0.2.11/go.mod h1:bT1PCTV316zFnlToRMk5zt9HmIQYRBveiT71mplYPfc=
+github.com/metacubex/sing-shadowsocks2 v0.2.5 h1:MnPn0hbcDkSJt6TlpI15XImHKK6IqaOwBUGPKyMnJnE=
+github.com/metacubex/sing-shadowsocks2 v0.2.5/go.mod h1:Zyh+rAQRyevYfG/COCvDs1c/YMhGqCuknn7QrGmoQIw=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
-github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8 h1:4zWKqxTx75TbfW2EmlQ3hxM6RTRg2PYOAVMCnU4I61I=
-github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
-github.com/metacubex/sing-vmess v0.2.2 h1:nG6GIKF1UOGmlzs+BIetdGHkFZ20YqFVIYp5Htqzp+4=
-github.com/metacubex/sing-vmess v0.2.2/go.mod h1:CVDNcdSLVYFgTHQlubr88d8CdqupAUDqLjROos+H9xk=
+github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 h1:YYpc60UZE2G0pUeHbRw9erDrUDZrPQy8QzWFqA3kHsk=
+github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
+github.com/metacubex/sing-vmess v0.2.3 h1:QKLdIk5A2FcR3Y7m2/JO1XhfzgDA8tF4W9/ffsH9opo=
+github.com/metacubex/sing-vmess v0.2.3/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
-github.com/metacubex/utls v1.7.4-0.20250610022031-808d767c8c73 h1:HWKsf92BqLYqugATFIJ3hYiEBZ7JF6AoqyvqF39afuI=
-github.com/metacubex/utls v1.7.4-0.20250610022031-808d767c8c73/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
+github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
+github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU=
github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4=
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
@@ -166,16 +162,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
-github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
-github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
-github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
+github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
+github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8=
@@ -272,8 +266,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/core/hub.go b/core/hub.go
index f8a0462..b40e6bc 100644
--- a/core/hub.go
+++ b/core/hub.go
@@ -2,7 +2,6 @@ package main
import (
"context"
- "core/state"
"encoding/json"
"fmt"
"github.com/metacubex/mihomo/adapter"
@@ -68,7 +67,7 @@ func handleGetIsInit() bool {
return isInit
}
-func handleForceGc() {
+func handleForceGC() {
go func() {
log.Infoln("[APP] request force GC")
runtime.GC()
@@ -136,8 +135,8 @@ func handleChangeProxy(data string, fn func(string string)) {
}()
}
-func handleGetTraffic() string {
- up, down := statistic.DefaultManager.Current(state.CurrentState.OnlyStatisticsProxy)
+func handleGetTraffic(onlyStatisticsProxy bool) string {
+ up, down := statistic.DefaultManager.Current(onlyStatisticsProxy)
traffic := map[string]int64{
"up": up,
"down": down,
@@ -150,8 +149,8 @@ func handleGetTraffic() string {
return string(data)
}
-func handleGetTotalTraffic() string {
- up, down := statistic.DefaultManager.Total(state.CurrentState.OnlyStatisticsProxy)
+func handleGetTotalTraffic(onlyStatisticsProxy bool) string {
+ up, down := statistic.DefaultManager.Total(onlyStatisticsProxy)
traffic := map[string]int64{
"up": up,
"down": down,
@@ -374,6 +373,15 @@ func handleSideLoadExternalProvider(providerName string, data []byte, fn func(va
}()
}
+func handleSuspend(suspended bool) bool {
+ if suspended {
+ tunnel.OnSuspend()
+ } else {
+ tunnel.OnRunning()
+ }
+ return true
+}
+
func handleStartLog() {
if logSubscriber != nil {
log.UnSubscribe(logSubscriber)
@@ -420,10 +428,6 @@ func handleGetMemory(fn func(value string)) {
}()
}
-func handleSetState(params string) {
- _ = json.Unmarshal([]byte(params), state.CurrentState)
-}
-
func handleGetConfig(path string) (*config.RawConfig, error) {
bytes, err := readFile(path)
if err != nil {
diff --git a/core/lib.go b/core/lib.go
index b5e6229..123e6bd 100644
--- a/core/lib.go
+++ b/core/lib.go
@@ -6,37 +6,155 @@ package main
#include
*/
import "C"
+
import (
- bridge "core/dart-bridge"
+ "context"
+ "core/platform"
+ t "core/tun"
"encoding/json"
+ "errors"
+ "github.com/metacubex/mihomo/component/dialer"
+ "github.com/metacubex/mihomo/component/process"
+ "github.com/metacubex/mihomo/constant"
+ "github.com/metacubex/mihomo/dns"
+ "github.com/metacubex/mihomo/listener/sing_tun"
+ "github.com/metacubex/mihomo/log"
+ "golang.org/x/sync/semaphore"
+ "net"
+ "strings"
+ "sync"
+ "syscall"
"unsafe"
)
-var messagePort int64 = -1
+var messageCallback unsafe.Pointer
-//export initNativeApiBridge
-func initNativeApiBridge(api unsafe.Pointer) {
- bridge.InitDartApi(api)
+type TunHandler struct {
+ listener *sing_tun.Listener
+ callback unsafe.Pointer
+
+ limit *semaphore.Weighted
}
-//export attachMessagePort
-func attachMessagePort(mPort C.longlong) {
- messagePort = int64(mPort)
+func (th *TunHandler) start(fd int, address, dns string) {
+ _ = th.limit.Acquire(context.TODO(), 4)
+ defer th.limit.Release(4)
+ th.initHook()
+ tunListener := t.Start(fd, currentConfig.General.Tun.Device, currentConfig.General.Tun.Stack, address, dns)
+ if tunListener != nil {
+ log.Infoln("TUN address: %v", tunListener.Address())
+ th.listener = tunListener
+ return
+ }
+ th.clear()
}
-//export getTraffic
-func getTraffic() *C.char {
- return C.CString(handleGetTraffic())
+func (th *TunHandler) close() {
+ _ = th.limit.Acquire(context.TODO(), 4)
+ defer th.limit.Release(4)
+ th.clear()
}
-//export getTotalTraffic
-func getTotalTraffic() *C.char {
- return C.CString(handleGetTotalTraffic())
+func (th *TunHandler) clear() {
+ th.removeHook()
+ if th.listener != nil {
+ _ = th.listener.Close()
+ }
+ if th.callback != nil {
+ releaseObject(th.callback)
+ }
+ th.callback = nil
+ th.listener = nil
}
-//export freeCString
-func freeCString(s *C.char) {
- C.free(unsafe.Pointer(s))
+func (th *TunHandler) handleProtect(fd int) {
+ _ = th.limit.Acquire(context.Background(), 1)
+ defer th.limit.Release(1)
+
+ if th.listener == nil {
+ return
+ }
+
+ protect(th.callback, fd)
+}
+
+func (th *TunHandler) handleResolveProcess(source, target net.Addr) string {
+ _ = th.limit.Acquire(context.Background(), 1)
+ defer th.limit.Release(1)
+
+ if th.listener == nil {
+ return ""
+ }
+ var protocol int
+ uid := -1
+ switch source.Network() {
+ case "udp", "udp4", "udp6":
+ protocol = syscall.IPPROTO_UDP
+ case "tcp", "tcp4", "tcp6":
+ protocol = syscall.IPPROTO_TCP
+ }
+ if version < 29 {
+ uid = platform.QuerySocketUidFromProcFs(source, target)
+ }
+ return resolveProcess(th.callback, protocol, source.String(), target.String(), uid)
+}
+
+func (th *TunHandler) initHook() {
+ dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error {
+ if platform.ShouldBlockConnection() {
+ return errBlocked
+ }
+ return conn.Control(func(fd uintptr) {
+ tunHandler.handleProtect(int(fd))
+ })
+ }
+ process.DefaultPackageNameResolver = func(metadata *constant.Metadata) (string, error) {
+ src, dst := metadata.RawSrcAddr, metadata.RawDstAddr
+ if src == nil || dst == nil {
+ return "", process.ErrInvalidNetwork
+ }
+ return tunHandler.handleResolveProcess(src, dst), nil
+ }
+}
+
+func (th *TunHandler) removeHook() {
+ dialer.DefaultSocketHook = nil
+ process.DefaultPackageNameResolver = nil
+}
+
+var (
+ tunLock sync.Mutex
+ errBlocked = errors.New("blocked")
+ tunHandler *TunHandler
+)
+
+func handleStopTun() {
+ tunLock.Lock()
+ defer tunLock.Unlock()
+ if tunHandler != nil {
+ tunHandler.close()
+ }
+}
+
+func handleStartTun(callback unsafe.Pointer, fd int, address, dns string) {
+ handleStopTun()
+ tunLock.Lock()
+ defer tunLock.Unlock()
+ if fd != 0 {
+ tunHandler = &TunHandler{
+ callback: callback,
+ limit: semaphore.NewWeighted(4),
+ }
+ tunHandler.start(fd, address, dns)
+ }
+}
+
+func handleUpdateDns(value string) {
+ go func() {
+ log.Infoln("[DNS] updateDns %s", value)
+ dns.UpdateSystemDNS(strings.Split(value, ","))
+ dns.FlushCacheWithDefaultResolver()
+ }()
}
func (result ActionResult) send() {
@@ -44,59 +162,92 @@ func (result ActionResult) send() {
if err != nil {
return
}
- bridge.SendToPort(result.Port, string(data))
+ invokeResult(result.callback, string(data))
+ if result.Method != messageMethod {
+ releaseObject(result.callback)
+ }
+}
+
+func nextHandle(action *Action, result ActionResult) bool {
+ switch action.Method {
+ case updateDnsMethod:
+ data := action.Data.(string)
+ handleUpdateDns(data)
+ result.success(true)
+ return true
+ }
+ return false
}
//export invokeAction
-func invokeAction(paramsChar *C.char, port C.longlong) {
- params := C.GoString(paramsChar)
- i := int64(port)
+func invokeAction(callback unsafe.Pointer, paramsChar *C.char) {
+ params := parseCString(paramsChar)
var action = &Action{}
err := json.Unmarshal([]byte(params), action)
if err != nil {
- bridge.SendToPort(i, err.Error())
+ invokeResult(callback, err.Error())
return
}
result := ActionResult{
- Id: action.Id,
- Method: action.Method,
- Port: i,
+ Id: action.Id,
+ Method: action.Method,
+ callback: callback,
}
go handleAction(action, result)
}
+//export startTUN
+func startTUN(callback unsafe.Pointer, fd C.int, addressChar, dnsChar *C.char) bool {
+ handleStartTun(callback, int(fd), parseCString(addressChar), parseCString(dnsChar))
+ return true
+}
+
+//export setMessageCallback
+func setMessageCallback(callback unsafe.Pointer) {
+ if messageCallback != nil {
+ releaseObject(messageCallback)
+ }
+ messageCallback = callback
+}
+
+//export getTotalTraffic
+func getTotalTraffic(onlyStatisticsProxy bool) *C.char {
+ return C.CString(handleGetTotalTraffic(onlyStatisticsProxy))
+}
+
+//export getTraffic
+func getTraffic(onlyStatisticsProxy bool) *C.char {
+ return C.CString(handleGetTraffic(onlyStatisticsProxy))
+}
+
func sendMessage(message Message) {
- if messagePort == -1 {
+ if messageCallback == nil {
return
}
result := ActionResult{
- Method: messageMethod,
- Port: messagePort,
- Data: message,
+ Method: messageMethod,
+ callback: messageCallback,
+ Data: message,
}
result.send()
}
-//export getConfig
-func getConfig(s *C.char) *C.char {
- path := C.GoString(s)
- config, err := handleGetConfig(path)
- if err != nil {
- return C.CString("")
- }
- marshal, err := json.Marshal(config)
- if err != nil {
- return C.CString("")
- }
- return C.CString(string(marshal))
+//export stopTun
+func stopTun() {
+ handleStopTun()
}
-//export startListener
-func startListener() {
- handleStartListener()
+//export suspend
+func suspend(suspended bool) {
+ handleSuspend(suspended)
}
-//export stopListener
-func stopListener() {
- handleStopListener()
+//export forceGC
+func forceGC() {
+ handleForceGC()
+}
+
+//export updateDns
+func updateDns(s *C.char) {
+ handleUpdateDns(parseCString(s))
}
diff --git a/core/lib_android.go b/core/lib_android.go
deleted file mode 100644
index 00b3b35..0000000
--- a/core/lib_android.go
+++ /dev/null
@@ -1,267 +0,0 @@
-//go:build android && cgo
-
-package main
-
-import "C"
-import (
- "context"
- bridge "core/dart-bridge"
- "core/platform"
- "core/state"
- t "core/tun"
- "encoding/json"
- "errors"
- "fmt"
- "github.com/metacubex/mihomo/component/dialer"
- "github.com/metacubex/mihomo/component/process"
- "github.com/metacubex/mihomo/constant"
- "github.com/metacubex/mihomo/dns"
- "github.com/metacubex/mihomo/listener/sing_tun"
- "github.com/metacubex/mihomo/log"
- "golang.org/x/sync/semaphore"
- "net"
- "strconv"
- "strings"
- "sync"
- "syscall"
- "time"
- "unsafe"
-)
-
-type TunHandler struct {
- listener *sing_tun.Listener
- callback unsafe.Pointer
-
- limit *semaphore.Weighted
-}
-
-func (t *TunHandler) close() {
- _ = t.limit.Acquire(context.TODO(), 4)
- defer t.limit.Release(4)
- removeTunHook()
- if t.listener != nil {
- _ = t.listener.Close()
- }
-
- if t.callback != nil {
- releaseObject(t.callback)
- }
- t.callback = nil
- t.listener = nil
-}
-
-func (t *TunHandler) handleProtect(fd int) {
- _ = t.limit.Acquire(context.Background(), 1)
- defer t.limit.Release(1)
-
- if t.listener == nil {
- return
- }
-
- Protect(t.callback, fd)
-}
-
-func (t *TunHandler) handleResolveProcess(source, target net.Addr) string {
- _ = t.limit.Acquire(context.Background(), 1)
- defer t.limit.Release(1)
-
- if t.listener == nil {
- return ""
- }
- var protocol int
- uid := -1
- switch source.Network() {
- case "udp", "udp4", "udp6":
- protocol = syscall.IPPROTO_UDP
- case "tcp", "tcp4", "tcp6":
- protocol = syscall.IPPROTO_TCP
- }
- if version < 29 {
- uid = platform.QuerySocketUidFromProcFs(source, target)
- }
- return ResolveProcess(t.callback, protocol, source.String(), target.String(), uid)
-}
-
-var (
- tunLock sync.Mutex
- runTime *time.Time
- errBlocked = errors.New("blocked")
- tunHandler *TunHandler
-)
-
-func handleStopTun() {
- tunLock.Lock()
- defer tunLock.Unlock()
- runTime = nil
- if tunHandler != nil {
- tunHandler.close()
- }
-}
-
-func handleStartTun(fd int, callback unsafe.Pointer) {
- handleStopTun()
- tunLock.Lock()
- defer tunLock.Unlock()
- now := time.Now()
- runTime = &now
- if fd != 0 {
- tunHandler = &TunHandler{
- callback: callback,
- limit: semaphore.NewWeighted(4),
- }
- initTunHook()
- tunListener, _ := t.Start(fd, currentConfig.General.Tun.Device, currentConfig.General.Tun.Stack)
- if tunListener != nil {
- log.Infoln("TUN address: %v", tunListener.Address())
- tunHandler.listener = tunListener
- } else {
- removeTunHook()
- }
- }
-}
-
-func handleGetRunTime() string {
- if runTime == nil {
- return ""
- }
- return strconv.FormatInt(runTime.UnixMilli(), 10)
-}
-
-func initTunHook() {
- dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error {
- if platform.ShouldBlockConnection() {
- return errBlocked
- }
- return conn.Control(func(fd uintptr) {
- tunHandler.handleProtect(int(fd))
- })
- }
- process.DefaultPackageNameResolver = func(metadata *constant.Metadata) (string, error) {
- src, dst := metadata.RawSrcAddr, metadata.RawDstAddr
- if src == nil || dst == nil {
- return "", process.ErrInvalidNetwork
- }
- return tunHandler.handleResolveProcess(src, dst), nil
- }
-}
-
-func removeTunHook() {
- dialer.DefaultSocketHook = nil
- process.DefaultPackageNameResolver = nil
-}
-
-func handleGetAndroidVpnOptions() string {
- tunLock.Lock()
- defer tunLock.Unlock()
- options := state.AndroidVpnOptions{
- Enable: state.CurrentState.VpnProps.Enable,
- Port: currentConfig.General.MixedPort,
- Ipv4Address: state.DefaultIpv4Address,
- Ipv6Address: state.GetIpv6Address(),
- AccessControl: state.CurrentState.VpnProps.AccessControl,
- SystemProxy: state.CurrentState.VpnProps.SystemProxy,
- AllowBypass: state.CurrentState.VpnProps.AllowBypass,
- RouteAddress: currentConfig.General.Tun.RouteAddress,
- BypassDomain: state.CurrentState.BypassDomain,
- DnsServerAddress: state.GetDnsServerAddress(),
- }
- data, err := json.Marshal(options)
- if err != nil {
- fmt.Println("Error:", err)
- return ""
- }
- return string(data)
-}
-
-func handleUpdateDns(value string) {
- go func() {
- log.Infoln("[DNS] updateDns %s", value)
- dns.UpdateSystemDNS(strings.Split(value, ","))
- dns.FlushCacheWithDefaultResolver()
- }()
-}
-
-func handleGetCurrentProfileName() string {
- if state.CurrentState == nil {
- return ""
- }
- return state.CurrentState.CurrentProfileName
-}
-
-func nextHandle(action *Action, result ActionResult) bool {
- switch action.Method {
- case getAndroidVpnOptionsMethod:
- result.success(handleGetAndroidVpnOptions())
- return true
- case updateDnsMethod:
- data := action.Data.(string)
- handleUpdateDns(data)
- result.success(true)
- return true
- case getRunTimeMethod:
- result.success(handleGetRunTime())
- return true
- case getCurrentProfileNameMethod:
- result.success(handleGetCurrentProfileName())
- return true
- }
- return false
-}
-
-//export quickStart
-func quickStart(initParamsChar *C.char, paramsChar *C.char, stateParamsChar *C.char, port C.longlong) {
- i := int64(port)
- paramsString := C.GoString(initParamsChar)
- bytes := []byte(C.GoString(paramsChar))
- stateParams := C.GoString(stateParamsChar)
- go func() {
- res := handleInitClash(paramsString)
- if res == false {
- bridge.SendToPort(i, "init error")
- }
- handleSetState(stateParams)
- bridge.SendToPort(i, handleSetupConfig(bytes))
- }()
-}
-
-//export startTUN
-func startTUN(fd C.int, callback unsafe.Pointer) bool {
- go func() {
- handleStartTun(int(fd), callback)
- }()
- return true
-}
-
-//export getRunTime
-func getRunTime() *C.char {
- return C.CString(handleGetRunTime())
-}
-
-//export stopTun
-func stopTun() {
- go func() {
- handleStopTun()
- }()
-}
-
-//export getCurrentProfileName
-func getCurrentProfileName() *C.char {
- return C.CString(handleGetCurrentProfileName())
-}
-
-//export getAndroidVpnOptions
-func getAndroidVpnOptions() *C.char {
- return C.CString(handleGetAndroidVpnOptions())
-}
-
-//export setState
-func setState(s *C.char) {
- paramsString := C.GoString(s)
- handleSetState(paramsString)
-}
-
-//export updateDns
-func updateDns(s *C.char) {
- dnsList := C.GoString(s)
- handleUpdateDns(dnsList)
-}
diff --git a/core/lib_no_android.go b/core/lib_no_android.go
deleted file mode 100644
index 84f10ce..0000000
--- a/core/lib_no_android.go
+++ /dev/null
@@ -1,7 +0,0 @@
-//go:build !android && cgo
-
-package main
-
-func nextHandle(action *Action, result func(data interface{})) bool {
- return false
-}
diff --git a/core/platform/procfs.go b/core/platform/procfs.go
index 94989c0..a6d604b 100644
--- a/core/platform/procfs.go
+++ b/core/platform/procfs.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package platform
diff --git a/core/state/state.go b/core/state/state.go
deleted file mode 100644
index 62beaf5..0000000
--- a/core/state/state.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package state
-
-import "net/netip"
-
-var DefaultIpv4Address = "172.19.0.1/30"
-var DefaultDnsAddress = "172.19.0.2"
-var DefaultIpv6Address = "fdfe:dcba:9876::1/126"
-
-type AndroidVpnOptions struct {
- Enable bool `json:"enable"`
- Port int `json:"port"`
- AccessControl *AccessControl `json:"accessControl"`
- AllowBypass bool `json:"allowBypass"`
- SystemProxy bool `json:"systemProxy"`
- BypassDomain []string `json:"bypassDomain"`
- RouteAddress []netip.Prefix `json:"routeAddress"`
- Ipv4Address string `json:"ipv4Address"`
- Ipv6Address string `json:"ipv6Address"`
- DnsServerAddress string `json:"dnsServerAddress"`
-}
-
-type AccessControl struct {
- Enable bool `json:"enable"`
- Mode string `json:"mode"`
- AcceptList []string `json:"acceptList"`
- RejectList []string `json:"rejectList"`
-}
-
-type AndroidVpnRawOptions struct {
- Enable bool `json:"enable"`
- AccessControl *AccessControl `json:"accessControl"`
- AllowBypass bool `json:"allowBypass"`
- SystemProxy bool `json:"systemProxy"`
- Ipv6 bool `json:"ipv6"`
-}
-
-type State struct {
- VpnProps AndroidVpnRawOptions `json:"vpn-props"`
- CurrentProfileName string `json:"current-profile-name"`
- OnlyStatisticsProxy bool `json:"only-statistics-proxy"`
- BypassDomain []string `json:"bypass-domain"`
-}
-
-var CurrentState = &State{
- OnlyStatisticsProxy: false,
- CurrentProfileName: "",
-}
-
-func GetIpv6Address() string {
- if CurrentState.VpnProps.Ipv6 {
- return DefaultIpv6Address
- } else {
- return ""
- }
-}
-
-func GetDnsServerAddress() string {
- return DefaultDnsAddress
-}
diff --git a/core/tun/tun.go b/core/tun/tun.go
index 8cae371..59ce35b 100644
--- a/core/tun/tun.go
+++ b/core/tun/tun.go
@@ -4,7 +4,6 @@ package tun
import "C"
import (
- "core/state"
"github.com/metacubex/mihomo/constant"
LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/listener/sing_tun"
@@ -12,38 +11,37 @@ import (
"github.com/metacubex/mihomo/tunnel"
"net"
"net/netip"
+ "strings"
)
-type Props struct {
- Fd int `json:"fd"`
- Gateway string `json:"gateway"`
- Gateway6 string `json:"gateway6"`
- Portal string `json:"portal"`
- Portal6 string `json:"portal6"`
- Dns string `json:"dns"`
- Dns6 string `json:"dns6"`
-}
-
-func Start(fd int, device string, stack constant.TUNStack) (*sing_tun.Listener, error) {
+func Start(fd int, device string, stack constant.TUNStack, address, dns string) *sing_tun.Listener {
var prefix4 []netip.Prefix
- tempPrefix4, err := netip.ParsePrefix(state.DefaultIpv4Address)
- if err != nil {
- log.Errorln("startTUN error:", err)
- return nil, err
- }
- prefix4 = append(prefix4, tempPrefix4)
var prefix6 []netip.Prefix
- if state.CurrentState.VpnProps.Ipv6 {
- tempPrefix6, err := netip.ParsePrefix(state.DefaultIpv6Address)
- if err != nil {
- log.Errorln("startTUN error:", err)
- return nil, err
+ for _, a := range strings.Split(address, ",") {
+ a = strings.TrimSpace(a)
+ if len(a) == 0 {
+ continue
+ }
+ prefix, err := netip.ParsePrefix(a)
+ if err != nil {
+ log.Errorln("TUN:", err)
+ return nil
+ }
+ if prefix.Addr().Is4() {
+ prefix4 = append(prefix4, prefix)
+ } else {
+ prefix6 = append(prefix6, prefix)
}
- prefix6 = append(prefix6, tempPrefix6)
}
var dnsHijack []string
- dnsHijack = append(dnsHijack, net.JoinHostPort(state.GetDnsServerAddress(), "53"))
+ for _, d := range strings.Split(dns, ",") {
+ d = strings.TrimSpace(d)
+ if len(d) == 0 {
+ continue
+ }
+ dnsHijack = append(dnsHijack, net.JoinHostPort(d, "53"))
+ }
options := LC.Tun{
Enable: true,
@@ -61,9 +59,9 @@ func Start(fd int, device string, stack constant.TUNStack) (*sing_tun.Listener,
listener, err := sing_tun.New(options, tunnel.Tunnel)
if err != nil {
- log.Errorln("startTUN error:", err)
- return nil, err
+ log.Errorln("TUN:", err)
+ return nil
}
- return listener, nil
+ return listener
}
diff --git a/lib/application.dart b/lib/application.dart
index 3baa1b0..06d4d51 100644
--- a/lib/application.dart
+++ b/lib/application.dart
@@ -1,8 +1,8 @@
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
-import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/common/common.dart';
+import 'package:fl_clash/core/core.dart';
import 'package:fl_clash/l10n/l10n.dart';
import 'package:fl_clash/manager/hotkey_manager.dart';
import 'package:fl_clash/manager/manager.dart';
@@ -17,9 +17,7 @@ import 'controller.dart';
import 'pages/pages.dart';
class Application extends ConsumerStatefulWidget {
- const Application({
- super.key,
- });
+ const Application({super.key});
@override
ConsumerState createState() => ApplicationState();
@@ -48,7 +46,6 @@ class ApplicationState extends ConsumerState {
@override
void initState() {
super.initState();
- _autoUpdateGroupTask();
_autoUpdateProfilesTask();
globalState.appController = AppController(context, ref);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
@@ -62,15 +59,6 @@ class ApplicationState extends ConsumerState {
});
}
- void _autoUpdateGroupTask() {
- _autoUpdateGroupTaskTimer = Timer(const Duration(milliseconds: 20000), () {
- WidgetsBinding.instance.addPostFrameCallback((_) {
- globalState.appController.updateGroupsDebounce();
- _autoUpdateGroupTask();
- });
- });
- }
-
void _autoUpdateProfilesTask() {
_autoUpdateProfilesTaskTimer = Timer(const Duration(minutes: 20), () async {
await globalState.appController.autoUpdateProfiles();
@@ -82,28 +70,20 @@ class ApplicationState extends ConsumerState {
if (system.isDesktop) {
return WindowManager(
child: TrayManager(
- child: HotKeyManager(
- child: ProxyManager(
- child: child,
- ),
- ),
+ child: HotKeyManager(child: ProxyManager(child: child)),
),
);
}
- return AndroidManager(
- child: TileManager(
- child: child,
- ),
- );
+ return AndroidManager(child: TileManager(child: child));
}
Widget _buildState(Widget child) {
return AppStateManager(
- child: ClashManager(
+ child: CoreManager(
child: ConnectivityManager(
onConnectivityChanged: (results) async {
if (!results.contains(ConnectivityResult.vpn)) {
- clashCore.closeConnections();
+ coreController.closeConnections();
}
globalState.appController.updateLocalIp();
globalState.appController.addCheckIpNumDebounce();
@@ -116,21 +96,13 @@ class ApplicationState extends ConsumerState {
Widget _buildPlatformApp(Widget child) {
if (system.isDesktop) {
- return WindowHeaderContainer(
- child: child,
- );
+ return WindowHeaderContainer(child: child);
}
- return VpnManager(
- child: child,
- );
+ return VpnManager(child: child);
}
Widget _buildApp(Widget child) {
- return MessageManager(
- child: ThemeManager(
- child: child,
- ),
- );
+ return MessageManager(child: ThemeManager(child: child));
}
@override
@@ -139,8 +111,9 @@ class ApplicationState extends ConsumerState {
_buildState(
Consumer(
builder: (_, ref, child) {
- final locale =
- ref.watch(appSettingProvider.select((state) => state.locale));
+ final locale = ref.watch(
+ appSettingProvider.select((state) => state.locale),
+ );
final themeProps = ref.watch(themeSettingProvider);
return MaterialApp(
debugShowCheckedModeBanner: false,
@@ -149,16 +122,12 @@ class ApplicationState extends ConsumerState {
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
- GlobalWidgetsLocalizations.delegate
+ GlobalWidgetsLocalizations.delegate,
],
builder: (_, child) {
return AppEnvManager(
child: _buildApp(
- AppSidebarContainer(
- child: _buildPlatformApp(
- child!,
- ),
- ),
+ AppSidebarContainer(child: _buildPlatformApp(child!)),
),
);
},
@@ -197,7 +166,7 @@ class ApplicationState extends ConsumerState {
linkManager.destroy();
_autoUpdateGroupTaskTimer?.cancel();
_autoUpdateProfilesTaskTimer?.cancel();
- await clashCore.destroy();
+ await coreController.destroy();
await globalState.appController.savePreferences();
await globalState.appController.handleExit();
super.dispose();
diff --git a/lib/clash/generated/clash_ffi.dart b/lib/clash/generated/clash_ffi.dart
deleted file mode 100644
index c97847f..0000000
--- a/lib/clash/generated/clash_ffi.dart
+++ /dev/null
@@ -1,5363 +0,0 @@
-// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-// ignore_for_file: type=lint
-import 'dart:ffi' as ffi;
-
-class ClashFFI {
- /// Holds the symbol lookup function.
- final ffi.Pointer Function(String symbolName)
- _lookup;
-
- /// The symbols are looked up in [dynamicLibrary].
- ClashFFI(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
-
- /// The symbols are looked up with [lookup].
- ClashFFI.fromLookup(
- ffi.Pointer Function(String symbolName)
- lookup)
- : _lookup = lookup;
-
- ffi.Pointer> signal(
- int arg0,
- ffi.Pointer> arg1,
- ) {
- return _signal(
- arg0,
- arg1,
- );
- }
-
- late final _signalPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer> Function(
- ffi.Int,
- ffi.Pointer<
- ffi.NativeFunction>)>>('signal');
- late final _signal = _signalPtr.asFunction<
- ffi.Pointer> Function(
- int, ffi.Pointer>)>();
-
- int getpriority(
- int arg0,
- int arg1,
- ) {
- return _getpriority(
- arg0,
- arg1,
- );
- }
-
- late final _getpriorityPtr =
- _lookup>(
- 'getpriority');
- late final _getpriority =
- _getpriorityPtr.asFunction();
-
- int getiopolicy_np(
- int arg0,
- int arg1,
- ) {
- return _getiopolicy_np(
- arg0,
- arg1,
- );
- }
-
- late final _getiopolicy_npPtr =
- _lookup>(
- 'getiopolicy_np');
- late final _getiopolicy_np =
- _getiopolicy_npPtr.asFunction();
-
- int getrlimit(
- int arg0,
- ffi.Pointer arg1,
- ) {
- return _getrlimit(
- arg0,
- arg1,
- );
- }
-
- late final _getrlimitPtr = _lookup<
- ffi.NativeFunction)>>(
- 'getrlimit');
- late final _getrlimit =
- _getrlimitPtr.asFunction)>();
-
- int getrusage(
- int arg0,
- ffi.Pointer arg1,
- ) {
- return _getrusage(
- arg0,
- arg1,
- );
- }
-
- late final _getrusagePtr = _lookup<
- ffi.NativeFunction)>>(
- 'getrusage');
- late final _getrusage =
- _getrusagePtr.asFunction)>();
-
- int setpriority(
- int arg0,
- int arg1,
- int arg2,
- ) {
- return _setpriority(
- arg0,
- arg1,
- arg2,
- );
- }
-
- late final _setpriorityPtr =
- _lookup>(
- 'setpriority');
- late final _setpriority =
- _setpriorityPtr.asFunction();
-
- int setiopolicy_np(
- int arg0,
- int arg1,
- int arg2,
- ) {
- return _setiopolicy_np(
- arg0,
- arg1,
- arg2,
- );
- }
-
- late final _setiopolicy_npPtr =
- _lookup>(
- 'setiopolicy_np');
- late final _setiopolicy_np =
- _setiopolicy_npPtr.asFunction();
-
- int setrlimit(
- int arg0,
- ffi.Pointer arg1,
- ) {
- return _setrlimit(
- arg0,
- arg1,
- );
- }
-
- late final _setrlimitPtr = _lookup<
- ffi.NativeFunction)>>(
- 'setrlimit');
- late final _setrlimit =
- _setrlimitPtr.asFunction)>();
-
- int wait$1(
- ffi.Pointer arg0,
- ) {
- return _wait$1(
- arg0,
- );
- }
-
- late final _wait$1Ptr =
- _lookup)>>('wait');
- late final _wait$1 =
- _wait$1Ptr.asFunction)>();
-
- int waitpid(
- int arg0,
- ffi.Pointer arg1,
- int arg2,
- ) {
- return _waitpid(
- arg0,
- arg1,
- arg2,
- );
- }
-
- late final _waitpidPtr = _lookup<
- ffi.NativeFunction<
- pid_t Function(pid_t, ffi.Pointer, ffi.Int)>>('waitpid');
- late final _waitpid =
- _waitpidPtr.asFunction, int)>();
-
- int waitid(
- idtype_t arg0,
- Dart__uint32_t arg1,
- ffi.Pointer arg2,
- int arg3,
- ) {
- return _waitid(
- arg0.value,
- arg1,
- arg2,
- arg3,
- );
- }
-
- late final _waitidPtr = _lookup<
- ffi.NativeFunction<
- ffi.Int Function(ffi.UnsignedInt, id_t, ffi.Pointer,
- ffi.Int)>>('waitid');
- late final _waitid = _waitidPtr
- .asFunction, int)>();
-
- int wait3(
- ffi.Pointer arg0,
- int arg1,
- ffi.Pointer arg2,
- ) {
- return _wait3(
- arg0,
- arg1,
- arg2,
- );
- }
-
- late final _wait3Ptr = _lookup<
- ffi.NativeFunction<
- pid_t Function(
- ffi.Pointer, ffi.Int, ffi.Pointer)>>('wait3');
- late final _wait3 = _wait3Ptr.asFunction<
- int Function(ffi.Pointer, int, ffi.Pointer)>();
-
- int wait4(
- int arg0,
- ffi.Pointer arg1,
- int arg2,
- ffi.Pointer arg3,
- ) {
- return _wait4(
- arg0,
- arg1,
- arg2,
- arg3,
- );
- }
-
- late final _wait4Ptr = _lookup<
- ffi.NativeFunction<
- pid_t Function(pid_t, ffi.Pointer, ffi.Int,
- ffi.Pointer)>>('wait4');
- late final _wait4 = _wait4Ptr.asFunction<
- int Function(int, ffi.Pointer, int, ffi.Pointer)>();
-
- ffi.Pointer alloca(
- int arg0,
- ) {
- return _alloca(
- arg0,
- );
- }
-
- late final _allocaPtr =
- _lookup Function(ffi.Size)>>(
- 'alloca');
- late final _alloca =
- _allocaPtr.asFunction Function(int)>();
-
- late final ffi.Pointer ___mb_cur_max =
- _lookup('__mb_cur_max');
-
- int get __mb_cur_max => ___mb_cur_max.value;
-
- set __mb_cur_max(int value) => ___mb_cur_max.value = value;
-
- ffi.Pointer malloc_type_malloc(
- int size,
- int type_id,
- ) {
- return _malloc_type_malloc(
- size,
- type_id,
- );
- }
-
- late final _malloc_type_mallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(
- ffi.Size, malloc_type_id_t)>>('malloc_type_malloc');
- late final _malloc_type_malloc = _malloc_type_mallocPtr
- .asFunction Function(int, int)>();
-
- ffi.Pointer malloc_type_calloc(
- int count,
- int size,
- int type_id,
- ) {
- return _malloc_type_calloc(
- count,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_callocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(
- ffi.Size, ffi.Size, malloc_type_id_t)>>('malloc_type_calloc');
- late final _malloc_type_calloc = _malloc_type_callocPtr
- .asFunction Function(int, int, int)>();
-
- void malloc_type_free(
- ffi.Pointer ptr,
- int type_id,
- ) {
- return _malloc_type_free(
- ptr,
- type_id,
- );
- }
-
- late final _malloc_type_freePtr = _lookup<
- ffi.NativeFunction<
- ffi.Void Function(
- ffi.Pointer, malloc_type_id_t)>>('malloc_type_free');
- late final _malloc_type_free = _malloc_type_freePtr
- .asFunction, int)>();
-
- ffi.Pointer malloc_type_realloc(
- ffi.Pointer ptr,
- int size,
- int type_id,
- ) {
- return _malloc_type_realloc(
- ptr,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_reallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Pointer, ffi.Size,
- malloc_type_id_t)>>('malloc_type_realloc');
- late final _malloc_type_realloc = _malloc_type_reallocPtr.asFunction<
- ffi.Pointer Function(ffi.Pointer, int, int)>();
-
- ffi.Pointer malloc_type_valloc(
- int size,
- int type_id,
- ) {
- return _malloc_type_valloc(
- size,
- type_id,
- );
- }
-
- late final _malloc_type_vallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(
- ffi.Size, malloc_type_id_t)>>('malloc_type_valloc');
- late final _malloc_type_valloc = _malloc_type_vallocPtr
- .asFunction Function(int, int)>();
-
- ffi.Pointer malloc_type_aligned_alloc(
- int alignment,
- int size,
- int type_id,
- ) {
- return _malloc_type_aligned_alloc(
- alignment,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_aligned_allocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Size, ffi.Size,
- malloc_type_id_t)>>('malloc_type_aligned_alloc');
- late final _malloc_type_aligned_alloc = _malloc_type_aligned_allocPtr
- .asFunction Function(int, int, int)>();
-
- int malloc_type_posix_memalign(
- ffi.Pointer> memptr,
- int alignment,
- int size,
- int type_id,
- ) {
- return _malloc_type_posix_memalign(
- memptr,
- alignment,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_posix_memalignPtr = _lookup<
- ffi.NativeFunction<
- ffi.Int Function(ffi.Pointer>, ffi.Size,
- ffi.Size, malloc_type_id_t)>>('malloc_type_posix_memalign');
- late final _malloc_type_posix_memalign =
- _malloc_type_posix_memalignPtr.asFunction<
- int Function(ffi.Pointer>, int, int, int)>();
-
- ffi.Pointer malloc_type_zone_malloc(
- ffi.Pointer zone,
- int size,
- int type_id,
- ) {
- return _malloc_type_zone_malloc(
- zone,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_zone_mallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Pointer, ffi.Size,
- malloc_type_id_t)>>('malloc_type_zone_malloc');
- late final _malloc_type_zone_malloc = _malloc_type_zone_mallocPtr.asFunction<
- ffi.Pointer Function(ffi.Pointer, int, int)>();
-
- ffi.Pointer malloc_type_zone_calloc(
- ffi.Pointer zone,
- int count,
- int size,
- int type_id,
- ) {
- return _malloc_type_zone_calloc(
- zone,
- count,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_zone_callocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Pointer, ffi.Size,
- ffi.Size, malloc_type_id_t)>>('malloc_type_zone_calloc');
- late final _malloc_type_zone_calloc = _malloc_type_zone_callocPtr.asFunction<
- ffi.Pointer Function(
- ffi.Pointer, int, int, int)>();
-
- void malloc_type_zone_free(
- ffi.Pointer zone,
- ffi.Pointer ptr,
- int type_id,
- ) {
- return _malloc_type_zone_free(
- zone,
- ptr,
- type_id,
- );
- }
-
- late final _malloc_type_zone_freePtr = _lookup<
- ffi.NativeFunction<
- ffi.Void Function(ffi.Pointer, ffi.Pointer,
- malloc_type_id_t)>>('malloc_type_zone_free');
- late final _malloc_type_zone_free = _malloc_type_zone_freePtr.asFunction<
- void Function(ffi.Pointer, ffi.Pointer, int)>();
-
- ffi.Pointer malloc_type_zone_realloc(
- ffi.Pointer zone,
- ffi.Pointer ptr,
- int size,
- int type_id,
- ) {
- return _malloc_type_zone_realloc(
- zone,
- ptr,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_zone_reallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(
- ffi.Pointer,
- ffi.Pointer,
- ffi.Size,
- malloc_type_id_t)>>('malloc_type_zone_realloc');
- late final _malloc_type_zone_realloc =
- _malloc_type_zone_reallocPtr.asFunction<
- ffi.Pointer Function(
- ffi.Pointer, ffi.Pointer, int, int)>();
-
- ffi.Pointer malloc_type_zone_valloc(
- ffi.Pointer zone,
- int size,
- int type_id,
- ) {
- return _malloc_type_zone_valloc(
- zone,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_zone_vallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Pointer, ffi.Size,
- malloc_type_id_t)>>('malloc_type_zone_valloc');
- late final _malloc_type_zone_valloc = _malloc_type_zone_vallocPtr.asFunction<
- ffi.Pointer Function(ffi.Pointer, int, int)>();
-
- ffi.Pointer malloc_type_zone_memalign(
- ffi.Pointer zone,
- int alignment,
- int size,
- int type_id,
- ) {
- return _malloc_type_zone_memalign(
- zone,
- alignment,
- size,
- type_id,
- );
- }
-
- late final _malloc_type_zone_memalignPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Pointer, ffi.Size,
- ffi.Size, malloc_type_id_t)>>('malloc_type_zone_memalign');
- late final _malloc_type_zone_memalign =
- _malloc_type_zone_memalignPtr.asFunction<
- ffi.Pointer Function(
- ffi.Pointer, int, int, int)>();
-
- ffi.Pointer malloc(
- int __size,
- ) {
- return _malloc(
- __size,
- );
- }
-
- late final _mallocPtr =
- _lookup Function(ffi.Size)>>(
- 'malloc');
- late final _malloc =
- _mallocPtr.asFunction Function(int)>();
-
- ffi.Pointer calloc(
- int __count,
- int __size,
- ) {
- return _calloc(
- __count,
- __size,
- );
- }
-
- late final _callocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(ffi.Size, ffi.Size)>>('calloc');
- late final _calloc =
- _callocPtr.asFunction Function(int, int)>();
-
- void free(
- ffi.Pointer arg0,
- ) {
- return _free(
- arg0,
- );
- }
-
- late final _freePtr =
- _lookup)>>(
- 'free');
- late final _free =
- _freePtr.asFunction)>();
-
- ffi.Pointer realloc(
- ffi.Pointer __ptr,
- int __size,
- ) {
- return _realloc(
- __ptr,
- __size,
- );
- }
-
- late final _reallocPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(
- ffi.Pointer, ffi.Size)>>('realloc');
- late final _realloc = _reallocPtr
- .asFunction Function(ffi.Pointer, int)>();
-
- ffi.Pointer reallocf(
- ffi.Pointer __ptr,
- int __size,
- ) {
- return _reallocf(
- __ptr,
- __size,
- );
- }
-
- late final _reallocfPtr = _lookup<
- ffi.NativeFunction<
- ffi.Pointer Function(
- ffi.Pointer, ffi.Size)>>('reallocf');
- late final _reallocf = _reallocfPtr
- .asFunction Function(ffi.Pointer, int)>();
-
- ffi.Pointer valloc(
- int __size,
- ) {
- return _valloc(
- __size,
- );
- }
-
- late final _vallocPtr =
- _lookup Function(ffi.Size)>>(
- 'valloc');
- late final _valloc =
- _vallocPtr.asFunction