Wait for Android VPN runtime before recovery probes

This commit is contained in:
2026-05-15 08:26:21 +03:00
parent 620d5a97c9
commit 8558b210c3
2 changed files with 36 additions and 5 deletions
+2 -2
View File
@@ -30,8 +30,8 @@ android {
applicationId "su.cin.rapvpn" applicationId "su.cin.rapvpn"
minSdk 26 minSdk 26
targetSdk 35 targetSdk 35
versionCode 186 versionCode 187
versionName "0.2.186" versionName "0.2.187"
buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\"" buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\""
buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\"" buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\""
buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\"" buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\""
@@ -73,6 +73,7 @@ public class RapDiagnosticService extends Service {
private static final int RECOVERY_PAGE_TIMEOUT_MS = 25000; private static final int RECOVERY_PAGE_TIMEOUT_MS = 25000;
private static final int RECOVERY_DOWNLOAD_CONNECT_TIMEOUT_MS = 8000; private static final int RECOVERY_DOWNLOAD_CONNECT_TIMEOUT_MS = 8000;
private static final int RECOVERY_DOWNLOAD_READ_TIMEOUT_MS = 12000; private static final int RECOVERY_DOWNLOAD_READ_TIMEOUT_MS = 12000;
private static final int RECOVERY_RUNTIME_READY_TIMEOUT_MS = 9000;
private volatile boolean running; private volatile boolean running;
private Thread worker; private Thread worker;
private Thread supervisor; private Thread supervisor;
@@ -483,13 +484,13 @@ public class RapDiagnosticService extends Service {
if (isRecoverableVPNProbe(type) && looksLikeVPNStall(result)) { if (isRecoverableVPNProbe(type) && looksLikeVPNStall(result)) {
String firstResult = result; String firstResult = result;
String recovery = controlledRestartVPNRuntime(client, clusterId); String recovery = controlledRestartVPNRuntime(client, clusterId);
Thread.sleep(2500); String ready = waitForVPNRuntimeReady(RECOVERY_RUNTIME_READY_TIMEOUT_MS);
String recoveryRetry = runVPNProbeCommand(type, recoveryProbePayload(type, params), true); String recoveryRetry = runVPNProbeCommand(type, recoveryProbePayload(type, params), true);
if (!looksLikeVPNStall(recoveryRetry)) { if (!looksLikeVPNStall(recoveryRetry)) {
result = firstResult + " | recovery=" + recovery + " | recovery_retry=" + recoveryRetry; result = firstResult + " | recovery=" + recovery + " | ready=" + ready + " | recovery_retry=" + recoveryRetry;
} else { } else {
Thread.sleep(1500); Thread.sleep(1500);
result = firstResult + " | recovery=" + recovery + " | recovery_retry=" + recoveryRetry + " | final_retry=" + runVPNProbeCommand(type, recoveryProbePayload(type, params), true); result = firstResult + " | recovery=" + recovery + " | ready=" + ready + " | recovery_retry=" + recoveryRetry + " | final_retry=" + runVPNProbeCommand(type, recoveryProbePayload(type, params), true);
} }
} }
lastCommandType = type; lastCommandType = type;
@@ -731,6 +732,36 @@ public class RapDiagnosticService extends Service {
} }
} }
private String waitForVPNRuntimeReady(int timeoutMs) {
SharedPreferences runtime = getSharedPreferences(RUNTIME_PREFS, MODE_PRIVATE);
long deadline = System.currentTimeMillis() + Math.max(1000, timeoutMs);
String last = "unknown";
while (System.currentTimeMillis() < deadline) {
String state = runtime.getString("state", "");
String senderState = runtime.getString("uplink_sender_state", "");
boolean senderAlive = runtime.getBoolean("uplink_sender_thread_alive", false);
boolean downlinkAlive = runtime.getBoolean("downlink_thread_alive", false);
long updatedAt = runtime.getLong("updated_at", 0);
long age = updatedAt <= 0 ? Long.MAX_VALUE : System.currentTimeMillis() - updatedAt;
last = state + "/sender=" + senderState + "/age_ms=" + age;
boolean readyState = "downlink".equals(state)
|| "downlink_idle".equals(state)
|| "uplink_sent".equals(state)
|| "uplink_read".equals(state)
|| "runtime_recovery".equals(state);
if (readyState && senderAlive && downlinkAlive && age < 3000) {
return "runtime_ready " + last;
}
try {
Thread.sleep(250);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "runtime_ready interrupted " + last;
}
}
return "runtime_ready timeout " + last;
}
private void maybeRestartVPNAfterAppUpgrade(RapApiClient client, String clusterId, SharedPreferences prefs) { private void maybeRestartVPNAfterAppUpgrade(RapApiClient client, String clusterId, SharedPreferences prefs) {
String lastVersion = prefs.getString("vpn_runtime_app_version", ""); String lastVersion = prefs.getString("vpn_runtime_app_version", "");
if (APP_VERSION.equals(lastVersion)) { if (APP_VERSION.equals(lastVersion)) {