Wait for capture stop when calling stop via API

This allows getting more accurate capture stats
This commit is contained in:
emanuele-f 2022-06-01 12:14:38 +02:00
parent 10b2774315
commit ca063e3296
3 changed files with 40 additions and 12 deletions

View File

@ -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);

View File

@ -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");

View File

@ -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;
}