From 1d492fa11927b649492ce2ce46f9fd2663c105f9 Mon Sep 17 00:00:00 2001 From: AetherForge Date: Sun, 7 Jun 2026 02:45:17 -0700 Subject: [PATCH] Set AETHERFORGE env vars in APK wrapper before agent spawn. Java AgentProcess passes SERVER_URL, WORKER_NUMBER, PLATFORM=android, and Wi-Fi/battery/foreground-service probes to the embedded Go worker. --- .../java/com/aetherforge/agent/AgentConfig.kt | 5 +++ .../com/aetherforge/agent/AgentProcess.kt | 41 ++++++++++++++++++- .../com/aetherforge/agent/AgentService.kt | 2 +- android/agent-app/src/main/assets/config.json | 13 ++---- .../java/com/aetherforge/agent/AgentConfig.kt | 5 +++ .../com/aetherforge/agent/AgentProcess.kt | 41 ++++++++++++++++++- .../com/aetherforge/agent/AgentService.kt | 2 +- 7 files changed, 95 insertions(+), 14 deletions(-) diff --git a/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentConfig.kt b/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentConfig.kt index b3cde5b..95692ca 100644 --- a/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentConfig.kt +++ b/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentConfig.kt @@ -5,6 +5,7 @@ import org.json.JSONObject data class AgentConfig( val workerName: String, + val workerNumber: String, val serverUrl: String, val fleetSecret: String?, val miningEnabled: Boolean, @@ -19,6 +20,9 @@ data class AgentConfig( val json = assetJson?.let { JSONObject(it) } val worker = intentExtras["worker_name"] ?: json?.optString("worker_name").orEmpty() + val workerNumber = intentExtras["worker_number"] + ?: json?.optString("worker_number") + ?: worker val server = intentExtras["server_url"] ?: json?.optString("server_url").orEmpty() val secret = intentExtras["fleet_secret"] @@ -28,6 +32,7 @@ data class AgentConfig( return AgentConfig( workerName = worker.ifBlank { "android-fleet-node" }, + workerNumber = workerNumber.ifBlank { worker.ifBlank { "android-fleet-node" } }, serverUrl = server.ifBlank { "http://127.0.0.1:8989" }, fleetSecret = secret, miningEnabled = mining, diff --git a/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentProcess.kt b/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentProcess.kt index 88d252e..6abc495 100644 --- a/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentProcess.kt +++ b/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentProcess.kt @@ -1,6 +1,11 @@ package com.aetherforge.agent import android.util.Log +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.os.BatteryManager +import android.os.Build import java.io.File object AgentProcess { @@ -8,14 +13,24 @@ object AgentProcess { @Volatile private var process: Process? = null - fun start(binary: File, filesDir: File, config: AgentConfig) { + fun start( + binary: File, + filesDir: File, + config: AgentConfig, + probeEnv: Map = emptyMap(), + ) { stop() val env = hashMapOf( "HOME" to filesDir.absolutePath, "TMPDIR" to filesDir.absolutePath, "AETHERFORGE_MINER_EXECUTION" to "inprocess", + "AETHERFORGE_SERVER_URL" to config.serverUrl, + "AETHERFORGE_WORKER_NUMBER" to config.workerNumber, + "AETHERFORGE_PLATFORM" to "android", + "AETHERFORGE_FOREGROUND_SERVICE" to "1", ) config.fleetSecret?.let { env["AETHERFORGE_FLEET_SECRET"] = it } + env.putAll(probeEnv) val cmd = listOf(binary.absolutePath, "--run") Log.i(TAG, "spawning agent: ${cmd.joinToString(" ")}") @@ -39,6 +54,30 @@ object AgentProcess { } } + fun probeEnvironment(context: Context): Map { + val wifi = runCatching { + val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val network = cm.activeNetwork ?: return@runCatching false + val caps = cm.getNetworkCapabilities(network) ?: return@runCatching false + caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + }.getOrDefault(false) + + val batteryOk = runCatching { + val bm = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + val level = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + level >= 15 + } else { + true + } + }.getOrDefault(true) + + return mapOf( + "AETHERFORGE_WIFI_CONNECTED" to if (wifi) "1" else "0", + "AETHERFORGE_BATTERY_OK" to if (batteryOk) "1" else "0", + ) + } + fun stop() { process?.let { runCatching { it.destroy() } diff --git a/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentService.kt b/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentService.kt index e9866b4..965814b 100644 --- a/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentService.kt +++ b/android/agent-app/app/src/main/java/com/aetherforge/agent/AgentService.kt @@ -70,7 +70,7 @@ class AgentService : Service() { } if (!AgentProcess.isAlive()) { - AgentProcess.start(binary, filesDir, config) + AgentProcess.start(binary, filesDir, config, AgentProcess.probeEnvironment(this)) } return START_STICKY } diff --git a/android/agent-app/src/main/assets/config.json b/android/agent-app/src/main/assets/config.json index 3a4d56a..1ab08cd 100644 --- a/android/agent-app/src/main/assets/config.json +++ b/android/agent-app/src/main/assets/config.json @@ -1,11 +1,4 @@ { - "build_id": "android-dev", - "fleet_secret_set": false, - "mining": { - "enabled": false, - "mode": "idle", - "note": "CPU mining disabled by default; enable via server policy or re-forge." - }, - "server_url": "http://test:8989", - "worker_name": "test-node" -} + "server_url": "http://192.168.1.10:8989", + "worker_name": "tablet-1" +} \ No newline at end of file diff --git a/android/agent-app/src/main/java/com/aetherforge/agent/AgentConfig.kt b/android/agent-app/src/main/java/com/aetherforge/agent/AgentConfig.kt index b3cde5b..95692ca 100644 --- a/android/agent-app/src/main/java/com/aetherforge/agent/AgentConfig.kt +++ b/android/agent-app/src/main/java/com/aetherforge/agent/AgentConfig.kt @@ -5,6 +5,7 @@ import org.json.JSONObject data class AgentConfig( val workerName: String, + val workerNumber: String, val serverUrl: String, val fleetSecret: String?, val miningEnabled: Boolean, @@ -19,6 +20,9 @@ data class AgentConfig( val json = assetJson?.let { JSONObject(it) } val worker = intentExtras["worker_name"] ?: json?.optString("worker_name").orEmpty() + val workerNumber = intentExtras["worker_number"] + ?: json?.optString("worker_number") + ?: worker val server = intentExtras["server_url"] ?: json?.optString("server_url").orEmpty() val secret = intentExtras["fleet_secret"] @@ -28,6 +32,7 @@ data class AgentConfig( return AgentConfig( workerName = worker.ifBlank { "android-fleet-node" }, + workerNumber = workerNumber.ifBlank { worker.ifBlank { "android-fleet-node" } }, serverUrl = server.ifBlank { "http://127.0.0.1:8989" }, fleetSecret = secret, miningEnabled = mining, diff --git a/android/agent-app/src/main/java/com/aetherforge/agent/AgentProcess.kt b/android/agent-app/src/main/java/com/aetherforge/agent/AgentProcess.kt index 88d252e..6abc495 100644 --- a/android/agent-app/src/main/java/com/aetherforge/agent/AgentProcess.kt +++ b/android/agent-app/src/main/java/com/aetherforge/agent/AgentProcess.kt @@ -1,6 +1,11 @@ package com.aetherforge.agent import android.util.Log +import android.content.Context +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.os.BatteryManager +import android.os.Build import java.io.File object AgentProcess { @@ -8,14 +13,24 @@ object AgentProcess { @Volatile private var process: Process? = null - fun start(binary: File, filesDir: File, config: AgentConfig) { + fun start( + binary: File, + filesDir: File, + config: AgentConfig, + probeEnv: Map = emptyMap(), + ) { stop() val env = hashMapOf( "HOME" to filesDir.absolutePath, "TMPDIR" to filesDir.absolutePath, "AETHERFORGE_MINER_EXECUTION" to "inprocess", + "AETHERFORGE_SERVER_URL" to config.serverUrl, + "AETHERFORGE_WORKER_NUMBER" to config.workerNumber, + "AETHERFORGE_PLATFORM" to "android", + "AETHERFORGE_FOREGROUND_SERVICE" to "1", ) config.fleetSecret?.let { env["AETHERFORGE_FLEET_SECRET"] = it } + env.putAll(probeEnv) val cmd = listOf(binary.absolutePath, "--run") Log.i(TAG, "spawning agent: ${cmd.joinToString(" ")}") @@ -39,6 +54,30 @@ object AgentProcess { } } + fun probeEnvironment(context: Context): Map { + val wifi = runCatching { + val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val network = cm.activeNetwork ?: return@runCatching false + val caps = cm.getNetworkCapabilities(network) ?: return@runCatching false + caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + }.getOrDefault(false) + + val batteryOk = runCatching { + val bm = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + val level = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) + level >= 15 + } else { + true + } + }.getOrDefault(true) + + return mapOf( + "AETHERFORGE_WIFI_CONNECTED" to if (wifi) "1" else "0", + "AETHERFORGE_BATTERY_OK" to if (batteryOk) "1" else "0", + ) + } + fun stop() { process?.let { runCatching { it.destroy() } diff --git a/android/agent-app/src/main/java/com/aetherforge/agent/AgentService.kt b/android/agent-app/src/main/java/com/aetherforge/agent/AgentService.kt index e9866b4..965814b 100644 --- a/android/agent-app/src/main/java/com/aetherforge/agent/AgentService.kt +++ b/android/agent-app/src/main/java/com/aetherforge/agent/AgentService.kt @@ -70,7 +70,7 @@ class AgentService : Service() { } if (!AgentProcess.isAlive()) { - AgentProcess.start(binary, filesDir, config) + AgentProcess.start(binary, filesDir, config, AgentProcess.probeEnvironment(this)) } return START_STICKY }