Merge branch 'android-scheduler'
Starting with Android 6, the system will aggressively suspend apps when the device is idle (Doze mode). With Android 10 on a Pixel 4 this seems to happen after about 70 minutes. Then the scheduler thread in our default scheduler is only woken rarely, combined with our previous use of the monotonic clock it meant that events were executed with severe delays and noticing that there was such a delay. This was particularly bad in regards to NAT keepalives as it usually meant that the device was not reachable anymore from the outside. Some changes here try to improve that situation, e.g. the clock is switched to CLOCK_REALTIME (Bionic doesn't support CLOCK_BOOTTIME for condvars) so we can measure the actual difference e.g. since the last outbound message, other changes try to ensure that connectivity is restored after being asleep for a while (send DPD instead of keepalive after a long delay, send DPD even if path to peer stays the same). However, the most significant change is the replacement of the default scheduler with one specifically designed for Android. It schedules long-term events via AlarmManager, which allows waking up the app even if the system put it to sleep. The latter requires adding the app to the system's battery optimization whitelist, which is requested from the user automatically if necessary. With this, NAT keepalives and rekeyings are now scheduled accurately, with little changes to the battery usage. If the app is not whitelisted (there is a setting to ignore this), events are delayed by up to 15 minutes after about 70 minutes, so behind a NAT the device won't be reachable from the outside afterwards (connectivity should be restored as soon as the device is woken from deep sleep by the user). Fixes #3364.
This commit is contained in:
commit
a22a1493c3
|
@ -40,6 +40,17 @@ charon.cache_crls = no
|
||||||
Certification Authority (CA) to **/etc/ipsec.d/crls** (stroke) or
|
Certification Authority (CA) to **/etc/ipsec.d/crls** (stroke) or
|
||||||
**/etc/swanctl/x509crl** (vici), respectively.
|
**/etc/swanctl/x509crl** (vici), respectively.
|
||||||
|
|
||||||
|
charon.check_current_path = no
|
||||||
|
Whether to use DPD to check if the current path still works after any
|
||||||
|
changes to interfaces/addresses.
|
||||||
|
|
||||||
|
By default, after detecting any changes to interfaces and/or addresses no
|
||||||
|
action is taken if the current path to the remote peer still looks usable.
|
||||||
|
Enabling this option will use DPD to check if the path actually still works,
|
||||||
|
or, for instance, the peer removed the state after a longer phase without
|
||||||
|
connectivity. It will also trigger a MOBIKE update if NAT mappings were
|
||||||
|
removed during the downtime.
|
||||||
|
|
||||||
charon.cisco_unity = no
|
charon.cisco_unity = no
|
||||||
Send Cisco Unity vendor ID payload (IKEv1 only).
|
Send Cisco Unity vendor ID payload (IKEv1 only).
|
||||||
|
|
||||||
|
@ -220,6 +231,11 @@ charon.interfaces_use
|
||||||
charon.keep_alive = 20s
|
charon.keep_alive = 20s
|
||||||
NAT keep alive interval.
|
NAT keep alive interval.
|
||||||
|
|
||||||
|
charon.keep_alive_dpd_margin = 0s
|
||||||
|
Number of seconds the keep alive interval may be exceeded before a DPD is
|
||||||
|
sent instead of a NAT keep alive (0 to disable). This is only useful if a
|
||||||
|
clock is used that includes time spent suspended (e.g. CLOCK_BOOTTIME).
|
||||||
|
|
||||||
charon.leak_detective.detailed = yes
|
charon.leak_detective.detailed = yes
|
||||||
Includes source file names and line numbers in leak detective output.
|
Includes source file names and line numbers in leak detective output.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2012-2018 Tobias Brunner
|
Copyright (C) 2012-2020 Tobias Brunner
|
||||||
Copyright (C) 2012 Giuliano Grassi
|
Copyright (C) 2012 Giuliano Grassi
|
||||||
Copyright (C) 2012 Ralf Sager
|
Copyright (C) 2012 Ralf Sager
|
||||||
HSR Hochschule fuer Technik Rapperswil
|
HSR Hochschule fuer Technik Rapperswil
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".logic.StrongSwanApplication"
|
android:name=".logic.StrongSwanApplication"
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Tobias Brunner
|
||||||
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.strongswan.android.logic;
|
||||||
|
|
||||||
|
import android.app.AlarmManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
|
public class Scheduler extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
private final String EXECUTE_JOB = "org.strongswan.android.Scheduler.EXECUTE_JOB";
|
||||||
|
private final Context mContext;
|
||||||
|
private final AlarmManager mManager;
|
||||||
|
private final PriorityQueue<ScheduledJob> mJobs;
|
||||||
|
|
||||||
|
public Scheduler(Context context)
|
||||||
|
{
|
||||||
|
mContext = context;
|
||||||
|
mManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
|
||||||
|
mJobs = new PriorityQueue<>();
|
||||||
|
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(EXECUTE_JOB);
|
||||||
|
mContext.registerReceiver(this, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all pending jobs and unregister the receiver.
|
||||||
|
* Called via JNI.
|
||||||
|
*/
|
||||||
|
public void Terminate()
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
mJobs.clear();
|
||||||
|
}
|
||||||
|
mManager.cancel(createIntent());
|
||||||
|
mContext.unregisterReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a job ID. Called via JNI.
|
||||||
|
*
|
||||||
|
* @return random ID for a new job
|
||||||
|
*/
|
||||||
|
public String allocateId()
|
||||||
|
{
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a pending intent to execute a job.
|
||||||
|
*
|
||||||
|
* @return pending intent
|
||||||
|
*/
|
||||||
|
private PendingIntent createIntent()
|
||||||
|
{
|
||||||
|
/* using component/class doesn't work with dynamic broadcast receivers */
|
||||||
|
Intent intent = new Intent(EXECUTE_JOB);
|
||||||
|
intent.setPackage(mContext.getPackageName());
|
||||||
|
return PendingIntent.getBroadcast(mContext, 0, intent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule executing a job in the future.
|
||||||
|
* Called via JNI from different threads.
|
||||||
|
*
|
||||||
|
* @param id job ID
|
||||||
|
* @param ms delta in milliseconds when the job should be executed
|
||||||
|
*/
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
public void scheduleJob(String id, long ms)
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
ScheduledJob job = new ScheduledJob(id, System.currentTimeMillis() + ms);
|
||||||
|
mJobs.add(job);
|
||||||
|
|
||||||
|
if (job == mJobs.peek())
|
||||||
|
{ /* update the alarm if the job has to be executed before all others */
|
||||||
|
PendingIntent pending = createIntent();
|
||||||
|
mManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, job.Time, pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
ArrayList<ScheduledJob> jobs = new ArrayList<>();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
ScheduledJob job = mJobs.peek();
|
||||||
|
while (job != null)
|
||||||
|
{
|
||||||
|
if (job.Time > now)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
jobs.add(mJobs.remove());
|
||||||
|
job = mJobs.peek();
|
||||||
|
}
|
||||||
|
if (job != null)
|
||||||
|
{
|
||||||
|
PendingIntent pending = createIntent();
|
||||||
|
mManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, job.Time, pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ScheduledJob job : jobs)
|
||||||
|
{
|
||||||
|
executeJob(job.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job with the given ID.
|
||||||
|
*
|
||||||
|
* @param id job ID
|
||||||
|
*/
|
||||||
|
public native void executeJob(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of scheduled jobs.
|
||||||
|
*/
|
||||||
|
private static class ScheduledJob implements Comparable<ScheduledJob>
|
||||||
|
{
|
||||||
|
String Id;
|
||||||
|
long Time;
|
||||||
|
|
||||||
|
ScheduledJob(String id, long time)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ScheduledJob o)
|
||||||
|
{
|
||||||
|
return Long.compare(Time, o.Time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,7 +66,7 @@ public class MainActivity extends AppCompatActivity implements OnVpnProfileSelec
|
||||||
ActionBar bar = getSupportActionBar();
|
ActionBar bar = getSupportActionBar();
|
||||||
bar.setDisplayShowHomeEnabled(true);
|
bar.setDisplayShowHomeEnabled(true);
|
||||||
bar.setDisplayShowTitleEnabled(false);
|
bar.setDisplayShowTitleEnabled(false);
|
||||||
bar.setIcon(R.drawable.ic_launcher);
|
bar.setIcon(R.mipmap.ic_app);
|
||||||
|
|
||||||
/* load CA certificates in a background task */
|
/* load CA certificates in a background task */
|
||||||
new LoadCertificatesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
new LoadCertificatesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class TrustedCertificateImportActivity extends AppCompatActivity
|
||||||
certificate = (X509Certificate)getArguments().getSerializable(VpnProfileDataSource.KEY_CERTIFICATE);
|
certificate = (X509Certificate)getArguments().getSerializable(VpnProfileDataSource.KEY_CERTIFICATE);
|
||||||
|
|
||||||
return new AlertDialog.Builder(getActivity())
|
return new AlertDialog.Builder(getActivity())
|
||||||
.setIcon(R.drawable.ic_launcher)
|
.setIcon(R.mipmap.ic_app)
|
||||||
.setTitle(R.string.import_certificate)
|
.setTitle(R.string.import_certificate)
|
||||||
.setMessage(certificate.getSubjectDN().toString())
|
.setMessage(certificate.getSubjectDN().toString())
|
||||||
.setPositiveButton(R.string.import_certificate, new DialogInterface.OnClickListener()
|
.setPositiveButton(R.string.import_certificate, new DialogInterface.OnClickListener()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2018 Tobias Brunner
|
* Copyright (C) 2012-2020 Tobias Brunner
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -19,12 +19,18 @@ import android.app.Dialog;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
import android.net.VpnService;
|
import android.net.VpnService;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
@ -36,13 +42,16 @@ import org.strongswan.android.data.VpnProfileDataSource;
|
||||||
import org.strongswan.android.data.VpnType.VpnTypeFeature;
|
import org.strongswan.android.data.VpnType.VpnTypeFeature;
|
||||||
import org.strongswan.android.logic.VpnStateService;
|
import org.strongswan.android.logic.VpnStateService;
|
||||||
import org.strongswan.android.logic.VpnStateService.State;
|
import org.strongswan.android.logic.VpnStateService.State;
|
||||||
|
import org.strongswan.android.utils.Constants;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.app.AppCompatDialogFragment;
|
import androidx.appcompat.app.AppCompatDialogFragment;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
public class VpnProfileControlActivity extends AppCompatActivity
|
public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
{
|
{
|
||||||
|
@ -51,6 +60,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
|
public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
|
||||||
|
|
||||||
private static final int PREPARE_VPN_SERVICE = 0;
|
private static final int PREPARE_VPN_SERVICE = 0;
|
||||||
|
private static final int ADD_TO_POWER_WHITELIST = 1;
|
||||||
private static final String WAITING_FOR_RESULT = "WAITING_FOR_RESULT";
|
private static final String WAITING_FOR_RESULT = "WAITING_FOR_RESULT";
|
||||||
private static final String PROFILE_NAME = "PROFILE_NAME";
|
private static final String PROFILE_NAME = "PROFILE_NAME";
|
||||||
private static final String PROFILE_REQUIRES_PASSWORD = "REQUIRES_PASSWORD";
|
private static final String PROFILE_REQUIRES_PASSWORD = "REQUIRES_PASSWORD";
|
||||||
|
@ -181,6 +191,29 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we are on the system's power whitelist, if necessary, or ask the user
|
||||||
|
* to add us.
|
||||||
|
* @return true if profile can be initiated immediately
|
||||||
|
*/
|
||||||
|
private boolean checkPowerWhitelist()
|
||||||
|
{
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
|
{
|
||||||
|
PowerManager pm = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
|
||||||
|
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
if (!pm.isIgnoringBatteryOptimizations(this.getPackageName()) &&
|
||||||
|
!pref.getBoolean(Constants.PREF_IGNORE_POWER_WHITELIST, false))
|
||||||
|
{
|
||||||
|
PowerWhitelistRequired whitelist = new PowerWhitelistRequired();
|
||||||
|
mWaitingForResult = true;
|
||||||
|
whitelist.show(getSupportFragmentManager(), DIALOG_TAG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
protected void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||||
{
|
{
|
||||||
|
@ -189,6 +222,8 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
case PREPARE_VPN_SERVICE:
|
case PREPARE_VPN_SERVICE:
|
||||||
mWaitingForResult = false;
|
mWaitingForResult = false;
|
||||||
if (resultCode == RESULT_OK && mProfileInfo != null)
|
if (resultCode == RESULT_OK && mProfileInfo != null)
|
||||||
|
{
|
||||||
|
if (checkPowerWhitelist())
|
||||||
{
|
{
|
||||||
if (mService != null)
|
if (mService != null)
|
||||||
{
|
{
|
||||||
|
@ -196,6 +231,7 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{ /* this happens if the always-on VPN feature is activated by a different app or the user declined */
|
{ /* this happens if the always-on VPN feature is activated by a different app or the user declined */
|
||||||
if (getSupportFragmentManager().isStateSaved())
|
if (getSupportFragmentManager().isStateSaved())
|
||||||
|
@ -207,6 +243,14 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
VpnNotSupportedError.showWithMessage(this, R.string.vpn_not_supported_no_permission);
|
VpnNotSupportedError.showWithMessage(this, R.string.vpn_not_supported_no_permission);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ADD_TO_POWER_WHITELIST:
|
||||||
|
mWaitingForResult = false;
|
||||||
|
if (mProfileInfo != null && mService != null)
|
||||||
|
{
|
||||||
|
mService.connect(mProfileInfo, true);
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
|
@ -531,6 +575,32 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that displays a warning before asking the user to add the app to the
|
||||||
|
* device's power whitelist.
|
||||||
|
*/
|
||||||
|
public static class PowerWhitelistRequired extends AppCompatDialogFragment
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
return new AlertDialog.Builder(getActivity())
|
||||||
|
.setTitle(R.string.power_whitelist_title)
|
||||||
|
.setMessage(R.string.power_whitelist_text)
|
||||||
|
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||||
|
Uri.parse("package:" + getActivity().getPackageName()));
|
||||||
|
getActivity().startActivityForResult(intent, ADD_TO_POWER_WHITELIST);
|
||||||
|
}).create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel(@NonNull DialogInterface dialog)
|
||||||
|
{
|
||||||
|
getActivity().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing an error message which is displayed if VpnService is
|
* Class representing an error message which is displayed if VpnService is
|
||||||
* not supported on the current device.
|
* not supported on the current device.
|
||||||
|
@ -556,7 +626,6 @@ public class VpnProfileControlActivity extends AppCompatActivity
|
||||||
return new AlertDialog.Builder(getActivity())
|
return new AlertDialog.Builder(getActivity())
|
||||||
.setTitle(R.string.vpn_not_supported_title)
|
.setTitle(R.string.vpn_not_supported_title)
|
||||||
.setMessage(messageId)
|
.setMessage(messageId)
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Tobias Brunner
|
* Copyright (C) 2018-2019 Tobias Brunner
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -39,6 +39,7 @@ import org.strongswan.android.utils.Constants;
|
||||||
@TargetApi(Build.VERSION_CODES.N)
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
public class VpnTileService extends TileService implements VpnStateService.VpnStateListener
|
public class VpnTileService extends TileService implements VpnStateService.VpnStateListener
|
||||||
{
|
{
|
||||||
|
private boolean mListening;
|
||||||
private VpnProfileDataSource mDataSource;
|
private VpnProfileDataSource mDataSource;
|
||||||
private VpnStateService mService;
|
private VpnStateService mService;
|
||||||
private final ServiceConnection mServiceConnection = new ServiceConnection()
|
private final ServiceConnection mServiceConnection = new ServiceConnection()
|
||||||
|
@ -53,7 +54,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
|
||||||
public void onServiceConnected(ComponentName name, IBinder service)
|
public void onServiceConnected(ComponentName name, IBinder service)
|
||||||
{
|
{
|
||||||
mService = ((VpnStateService.LocalBinder)service).getService();
|
mService = ((VpnStateService.LocalBinder)service).getService();
|
||||||
if (mDataSource != null)
|
if (mListening && mDataSource != null)
|
||||||
{
|
{
|
||||||
mService.registerListener(VpnTileService.this);
|
mService.registerListener(VpnTileService.this);
|
||||||
updateTile();
|
updateTile();
|
||||||
|
@ -69,6 +70,9 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
|
||||||
Context context = getApplicationContext();
|
Context context = getApplicationContext();
|
||||||
context.bindService(new Intent(context, VpnStateService.class),
|
context.bindService(new Intent(context, VpnStateService.class),
|
||||||
mServiceConnection, Service.BIND_AUTO_CREATE);
|
mServiceConnection, Service.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
|
mDataSource = new VpnProfileDataSource(this);
|
||||||
|
mDataSource.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,15 +84,15 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
|
||||||
{
|
{
|
||||||
getApplicationContext().unbindService(mServiceConnection);
|
getApplicationContext().unbindService(mServiceConnection);
|
||||||
}
|
}
|
||||||
|
mDataSource.close();
|
||||||
|
mDataSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartListening()
|
public void onStartListening()
|
||||||
{
|
{
|
||||||
super.onStartListening();
|
super.onStartListening();
|
||||||
|
mListening = true;
|
||||||
mDataSource = new VpnProfileDataSource(this);
|
|
||||||
mDataSource.open();
|
|
||||||
|
|
||||||
if (mService != null)
|
if (mService != null)
|
||||||
{
|
{
|
||||||
|
@ -101,14 +105,12 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
|
||||||
public void onStopListening()
|
public void onStopListening()
|
||||||
{
|
{
|
||||||
super.onStopListening();
|
super.onStopListening();
|
||||||
|
mListening = false;
|
||||||
|
|
||||||
if (mService != null)
|
if (mService != null)
|
||||||
{
|
{
|
||||||
mService.unregisterListener(this);
|
mService.unregisterListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDataSource.close();
|
|
||||||
mDataSource = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private VpnProfile getProfile()
|
private VpnProfile getProfile()
|
||||||
|
@ -119,8 +121,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
|
||||||
{
|
{
|
||||||
uuid = pref.getString(Constants.PREF_MRU_VPN_PROFILE, null);
|
uuid = pref.getString(Constants.PREF_MRU_VPN_PROFILE, null);
|
||||||
}
|
}
|
||||||
|
return mDataSource != null ? mDataSource.getVpnProfile(uuid) : null;
|
||||||
return mDataSource.getVpnProfile(uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -134,7 +135,7 @@ public class VpnTileService extends TileService implements VpnStateService.VpnSt
|
||||||
{
|
{
|
||||||
profile = getProfile();
|
profile = getProfile();
|
||||||
}
|
}
|
||||||
else
|
else if (mDataSource != null)
|
||||||
{ /* always get the plain profile without cached password */
|
{ /* always get the plain profile without cached password */
|
||||||
profile = mDataSource.getVpnProfile(profile.getId());
|
profile = mDataSource.getVpnProfile(profile.getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016-2018 Tobias Brunner
|
* Copyright (C) 2016-2020 Tobias Brunner
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -58,4 +58,9 @@ public final class Constants
|
||||||
* Preference key to store the most recently used VPN profile
|
* Preference key to store the most recently used VPN profile
|
||||||
*/
|
*/
|
||||||
public static final String PREF_MRU_VPN_PROFILE = "pref_mru_vpn_profile";
|
public static final String PREF_MRU_VPN_PROFILE = "pref_mru_vpn_profile";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference key to store whether the user permanently dismissed our warning to add the app to the power whitelist
|
||||||
|
*/
|
||||||
|
public static final String PREF_IGNORE_POWER_WHITELIST = "pref_ignore_power_whitelist";
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ backend/android_creds.c \
|
||||||
backend/android_fetcher.c \
|
backend/android_fetcher.c \
|
||||||
backend/android_dns_proxy.c \
|
backend/android_dns_proxy.c \
|
||||||
backend/android_private_key.c \
|
backend/android_private_key.c \
|
||||||
|
backend/android_scheduler.c \
|
||||||
backend/android_service.c \
|
backend/android_service.c \
|
||||||
charonservice.c \
|
charonservice.c \
|
||||||
kernel/android_ipsec.c \
|
kernel/android_ipsec.c \
|
||||||
|
|
|
@ -58,6 +58,7 @@ typedef enum {
|
||||||
ANDROID_JELLY_BEAN_MR1 = 17,
|
ANDROID_JELLY_BEAN_MR1 = 17,
|
||||||
ANDROID_JELLY_BEAN_MR2 = 18,
|
ANDROID_JELLY_BEAN_MR2 = 18,
|
||||||
ANDROID_LOLLIPOP = 21,
|
ANDROID_LOLLIPOP = 21,
|
||||||
|
ANDROID_MARSHMALLOW = 23,
|
||||||
} android_sdk_version_t;
|
} android_sdk_version_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,330 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Tobias Brunner
|
||||||
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. *
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include "android_scheduler.h"
|
||||||
|
#include "../android_jni.h"
|
||||||
|
|
||||||
|
#include <collections/hashtable.h>
|
||||||
|
#include <processing/jobs/callback_job.h>
|
||||||
|
#include <threading/mutex.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Threshold in milliseconds up to which the default scheduler is used.
|
||||||
|
* This includes the roaming events (100 ms) and initial retransmits.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_SCHEDULER_THRESHOLD 3000
|
||||||
|
|
||||||
|
typedef struct private_scheduler_t private_scheduler_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data.
|
||||||
|
*/
|
||||||
|
struct private_scheduler_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public interface.
|
||||||
|
*/
|
||||||
|
scheduler_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to Scheduler object.
|
||||||
|
*/
|
||||||
|
jobject obj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java class for Scheduler.
|
||||||
|
*/
|
||||||
|
jclass cls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hashtable that stores scheduled jobs (entry_t*).
|
||||||
|
*/
|
||||||
|
hashtable_t *jobs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex to safely access the scheduled jobs.
|
||||||
|
*/
|
||||||
|
mutex_t *mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default scheduler used for short-term events.
|
||||||
|
*/
|
||||||
|
scheduler_t *default_scheduler;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for scheduled jobs.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random identifier as string.
|
||||||
|
*/
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scheduled job.
|
||||||
|
*/
|
||||||
|
job_t *job;
|
||||||
|
|
||||||
|
} entry_t;
|
||||||
|
|
||||||
|
CALLBACK(destroy_entry, void,
|
||||||
|
entry_t *this, const void *key)
|
||||||
|
{
|
||||||
|
DESTROY_IF(this->job);
|
||||||
|
free(this->id);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNI_METHOD(Scheduler, executeJob, void,
|
||||||
|
jstring jid)
|
||||||
|
{
|
||||||
|
private_scheduler_t *sched;
|
||||||
|
entry_t *entry;
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
sched = (private_scheduler_t*)lib->scheduler;
|
||||||
|
id = androidjni_convert_jstring(env, jid);
|
||||||
|
sched->mutex->lock(sched->mutex);
|
||||||
|
entry = sched->jobs->remove(sched->jobs, id);
|
||||||
|
sched->mutex->unlock(sched->mutex);
|
||||||
|
free(id);
|
||||||
|
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
lib->processor->queue_job(lib->processor, entry->job);
|
||||||
|
entry->job = NULL;
|
||||||
|
destroy_entry(entry, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(scheduler_t, get_job_load, u_int,
|
||||||
|
private_scheduler_t *this)
|
||||||
|
{
|
||||||
|
u_int count;
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
count = this->jobs->get_count(this->jobs);
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate an ID for a new job. We do this via JNI so we don't have to rely
|
||||||
|
* on RNGs being available when we replace the default scheduler.
|
||||||
|
*/
|
||||||
|
static jstring allocate_id(private_scheduler_t *this, JNIEnv *env)
|
||||||
|
{
|
||||||
|
jmethodID method_id;
|
||||||
|
|
||||||
|
method_id = (*env)->GetMethodID(env, this->cls, "allocateId",
|
||||||
|
"()Ljava/lang/String;");
|
||||||
|
if (!method_id)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return (*env)->CallObjectMethod(env, this->obj, method_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(scheduler_t, schedule_job_ms, void,
|
||||||
|
private_scheduler_t *this, job_t *job, uint32_t ms)
|
||||||
|
{
|
||||||
|
JNIEnv *env;
|
||||||
|
jmethodID method_id;
|
||||||
|
entry_t *entry = NULL;
|
||||||
|
jstring jid;
|
||||||
|
|
||||||
|
/* use the default scheduler for short-term events */
|
||||||
|
if (ms <= DEFAULT_SCHEDULER_THRESHOLD)
|
||||||
|
{
|
||||||
|
this->default_scheduler->schedule_job_ms(this->default_scheduler,
|
||||||
|
job, ms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
androidjni_attach_thread(&env);
|
||||||
|
jid = allocate_id(this, env);
|
||||||
|
if (!jid)
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
method_id = (*env)->GetMethodID(env, this->cls, "scheduleJob",
|
||||||
|
"(Ljava/lang/String;J)V");
|
||||||
|
if (!method_id)
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
INIT(entry,
|
||||||
|
.id = androidjni_convert_jstring(env, jid),
|
||||||
|
.job = job,
|
||||||
|
);
|
||||||
|
job->status = JOB_STATUS_QUEUED;
|
||||||
|
this->jobs->put(this->jobs, entry->id, entry);
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
(*env)->CallVoidMethod(env, this->obj, method_id, jid, (jlong)ms);
|
||||||
|
if (androidjni_exception_occurred(env))
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
androidjni_detach_thread();
|
||||||
|
return;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
DBG1(DBG_JOB, "unable to schedule job for execution in %u ms", ms);
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
this->jobs->remove(this->jobs, entry->id);
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
destroy_entry(entry, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
job->destroy(job);
|
||||||
|
}
|
||||||
|
androidjni_exception_occurred(env);
|
||||||
|
androidjni_detach_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(scheduler_t, schedule_job_tv, void,
|
||||||
|
private_scheduler_t *this, job_t *job, timeval_t tv)
|
||||||
|
{
|
||||||
|
timeval_t now;
|
||||||
|
|
||||||
|
time_monotonic(&now);
|
||||||
|
|
||||||
|
if (!timercmp(&now, &tv, <))
|
||||||
|
{
|
||||||
|
/* already expired, just send it to the processor */
|
||||||
|
lib->processor->queue_job(lib->processor, job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timersub(&tv, &now, &now);
|
||||||
|
schedule_job_ms(this, job, now.tv_sec * 1000 + now.tv_usec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(scheduler_t, schedule_job, void,
|
||||||
|
private_scheduler_t *this, job_t *job, uint32_t s)
|
||||||
|
{
|
||||||
|
schedule_job_ms(this, job, s * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(scheduler_t, flush, void,
|
||||||
|
private_scheduler_t *this)
|
||||||
|
{
|
||||||
|
JNIEnv *env;
|
||||||
|
jmethodID method_id;
|
||||||
|
|
||||||
|
this->default_scheduler->flush(this->default_scheduler);
|
||||||
|
|
||||||
|
this->mutex->lock(this->mutex);
|
||||||
|
this->jobs->destroy_function(this->jobs, destroy_entry);
|
||||||
|
this->jobs = hashtable_create(hashtable_hash_str, hashtable_equals_str, 16);
|
||||||
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
|
androidjni_attach_thread(&env);
|
||||||
|
method_id = (*env)->GetMethodID(env, this->cls, "Terminate", "()V");
|
||||||
|
if (!method_id)
|
||||||
|
{
|
||||||
|
androidjni_exception_occurred(env);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*env)->CallVoidMethod(env, this->obj, method_id);
|
||||||
|
androidjni_exception_occurred(env);
|
||||||
|
}
|
||||||
|
androidjni_detach_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(scheduler_t, destroy, void,
|
||||||
|
private_scheduler_t *this)
|
||||||
|
{
|
||||||
|
JNIEnv *env;
|
||||||
|
|
||||||
|
androidjni_attach_thread(&env);
|
||||||
|
if (this->obj)
|
||||||
|
{
|
||||||
|
(*env)->DeleteGlobalRef(env, this->obj);
|
||||||
|
}
|
||||||
|
if (this->cls)
|
||||||
|
{
|
||||||
|
(*env)->DeleteGlobalRef(env, this->cls);
|
||||||
|
}
|
||||||
|
androidjni_detach_thread();
|
||||||
|
this->default_scheduler->destroy(this->default_scheduler);
|
||||||
|
this->mutex->destroy(this->mutex);
|
||||||
|
this->jobs->destroy(this->jobs);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header
|
||||||
|
*/
|
||||||
|
scheduler_t *android_scheduler_create(jobject context, scheduler_t *scheduler)
|
||||||
|
{
|
||||||
|
private_scheduler_t *this;
|
||||||
|
JNIEnv *env;
|
||||||
|
jmethodID method_id;
|
||||||
|
jobject obj;
|
||||||
|
jclass cls;
|
||||||
|
|
||||||
|
INIT(this,
|
||||||
|
.public = {
|
||||||
|
.get_job_load = _get_job_load,
|
||||||
|
.schedule_job = _schedule_job,
|
||||||
|
.schedule_job_ms = _schedule_job_ms,
|
||||||
|
.schedule_job_tv = _schedule_job_tv,
|
||||||
|
.flush = _flush,
|
||||||
|
.destroy = _destroy,
|
||||||
|
},
|
||||||
|
.default_scheduler = scheduler,
|
||||||
|
.jobs = hashtable_create(hashtable_hash_str, hashtable_equals_str, 16),
|
||||||
|
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||||
|
);
|
||||||
|
|
||||||
|
androidjni_attach_thread(&env);
|
||||||
|
cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/Scheduler");
|
||||||
|
if (!cls)
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
this->cls = (*env)->NewGlobalRef(env, cls);
|
||||||
|
method_id = (*env)->GetMethodID(env, cls, "<init>",
|
||||||
|
"(Landroid/content/Context;)V");
|
||||||
|
if (!method_id)
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
obj = (*env)->NewObject(env, cls, method_id, context);
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
this->obj = (*env)->NewGlobalRef(env, obj);
|
||||||
|
androidjni_detach_thread();
|
||||||
|
return &this->public;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
DBG1(DBG_JOB, "failed to create Scheduler object");
|
||||||
|
androidjni_exception_occurred(env);
|
||||||
|
androidjni_detach_thread();
|
||||||
|
destroy(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Tobias Brunner
|
||||||
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup android_scheduler android_scheduler
|
||||||
|
* @{ @ingroup android_backend
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANDROID_SCHEDULER_H_
|
||||||
|
#define ANDROID_SCHEDULER_H_
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <processing/scheduler.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an Android-specific scheduler_t implementation.
|
||||||
|
*
|
||||||
|
* The given scheduler is used for short-term events. We can't destroy it anyway
|
||||||
|
* because of the scheduler job operating on it, and this way we can use it to
|
||||||
|
* avoid the overhead of broadcasts for some events.
|
||||||
|
*
|
||||||
|
* @param context Context object
|
||||||
|
* @param scheduler the default scheduler used as fallback
|
||||||
|
* @return scheduler_t instance
|
||||||
|
*/
|
||||||
|
scheduler_t *android_scheduler_create(jobject context, scheduler_t *scheduler);
|
||||||
|
|
||||||
|
#endif /** ANDROID_SCHEDULER_H_ @}*/
|
|
@ -754,13 +754,13 @@ static job_requeue_t initiate(private_android_service_t *this)
|
||||||
.unique = UNIQUE_REPLACE,
|
.unique = UNIQUE_REPLACE,
|
||||||
.rekey_time = 36000, /* 10h */
|
.rekey_time = 36000, /* 10h */
|
||||||
.jitter_time = 600, /* 10min */
|
.jitter_time = 600, /* 10min */
|
||||||
.over_time = 600, /* 10min */
|
.over_time = 1800, /* 30min */
|
||||||
};
|
};
|
||||||
child_cfg_create_t child = {
|
child_cfg_create_t child = {
|
||||||
.lifetime = {
|
.lifetime = {
|
||||||
.time = {
|
.time = {
|
||||||
.life = 3600, /* 1h */
|
.life = 9000, /* 2.5h */
|
||||||
.rekey = 3000, /* 50min */
|
.rekey = 7200, /* 2h */
|
||||||
.jitter = 300 /* 5min */
|
.jitter = 300 /* 5min */
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2019 Tobias Brunner
|
* Copyright (C) 2012-2020 Tobias Brunner
|
||||||
* Copyright (C) 2012 Giuliano Grassi
|
* Copyright (C) 2012 Giuliano Grassi
|
||||||
* Copyright (C) 2012 Ralf Sager
|
* Copyright (C) 2012 Ralf Sager
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
#include "backend/android_creds.h"
|
#include "backend/android_creds.h"
|
||||||
#include "backend/android_fetcher.h"
|
#include "backend/android_fetcher.h"
|
||||||
#include "backend/android_private_key.h"
|
#include "backend/android_private_key.h"
|
||||||
|
#include "backend/android_scheduler.h"
|
||||||
#include "backend/android_service.h"
|
#include "backend/android_service.h"
|
||||||
#include "kernel/android_ipsec.h"
|
#include "kernel/android_ipsec.h"
|
||||||
#include "kernel/android_net.h"
|
#include "kernel/android_net.h"
|
||||||
|
@ -45,6 +46,7 @@
|
||||||
#define ANDROID_RETRANSMIT_TIMEOUT 2.0
|
#define ANDROID_RETRANSMIT_TIMEOUT 2.0
|
||||||
#define ANDROID_RETRANSMIT_BASE 1.4
|
#define ANDROID_RETRANSMIT_BASE 1.4
|
||||||
#define ANDROID_KEEPALIVE_INTERVAL 45
|
#define ANDROID_KEEPALIVE_INTERVAL 45
|
||||||
|
#define ANDROID_KEEPALIVE_DPD_MARGIN 20
|
||||||
|
|
||||||
typedef struct private_charonservice_t private_charonservice_t;
|
typedef struct private_charonservice_t private_charonservice_t;
|
||||||
|
|
||||||
|
@ -434,6 +436,10 @@ static void initiate(settings_t *settings)
|
||||||
"charon.keep_alive",
|
"charon.keep_alive",
|
||||||
settings->get_int(settings, "global.nat_keepalive",
|
settings->get_int(settings, "global.nat_keepalive",
|
||||||
ANDROID_KEEPALIVE_INTERVAL));
|
ANDROID_KEEPALIVE_INTERVAL));
|
||||||
|
/* send DPDs if above interval is exceeded, use a static value for now */
|
||||||
|
lib->settings->set_int(lib->settings,
|
||||||
|
"charon.keep_alive_dpd_margin",
|
||||||
|
ANDROID_KEEPALIVE_DPD_MARGIN);
|
||||||
|
|
||||||
/* reload plugins after changing settings */
|
/* reload plugins after changing settings */
|
||||||
lib->plugins->reload(lib->plugins, NULL);
|
lib->plugins->reload(lib->plugins, NULL);
|
||||||
|
@ -499,6 +505,8 @@ static void set_options(char *logfile)
|
||||||
"charon.initiator_only", TRUE);
|
"charon.initiator_only", TRUE);
|
||||||
lib->settings->set_bool(lib->settings,
|
lib->settings->set_bool(lib->settings,
|
||||||
"charon.close_ike_on_child_failure", TRUE);
|
"charon.close_ike_on_child_failure", TRUE);
|
||||||
|
lib->settings->set_bool(lib->settings,
|
||||||
|
"charon.check_current_path", TRUE);
|
||||||
/* setting the source address breaks the VpnService.protect() function which
|
/* setting the source address breaks the VpnService.protect() function which
|
||||||
* uses SO_BINDTODEVICE internally. the addresses provided to the kernel as
|
* uses SO_BINDTODEVICE internally. the addresses provided to the kernel as
|
||||||
* auxiliary data have precedence over this option causing a routing loop if
|
* auxiliary data have precedence over this option causing a routing loop if
|
||||||
|
@ -613,6 +621,14 @@ static void segv_handler(int signal)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register this logger as default before we have the bus available
|
||||||
|
*/
|
||||||
|
static void __attribute__ ((constructor))register_logger()
|
||||||
|
{
|
||||||
|
dbg = dbg_android;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize charon and the libraries via JNI
|
* Initialize charon and the libraries via JNI
|
||||||
*/
|
*/
|
||||||
|
@ -623,9 +639,6 @@ JNI_METHOD(CharonVpnService, initializeCharon, jboolean,
|
||||||
struct utsname utsname;
|
struct utsname utsname;
|
||||||
char *logfile, *appdir, *plugins;
|
char *logfile, *appdir, *plugins;
|
||||||
|
|
||||||
/* logging for library during initialization, as we have no bus yet */
|
|
||||||
dbg = dbg_android;
|
|
||||||
|
|
||||||
/* initialize library */
|
/* initialize library */
|
||||||
if (!library_init(NULL, "charon"))
|
if (!library_init(NULL, "charon"))
|
||||||
{
|
{
|
||||||
|
@ -633,6 +646,12 @@ JNI_METHOD(CharonVpnService, initializeCharon, jboolean,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (android_sdk_version >= ANDROID_MARSHMALLOW)
|
||||||
|
{
|
||||||
|
/* use a custom scheduler so the app is woken when jobs have to run */
|
||||||
|
lib->scheduler = android_scheduler_create(this, lib->scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
/* set options before initializing other libraries that might read them */
|
/* set options before initializing other libraries that might read them */
|
||||||
logfile = androidjni_convert_jstring(env, jlogfile);
|
logfile = androidjni_convert_jstring(env, jlogfile);
|
||||||
|
|
||||||
|
@ -743,8 +762,6 @@ JNI_METHOD_P(org_strongswan_android_utils, Utils, isProposalValid, jboolean,
|
||||||
char *str;
|
char *str;
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
dbg = dbg_android;
|
|
||||||
|
|
||||||
if (!library_init(NULL, "charon"))
|
if (!library_init(NULL, "charon"))
|
||||||
{
|
{
|
||||||
library_deinit();
|
library_deinit();
|
||||||
|
@ -769,8 +786,6 @@ JNI_METHOD_P(org_strongswan_android_utils, Utils, parseInetAddressBytes, jbyteAr
|
||||||
host_t *host;
|
host_t *host;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
dbg = dbg_android;
|
|
||||||
|
|
||||||
if (!library_init(NULL, "charon"))
|
if (!library_init(NULL, "charon"))
|
||||||
{
|
{
|
||||||
library_deinit();
|
library_deinit();
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright (C) 2018 Tobias Brunner
|
|
||||||
HSR Hochschule fuer Technik Rapperswil
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of the GNU General Public License as published by the
|
|
||||||
Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
-->
|
|
||||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:drawable="@drawable/ic_launcher" />
|
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2012-2019 Tobias Brunner
|
Copyright (C) 2012-2020 Tobias Brunner
|
||||||
Copyright (C) 2012 Giuliano Grassi
|
Copyright (C) 2012 Giuliano Grassi
|
||||||
Copyright (C) 2012 Ralf Sager
|
Copyright (C) 2012 Ralf Sager
|
||||||
HSR Hochschule fuer Technik Rapperswil
|
HSR Hochschule fuer Technik Rapperswil
|
||||||
|
@ -36,6 +36,8 @@
|
||||||
<string name="pref_title">Einstellungen</string>
|
<string name="pref_title">Einstellungen</string>
|
||||||
<string name="pref_default_vpn_profile">Voreingestelltes VPN Profil</string>
|
<string name="pref_default_vpn_profile">Voreingestelltes VPN Profil</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Verbinden mit zuletzt verwendetem Profil</string>
|
<string name="pref_default_vpn_profile_mru">Verbinden mit zuletzt verwendetem Profil</string>
|
||||||
|
<string name="pref_power_whitelist_title">Akku-Optimierung ignorieren</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Keine Warnung anzeigen, falls die App nicht auf der weissen Liste für Akku-Optimierung ist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">Log</string>
|
<string name="log_title">Log</string>
|
||||||
|
@ -215,6 +217,8 @@
|
||||||
<item quantity="other">Wiederholen in %1$d Sekunden</item>
|
<item quantity="other">Wiederholen in %1$d Sekunden</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Wiederholen abbrechen</string>
|
<string name="cancel_retry">Wiederholen abbrechen</string>
|
||||||
|
<string name="power_whitelist_title">Akku-Optimierung deaktivieren</string>
|
||||||
|
<string name="power_whitelist_text">Bitte den nächsten Dialog bestätigen, um die App auf die weisse Liste für Akku-Optimierung zu setzen, so dass sie NAT keepalives und Rekeyings zeitlich korrekt planen kann, um konstant erreichbar zu bleiben während die VPN-Verbindung besteht.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">VPN umschalten</string>
|
<string name="tile_default">VPN umschalten</string>
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
<string name="pref_title">Settings</string>
|
<string name="pref_title">Settings</string>
|
||||||
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
||||||
|
<string name="pref_power_whitelist_title">Ignore battery optimizations</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Don\'t show a warning if the app is not on the device\'s power whitelist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">Log</string>
|
<string name="log_title">Log</string>
|
||||||
|
@ -215,6 +217,8 @@
|
||||||
<item quantity="other">Retry in %1$d seconds</item>
|
<item quantity="other">Retry in %1$d seconds</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Cancel retry</string>
|
<string name="cancel_retry">Cancel retry</string>
|
||||||
|
<string name="power_whitelist_title">Disable battery optimizations</string>
|
||||||
|
<string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">Toggle VPN</string>
|
<string name="tile_default">Toggle VPN</string>
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
<string name="pref_title">Settings</string>
|
<string name="pref_title">Settings</string>
|
||||||
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
||||||
|
<string name="pref_power_whitelist_title">Ignore battery optimizations</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Don\'t show a warning if the app is not on the device\'s power whitelist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">Журнал</string>
|
<string name="log_title">Журнал</string>
|
||||||
|
@ -212,6 +214,8 @@
|
||||||
<item quantity="other">Retry in %1$d seconds</item>
|
<item quantity="other">Retry in %1$d seconds</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Cancel retry</string>
|
<string name="cancel_retry">Cancel retry</string>
|
||||||
|
<string name="power_whitelist_title">Disable battery optimizations</string>
|
||||||
|
<string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">Toggle VPN</string>
|
<string name="tile_default">Toggle VPN</string>
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
<string name="pref_title">Settings</string>
|
<string name="pref_title">Settings</string>
|
||||||
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
||||||
|
<string name="pref_power_whitelist_title">Ignore battery optimizations</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Don\'t show a warning if the app is not on the device\'s power whitelist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">Журнал</string>
|
<string name="log_title">Журнал</string>
|
||||||
|
@ -213,6 +215,8 @@
|
||||||
<item quantity="other">Retry in %1$d seconds</item>
|
<item quantity="other">Retry in %1$d seconds</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Cancel retry</string>
|
<string name="cancel_retry">Cancel retry</string>
|
||||||
|
<string name="power_whitelist_title">Disable battery optimizations</string>
|
||||||
|
<string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">Toggle VPN</string>
|
<string name="tile_default">Toggle VPN</string>
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
<string name="pref_title">Settings</string>
|
<string name="pref_title">Settings</string>
|
||||||
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
||||||
|
<string name="pref_power_whitelist_title">Ignore battery optimizations</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Don\'t show a warning if the app is not on the device\'s power whitelist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">日志</string>
|
<string name="log_title">日志</string>
|
||||||
|
@ -212,6 +214,8 @@
|
||||||
<item quantity="other">Retry in %1$d seconds</item>
|
<item quantity="other">Retry in %1$d seconds</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Cancel retry</string>
|
<string name="cancel_retry">Cancel retry</string>
|
||||||
|
<string name="power_whitelist_title">Disable battery optimizations</string>
|
||||||
|
<string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">Toggle VPN</string>
|
<string name="tile_default">Toggle VPN</string>
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
<string name="pref_title">Settings</string>
|
<string name="pref_title">Settings</string>
|
||||||
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
||||||
|
<string name="pref_power_whitelist_title">Ignore battery optimizations</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Don\'t show a warning if the app is not on the device\'s power whitelist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">日誌</string>
|
<string name="log_title">日誌</string>
|
||||||
|
@ -212,6 +214,8 @@
|
||||||
<item quantity="other">Retry in %1$d seconds</item>
|
<item quantity="other">Retry in %1$d seconds</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Cancel retry</string>
|
<string name="cancel_retry">Cancel retry</string>
|
||||||
|
<string name="power_whitelist_title">Disable battery optimizations</string>
|
||||||
|
<string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">Toggle VPN</string>
|
<string name="tile_default">Toggle VPN</string>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2018 Tobias Brunner
|
Copyright (C) 2020 Tobias Brunner
|
||||||
HSR Hochschule fuer Technik Rapperswil
|
HSR Hochschule fuer Technik Rapperswil
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -13,5 +13,7 @@
|
||||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
for more details.
|
for more details.
|
||||||
-->
|
-->
|
||||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
<resources>
|
||||||
android:drawable="@drawable/ic_launcher" />
|
<mipmap name="ic_launcher">@mipmap/ic_app</mipmap>
|
||||||
|
<mipmap name="ic_shortcut">@mipmap/ic_app</mipmap>
|
||||||
|
</resources>
|
|
@ -36,6 +36,8 @@
|
||||||
<string name="pref_title">Settings</string>
|
<string name="pref_title">Settings</string>
|
||||||
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
<string name="pref_default_vpn_profile">Default VPN profile</string>
|
||||||
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
<string name="pref_default_vpn_profile_mru">Connect to most recently used profile</string>
|
||||||
|
<string name="pref_power_whitelist_title">Ignore battery optimizations</string>
|
||||||
|
<string name="pref_power_whitelist_summary">Don\'t show a warning if the app is not on the device\'s power whitelist</string>
|
||||||
|
|
||||||
<!-- Log view -->
|
<!-- Log view -->
|
||||||
<string name="log_title">Log</string>
|
<string name="log_title">Log</string>
|
||||||
|
@ -215,6 +217,8 @@
|
||||||
<item quantity="other">Retry in %1$d seconds</item>
|
<item quantity="other">Retry in %1$d seconds</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="cancel_retry">Cancel retry</string>
|
<string name="cancel_retry">Cancel retry</string>
|
||||||
|
<string name="power_whitelist_title">Disable battery optimizations</string>
|
||||||
|
<string name="power_whitelist_text">Please confirm the next dialog to add the app to the device\'s power whitelist so it can ignore battery optimizations and schedule NAT keep-alives and rekeyings accurately in order to constantly keep reachable while the VPN is established.</string>
|
||||||
|
|
||||||
<!-- Quick Settings tile -->
|
<!-- Quick Settings tile -->
|
||||||
<string name="tile_default">Toggle VPN</string>
|
<string name="tile_default">Toggle VPN</string>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2018 Tobias Brunner
|
Copyright (C) 2018-2020 Tobias Brunner
|
||||||
HSR Hochschule fuer Technik Rapperswil
|
HSR Hochschule fuer Technik Rapperswil
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -20,4 +20,9 @@
|
||||||
android:title="@string/pref_default_vpn_profile"
|
android:title="@string/pref_default_vpn_profile"
|
||||||
android:summary="@string/pref_default_vpn_profile_mru" />
|
android:summary="@string/pref_default_vpn_profile_mru" />
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="pref_ignore_power_whitelist"
|
||||||
|
android:title="@string/pref_power_whitelist_title"
|
||||||
|
android:summary="@string/pref_power_whitelist_summary" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -4,7 +4,7 @@ buildscript {
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
classpath 'com.android.tools.build:gradle:3.6.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#Mon Oct 07 16:41:25 CEST 2019
|
#Wed Feb 26 10:22:42 CET 2020
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||||
|
|
|
@ -236,6 +236,12 @@ struct private_ike_sa_t {
|
||||||
*/
|
*/
|
||||||
uint32_t keepalive_interval;
|
uint32_t keepalive_interval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time the NAT keep alive interval may be exceeded before triggering a DPD
|
||||||
|
* instead of a NAT keep alive
|
||||||
|
*/
|
||||||
|
uint32_t keepalive_dpd_margin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scheduled keep alive job, if any
|
* The scheduled keep alive job, if any
|
||||||
*/
|
*/
|
||||||
|
@ -655,7 +661,19 @@ METHOD(ike_sa_t, send_keepalive, void,
|
||||||
|
|
||||||
diff = now - last_out;
|
diff = now - last_out;
|
||||||
|
|
||||||
if (diff >= this->keepalive_interval)
|
if (this->keepalive_dpd_margin &&
|
||||||
|
diff > (this->keepalive_interval + this->keepalive_dpd_margin))
|
||||||
|
{
|
||||||
|
if (!this->task_manager->busy(this->task_manager))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "sending DPD instead of keep alive %ds after last "
|
||||||
|
"outbound message", diff);
|
||||||
|
this->task_manager->queue_dpd(this->task_manager);
|
||||||
|
this->task_manager->initiate(this->task_manager);
|
||||||
|
}
|
||||||
|
diff = 0;
|
||||||
|
}
|
||||||
|
else if (diff >= this->keepalive_interval)
|
||||||
{
|
{
|
||||||
packet_t *packet;
|
packet_t *packet;
|
||||||
chunk_t data;
|
chunk_t data;
|
||||||
|
@ -669,6 +687,7 @@ METHOD(ike_sa_t, send_keepalive, void,
|
||||||
packet->set_data(packet, data);
|
packet->set_data(packet, data);
|
||||||
DBG1(DBG_IKE, "sending keep alive to %#H", this->other_host);
|
DBG1(DBG_IKE, "sending keep alive to %#H", this->other_host);
|
||||||
charon->sender->send_no_marker(charon->sender, packet);
|
charon->sender->send_no_marker(charon->sender, packet);
|
||||||
|
this->stats[STAT_OUTBOUND] = now;
|
||||||
diff = 0;
|
diff = 0;
|
||||||
}
|
}
|
||||||
if (!this->keepalive_job)
|
if (!this->keepalive_job)
|
||||||
|
@ -2407,9 +2426,16 @@ METHOD(ike_sa_t, retransmit, status_t,
|
||||||
{
|
{
|
||||||
return INVALID_STATE;
|
return INVALID_STATE;
|
||||||
}
|
}
|
||||||
this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
|
switch (this->task_manager->retransmit(this->task_manager, message_id))
|
||||||
if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
|
|
||||||
{
|
{
|
||||||
|
case SUCCESS:
|
||||||
|
this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
|
||||||
|
return SUCCESS;
|
||||||
|
case INVALID_STATE:
|
||||||
|
return INVALID_STATE;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* send a proper signal to brief interested bus listeners */
|
/* send a proper signal to brief interested bus listeners */
|
||||||
switch (this->state)
|
switch (this->state)
|
||||||
{
|
{
|
||||||
|
@ -2481,8 +2507,6 @@ METHOD(ike_sa_t, retransmit, status_t,
|
||||||
}
|
}
|
||||||
return DESTROY_ME;
|
return DESTROY_ME;
|
||||||
}
|
}
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
METHOD(ike_sa_t, set_auth_lifetime, status_t,
|
METHOD(ike_sa_t, set_auth_lifetime, status_t,
|
||||||
private_ike_sa_t *this, uint32_t lifetime)
|
private_ike_sa_t *this, uint32_t lifetime)
|
||||||
|
@ -2689,6 +2713,14 @@ METHOD(ike_sa_t, roam, status_t,
|
||||||
this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE);
|
this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE);
|
||||||
return this->task_manager->initiate(this->task_manager);
|
return this->task_manager->initiate(this->task_manager);
|
||||||
}
|
}
|
||||||
|
if (lib->settings->get_bool(lib->settings,
|
||||||
|
"%s.check_current_path", FALSE, lib->ns) &&
|
||||||
|
!this->task_manager->busy(this->task_manager))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "checking if current path still works using DPD");
|
||||||
|
this->task_manager->queue_dpd(this->task_manager);
|
||||||
|
return this->task_manager->initiate(this->task_manager);
|
||||||
|
}
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3182,6 +3214,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
|
||||||
.unique_id = ref_get(&unique_id),
|
.unique_id = ref_get(&unique_id),
|
||||||
.keepalive_interval = lib->settings->get_time(lib->settings,
|
.keepalive_interval = lib->settings->get_time(lib->settings,
|
||||||
"%s.keep_alive", KEEPALIVE_INTERVAL, lib->ns),
|
"%s.keep_alive", KEEPALIVE_INTERVAL, lib->ns),
|
||||||
|
.keepalive_dpd_margin = lib->settings->get_time(lib->settings,
|
||||||
|
"%s.keep_alive_dpd_margin", 0, lib->ns),
|
||||||
.retry_initiate_interval = lib->settings->get_time(lib->settings,
|
.retry_initiate_interval = lib->settings->get_time(lib->settings,
|
||||||
"%s.retry_initiate_interval", 0, lib->ns),
|
"%s.retry_initiate_interval", 0, lib->ns),
|
||||||
.flush_auth_cfg = lib->settings->get_bool(lib->settings,
|
.flush_auth_cfg = lib->settings->get_bool(lib->settings,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2006-2019 Tobias Brunner
|
* Copyright (C) 2006-2020 Tobias Brunner
|
||||||
* Copyright (C) 2006 Daniel Roethlisberger
|
* Copyright (C) 2006 Daniel Roethlisberger
|
||||||
* Copyright (C) 2005-2009 Martin Willi
|
* Copyright (C) 2005-2009 Martin Willi
|
||||||
* Copyright (C) 2005 Jan Hutter
|
* Copyright (C) 2005 Jan Hutter
|
||||||
|
@ -872,8 +872,9 @@ struct ike_sa_t {
|
||||||
*
|
*
|
||||||
* @param message_id ID of the request to retransmit
|
* @param message_id ID of the request to retransmit
|
||||||
* @return
|
* @return
|
||||||
* - SUCCESS
|
* - SUCCESS if retransmit was sent
|
||||||
* - NOT_FOUND if request doesn't have to be retransmitted
|
* - INVALID_STATE if no retransmit required
|
||||||
|
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||||
*/
|
*/
|
||||||
status_t (*retransmit)(ike_sa_t *this, uint32_t message_id);
|
status_t (*retransmit)(ike_sa_t *this, uint32_t message_id);
|
||||||
|
|
||||||
|
|
|
@ -404,7 +404,7 @@ static status_t retransmit_packet(private_task_manager_t *this, uint32_t seqnr,
|
||||||
METHOD(task_manager_t, retransmit, status_t,
|
METHOD(task_manager_t, retransmit, status_t,
|
||||||
private_task_manager_t *this, uint32_t seqnr)
|
private_task_manager_t *this, uint32_t seqnr)
|
||||||
{
|
{
|
||||||
status_t status = SUCCESS;
|
status_t status = INVALID_STATE;
|
||||||
|
|
||||||
if (seqnr == this->initiating.seqnr &&
|
if (seqnr == this->initiating.seqnr &&
|
||||||
array_count(this->initiating.packets))
|
array_count(this->initiating.packets))
|
||||||
|
|
|
@ -409,7 +409,7 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||||
"deferred");
|
"deferred");
|
||||||
this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
|
this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
|
||||||
this->initiating.deferred = TRUE;
|
this->initiating.deferred = TRUE;
|
||||||
return SUCCESS;
|
return INVALID_STATE;
|
||||||
}
|
}
|
||||||
else if (mobike->is_probing(mobike))
|
else if (mobike->is_probing(mobike))
|
||||||
{
|
{
|
||||||
|
@ -443,7 +443,7 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||||
"deferred");
|
"deferred");
|
||||||
this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
|
this->ike_sa->set_condition(this->ike_sa, COND_STALE, TRUE);
|
||||||
this->initiating.deferred = TRUE;
|
this->initiating.deferred = TRUE;
|
||||||
return SUCCESS;
|
return INVALID_STATE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,9 +451,10 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||||
job = (job_t*)retransmit_job_create(this->initiating.mid,
|
job = (job_t*)retransmit_job_create(this->initiating.mid,
|
||||||
this->ike_sa->get_id(this->ike_sa));
|
this->ike_sa->get_id(this->ike_sa));
|
||||||
lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout);
|
lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout);
|
||||||
}
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
return INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(task_manager_t, initiate, status_t,
|
METHOD(task_manager_t, initiate, status_t,
|
||||||
private_task_manager_t *this)
|
private_task_manager_t *this)
|
||||||
|
|
|
@ -93,30 +93,6 @@ struct private_scheduler_t {
|
||||||
condvar_t *condvar;
|
condvar_t *condvar;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two timevals, return >0 if a > b, <0 if a < b and =0 if equal
|
|
||||||
*/
|
|
||||||
static int timeval_cmp(timeval_t *a, timeval_t *b)
|
|
||||||
{
|
|
||||||
if (a->tv_sec > b->tv_sec)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (a->tv_sec < b->tv_sec)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a->tv_usec > b->tv_usec)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (a->tv_usec < b->tv_usec)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the top event without removing it. Returns NULL if the heap is empty.
|
* Returns the top event without removing it. Returns NULL if the heap is empty.
|
||||||
*/
|
*/
|
||||||
|
@ -132,6 +108,7 @@ static event_t *peek_event(private_scheduler_t *this)
|
||||||
static event_t *remove_event(private_scheduler_t *this)
|
static event_t *remove_event(private_scheduler_t *this)
|
||||||
{
|
{
|
||||||
event_t *event, *top;
|
event_t *event, *top;
|
||||||
|
|
||||||
if (!this->event_count)
|
if (!this->event_count)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -144,21 +121,22 @@ static event_t *remove_event(private_scheduler_t *this)
|
||||||
|
|
||||||
if (--this->event_count > 1)
|
if (--this->event_count > 1)
|
||||||
{
|
{
|
||||||
/* seep down the top event */
|
|
||||||
u_int position = 1;
|
u_int position = 1;
|
||||||
|
|
||||||
|
/* seep down the top event */
|
||||||
while ((position << 1) <= this->event_count)
|
while ((position << 1) <= this->event_count)
|
||||||
{
|
{
|
||||||
u_int child = position << 1;
|
u_int child = position << 1;
|
||||||
|
|
||||||
if ((child + 1) <= this->event_count &&
|
if ((child + 1) <= this->event_count &&
|
||||||
timeval_cmp(&this->heap[child + 1]->time,
|
timercmp(&this->heap[child + 1]->time,
|
||||||
&this->heap[child]->time) < 0)
|
&this->heap[child]->time, <))
|
||||||
{
|
{
|
||||||
/* the "right" child is smaller */
|
/* the "right" child is smaller */
|
||||||
child++;
|
child++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeval_cmp(&top->time, &this->heap[child]->time) <= 0)
|
if (!timercmp(&top->time, &this->heap[child]->time, >))
|
||||||
{
|
{
|
||||||
/* the top event fires before the smaller of the two children,
|
/* the top event fires before the smaller of the two children,
|
||||||
* stop */
|
* stop */
|
||||||
|
@ -189,7 +167,7 @@ static job_requeue_t schedule(private_scheduler_t * this)
|
||||||
|
|
||||||
if ((event = peek_event(this)) != NULL)
|
if ((event = peek_event(this)) != NULL)
|
||||||
{
|
{
|
||||||
if (timeval_cmp(&now, &event->time) >= 0)
|
if (!timercmp(&now, &event->time, <))
|
||||||
{
|
{
|
||||||
remove_event(this);
|
remove_event(this);
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
|
@ -231,6 +209,7 @@ METHOD(scheduler_t, get_job_load, u_int,
|
||||||
private_scheduler_t *this)
|
private_scheduler_t *this)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
count = this->event_count;
|
count = this->event_count;
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
|
@ -262,8 +241,8 @@ METHOD(scheduler_t, schedule_job_tv, void,
|
||||||
position = this->event_count;
|
position = this->event_count;
|
||||||
|
|
||||||
/* then bubble it up */
|
/* then bubble it up */
|
||||||
while (position > 1 && timeval_cmp(&this->heap[position >> 1]->time,
|
while (position > 1 &&
|
||||||
&event->time) > 0)
|
timercmp(&this->heap[position >> 1]->time, &event->time, >))
|
||||||
{
|
{
|
||||||
/* parent has to be fired after the new event, move up */
|
/* parent has to be fired after the new event, move up */
|
||||||
this->heap[position] = this->heap[position >> 1];
|
this->heap[position] = this->heap[position >> 1];
|
||||||
|
@ -354,4 +333,3 @@ scheduler_t * scheduler_create()
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,8 @@ METHOD(condvar_t, wait_, void,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use the monotonic clock based version of this function if available */
|
/* use the monotonic clock based version of this function if available */
|
||||||
#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
|
#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) && \
|
||||||
|
!defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
|
||||||
#define pthread_cond_timedwait pthread_cond_timedwait_monotonic
|
#define pthread_cond_timedwait pthread_cond_timedwait_monotonic
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -336,7 +337,7 @@ condvar_t *condvar_create(condvar_type_t type)
|
||||||
pthread_condattr_t condattr;
|
pthread_condattr_t condattr;
|
||||||
pthread_condattr_init(&condattr);
|
pthread_condattr_init(&condattr);
|
||||||
#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
|
#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
|
||||||
pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
|
pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
|
||||||
#endif
|
#endif
|
||||||
pthread_cond_init(&this->condvar, &condattr);
|
pthread_cond_init(&this->condvar, &condattr);
|
||||||
pthread_condattr_destroy(&condattr);
|
pthread_condattr_destroy(&condattr);
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
#define HAVE_PTHREAD_CONDATTR_INIT 1
|
#define HAVE_PTHREAD_CONDATTR_INIT 1
|
||||||
#define HAVE_CONDATTR_CLOCK_MONOTONIC 1
|
#define HAVE_CONDATTR_CLOCK_MONOTONIC 1
|
||||||
|
|
||||||
|
#undef TIME_CLOCK_ID
|
||||||
|
#define TIME_CLOCK_ID CLOCK_REALTIME
|
||||||
|
|
||||||
#define HAVE_SYS_CAPABILITY_H 1
|
#define HAVE_SYS_CAPABILITY_H 1
|
||||||
|
|
||||||
#else /* __ANDROID_API__ */
|
#else /* __ANDROID_API__ */
|
||||||
|
|
|
@ -52,7 +52,7 @@ time_t time_monotonic(timeval_t *tv)
|
||||||
* monotonic time source only if it is also supported by pthread. */
|
* monotonic time source only if it is also supported by pthread. */
|
||||||
timespec_t ts;
|
timespec_t ts;
|
||||||
|
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
if (clock_gettime(TIME_CLOCK_ID, &ts) == 0)
|
||||||
{
|
{
|
||||||
if (tv)
|
if (tv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,20 @@
|
||||||
*/
|
*/
|
||||||
#define TIME_32_BIT_SIGNED_MAX 0x7fffffff
|
#define TIME_32_BIT_SIGNED_MAX 0x7fffffff
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The clock that should be used for time_monotonic() and conditional variables
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CLOCK_GETTIME
|
||||||
|
#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
|
||||||
|
/* only can use different clocks if we can set it via attribute */
|
||||||
|
#ifndef TIME_CLOCK_ID
|
||||||
|
#define TIME_CLOCK_ID CLOCK_MONOTONIC
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define TIME_CLOCK_ID CLOCK_MONOTONIC
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle struct timeval like an own type.
|
* Handle struct timeval like an own type.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue