summaryrefslogtreecommitdiff
path: root/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java')
-rw-r--r--main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java134
1 files changed, 134 insertions, 0 deletions
diff --git a/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java b/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java
new file mode 100644
index 00000000..b4264aba
--- /dev/null
+++ b/main/src/main/java/de/blinkt/openvpn/core/keepVPNAlive.java
@@ -0,0 +1,134 @@
+/*
+ * 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.Build;
+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(getMinPeriodMillis(), 5 * 60 * 1000L);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ long flexMillis = Math.max(JobInfo.getMinFlexMillis(), 2 * 60 * 1000L);
+ jib.setPeriodic(initervalMillis, flexMillis);
+ }
+ else
+ {
+ jib.setPeriodic(initervalMillis);
+ }
+ jib.setPersisted(true);
+
+ JobScheduler jobScheduler = null;
+ jobScheduler = getJobScheduler(c);
+
+ jobScheduler.schedule(jib.build());
+ VpnStatus.logDebug("Scheduling VPN keep alive for VPN " + vp.mName);
+ }
+
+ private static JobScheduler getJobScheduler(Context c) {
+ JobScheduler jobScheduler;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ jobScheduler = c.getSystemService(JobScheduler.class);
+
+ } else {
+ jobScheduler = (JobScheduler) c.getSystemService(JOB_SCHEDULER_SERVICE);
+ }
+ return jobScheduler;
+ }
+
+ private static long getMinPeriodMillis() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return JobInfo.getMinPeriodMillis();
+ } else {
+ return 15 * 60 * 1000L; // 15 minutes
+ }
+ }
+
+ public static void unscheduleKeepVPNAliveJobService(Context c) {
+ JobScheduler jobScheduler = getJobScheduler(c);
+ jobScheduler.cancel(JOBID_KEEPVPNALIVE);
+ VpnStatus.logDebug("Unscheduling VPN keep alive");
+ }
+}