0
0
mirror of https://github.com/schwabe/ics-openvpn.git synced 2024-09-20 03:52:27 +02:00

Use JobScheduler as backup to keep an active VPN active

This should restart it in some instances when the app dies or gets killed.
This commit is contained in:
Arne Schwabe 2023-06-01 00:28:41 +02:00
parent 3211fed064
commit 8fe897a3c7
3 changed files with 119 additions and 1 deletions

View File

@ -96,6 +96,11 @@
</intent-filter>
</receiver>
<service android:name=".core.keepVPNAlive"
android:process=":openvpn"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<activity
android:name=".LaunchVPN"

View File

@ -14,6 +14,8 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.UiModeManager;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@ -34,12 +36,12 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;
import androidx.annotation.NonNull;
@ -227,6 +229,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
private void endVpnService() {
if (!isAlwaysOn()) {
/* if we should be an always on VPN, keep the timer running */
keepVPNAlive.unscheduleKeepVPNAliveJobService(this);
}
synchronized (mProcessLock) {
mProcessThread = null;
}
@ -573,6 +579,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
ProfileManager.setConnectedVpnProfile(this, mProfile);
VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString());
keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp);
String nativeLibraryDirectory = getApplicationInfo().nativeLibraryDir;
String tmpDir;

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2012-2023 Arne Schwabe
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
*/
package de.blinkt.openvpn.core;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.VpnService;
import android.os.PersistableBundle;
import de.blinkt.openvpn.LaunchVPN;
import de.blinkt.openvpn.VpnProfile;
/**
* This is a task that is run periodically to restart the VPN if tit has died for
* some reason in the background
*/
public class keepVPNAlive extends JobService implements VpnStatus.StateListener {
private ConnectionStatus mLevel = ConnectionStatus.UNKNOWN_LEVEL;
private static final int JOBID_KEEPVPNALIVE = 6231;
@Override
public void onCreate() {
super.onCreate();
VpnStatus.addStateListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
VpnStatus.removeStateListener(this);
}
@Override
public boolean onStartJob(JobParameters jobParameters) {
if (mLevel == ConnectionStatus.UNKNOWN_LEVEL || mLevel == ConnectionStatus.LEVEL_NOTCONNECTED) {
String vpnUUID = jobParameters.getExtras().getString(LaunchVPN.EXTRA_KEY);
VpnProfile vp = ProfileManager.get(this, vpnUUID);
if (vp == null) {
VpnStatus.logError("Keepalive service cannot find VPN");
unscheduleKeepVPNAliveJobService(this);
return false;
}
VPNLaunchHelper.startOpenVpn(vp, getApplicationContext(), "VPN keep alive Job");
} else {
VpnStatus.logDebug("Keepalive service called but VPN still connected.");
}
/* The job has finished */
return false;
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
/* not doing anything */
return true;
}
@Override
public void updateState(String state, String logmessage,
int localizedResId, ConnectionStatus level, Intent Intent) {
mLevel = level;
}
@Override
public void setConnectedVPN(String uuid) {
}
public static void scheduleKeepVPNAliveJobService(Context c, VpnProfile vp) {
ComponentName keepVPNAliveComponent = new ComponentName(c, keepVPNAlive.class);
JobInfo.Builder jib = new JobInfo.Builder(JOBID_KEEPVPNALIVE, keepVPNAliveComponent);
/* set the VPN that should be restarted if we get killed */
PersistableBundle extraBundle = new PersistableBundle();
extraBundle.putString(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, vp.getUUIDString());
jib.setExtras(extraBundle);
/* periodic timing */
/* The current limits are 15 minutes and 5 minutes for flex and periodic timer
* but we use a minimum of 5 minutes and 2 minutes to avoid problems if there is some
* strange Android build that allows lower lmits.
*/
long initervalMillis = Math.max(JobInfo.getMinPeriodMillis(), 5 * 60 * 1000L);
long flexMillis = Math.max(JobInfo.getMinFlexMillis(), 2 * 60 * 1000L);
jib.setPeriodic(initervalMillis, flexMillis);
jib.setPersisted(true);
JobScheduler jobScheduler = c.getSystemService(JobScheduler.class);
jobScheduler.schedule(jib.build());
VpnStatus.logDebug("Scheduling VPN keep alive for VPN " + vp.mName);
}
public static void unscheduleKeepVPNAliveJobService(Context c) {
JobScheduler jobScheduler = c.getSystemService(JobScheduler.class);
jobScheduler.cancel(JOBID_KEEPVPNALIVE);
VpnStatus.logDebug("Unscheduling VPN keep alive");
}
}