From ca063e3296509fe6d6ae36dae857d91f7e44ab5c Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Wed, 1 Jun 2022 12:14:38 +0200 Subject: [PATCH] Wait for capture stop when calling stop via API This allows getting more accurate capture stats --- .../remote_capture/CaptureService.java | 36 ++++++++++++++++--- .../activities/CaptureCtrl.java | 14 ++++---- app/src/main/jni/core/capture_vpn.c | 2 +- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index 80ec6dae..034045b6 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -83,6 +83,8 @@ import java.net.UnknownHostException; import java.util.Enumeration; import java.util.Iterator; import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; public class CaptureService extends VpnService implements Runnable { private static final String TAG = "CaptureService"; @@ -92,6 +94,8 @@ public class CaptureService extends VpnService implements Runnable { private static final int VPN_MTU = 10000; private static final int NOTIFY_ID_VPNSERVICE = 1; private static CaptureService INSTANCE; + final ReentrantLock mLock = new ReentrantLock(); + final Condition mCaptureStopped = mLock.newCondition(); private ParcelFileDescriptor mParcelFileDescriptor; private boolean mIsAlwaysOnVPN; private SharedPreferences mPrefs; @@ -883,13 +887,16 @@ public class CaptureService extends VpnService implements Runnable { stopService(); + mLock.lock(); + mCaptureThread = null; + mCaptureStopped.signalAll(); + mLock.unlock(); + // Notify mHandler.post(() -> { sendServiceStatus(SERVICE_STATUS_STOPPED); - CaptureCtrl.notifyCaptureStopped(this, mLastStats); + CaptureCtrl.notifyCaptureStopped(this, getStats()); }); - - mCaptureThread = null; } private void connUpdateWork() { @@ -1176,8 +1183,27 @@ public class CaptureService extends VpnService implements Runnable { nativeSetFirewallEnabled(enabled); } - public static CaptureStats getStats() { - return((INSTANCE != null) ? INSTANCE.mLastStats : null); + public static @NonNull CaptureStats getStats() { + CaptureStats stats = (INSTANCE != null) ? INSTANCE.mLastStats : null; + return((stats != null) ? stats : new CaptureStats()); + } + + public static void waitForCaptureStop() { + if(INSTANCE == null) + return; + + Log.d(TAG, "waitForCaptureStop " + Thread.currentThread().getName()); + INSTANCE.mLock.lock(); + try { + while(INSTANCE.mCaptureThread != null) { + try { + INSTANCE.mCaptureStopped.await(); + } catch (InterruptedException ignored) {} + } + } finally { + INSTANCE.mLock.unlock(); + } + Log.d(TAG, "waitForCaptureStop done " + Thread.currentThread().getName()); } private static native void runPacketLoop(int fd, CaptureService vpn, int sdk); diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/CaptureCtrl.java b/app/src/main/java/com/emanuelef/remote_capture/activities/CaptureCtrl.java index f4cee651..5969e201 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/CaptureCtrl.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/CaptureCtrl.java @@ -206,9 +206,10 @@ public class CaptureCtrl extends AppCompatActivity { CaptureService.stopService(); mStarterApp = null; - CaptureStats stats = CaptureService.getStats(); - if(stats != null) - putStats(res, stats); + // stopService returns immediately, need to wait for capture stop + CaptureService.waitForCaptureStop(); + + putStats(res, CaptureService.getStats()); } else if(action.equals(ACTION_STATUS)) { Log.d(TAG, "Returning status"); @@ -216,9 +217,7 @@ public class CaptureCtrl extends AppCompatActivity { res.putExtra("version_name", BuildConfig.VERSION_NAME); res.putExtra("version_code", BuildConfig.VERSION_CODE); - CaptureStats stats = CaptureService.getStats(); - if(stats != null) - putStats(res, stats); + putStats(res, CaptureService.getStats()); } else { Log.e(TAG, "unknown action: " + action); abort(); @@ -230,6 +229,9 @@ public class CaptureCtrl extends AppCompatActivity { } public static void notifyCaptureStopped(Context ctx, CaptureStats stats) { + if(stats != null) + Log.d(TAG, "notifyCaptureStopped: " + (stats.pkts_sent + stats.pkts_rcvd) + " pkts"); + if((mStarterApp != null) && (mReceiverClass != null)) { Log.d(TAG, "Notifying receiver"); diff --git a/app/src/main/jni/core/capture_vpn.c b/app/src/main/jni/core/capture_vpn.c index fbe9906d..b2396cf5 100644 --- a/app/src/main/jni/core/capture_vpn.c +++ b/app/src/main/jni/core/capture_vpn.c @@ -583,7 +583,7 @@ int run_vpn(pcapdroid_t *pd) { } else { // zdtun_forward was successful if(data->vpn.fw_pctx) { - // not accounted in remote2vpn, account here + // it was not accounted in remote2vpn, account here pd_account_stats(pd, data->vpn.fw_pctx); data->vpn.fw_pctx = NULL; }