diff options
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/eip/EIP.java')
-rw-r--r-- | app/src/main/java/se/leap/bitmaskclient/eip/EIP.java | 563 |
1 files changed, 400 insertions, 163 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index 665e0ebd..92bd5929 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -16,25 +16,46 @@ */ package se.leap.bitmaskclient.eip; -import android.app.IntentService; +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.SystemClock; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.support.annotation.WorkerThread; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; +import java.io.Closeable; import java.lang.ref.WeakReference; +import java.util.Observable; +import java.util.Observer; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; import de.blinkt.openvpn.LaunchVPN; +import de.blinkt.openvpn.core.IOpenVPNServiceInternal; +import de.blinkt.openvpn.core.OpenVPNService; +import de.blinkt.openvpn.core.ProfileManager; +import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.OnBootReceiver; import static android.app.Activity.RESULT_CANCELED; import static android.app.Activity.RESULT_OK; import static android.content.Intent.CATEGORY_DEFAULT; +import static se.leap.bitmaskclient.ConfigHelper.ensureNotOnMainThread; import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; @@ -43,11 +64,11 @@ import static se.leap.bitmaskclient.Constants.EIP_ACTION_IS_RUNNING; import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP; +import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP_BLOCKING_VPN; import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES; import static se.leap.bitmaskclient.Constants.EIP_RECEIVER; import static se.leap.bitmaskclient.Constants.EIP_REQUEST; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; -import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.MainActivityErrorDialog.DOWNLOAD_ERRORS.ERROR_INVALID_VPN_CERTIFICATE; @@ -56,227 +77,443 @@ import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; /** * EIP is the abstract base class for interacting with and managing the Encrypted * Internet Proxy connection. Connections are started, stopped, and queried through - * this IntentService. + * this Service. * Contains logic for parsing eip-service.json from the provider, configuring and selecting * gateways, and controlling {@link de.blinkt.openvpn.core.OpenVPNService} connections. * * @author Sean Leonard <meanderingcode@aetherislands.net> * @author Parménides GV <parmegv@sdf.org> */ -public final class EIP extends IntentService { +public final class EIP extends Service implements Observer { public final static String TAG = EIP.class.getSimpleName(), SERVICE_API_PATH = "config/eip-service.json", ERRORS = "errors", ERROR_ID = "errorID"; - private WeakReference<ResultReceiver> mReceiverRef = new WeakReference<>(null); - private SharedPreferences preferences; + private volatile SharedPreferences preferences; + private AtomicInteger processCounter; + private volatile EipStatus eipStatus; + private final Object lock = new Object(); - public EIP() { - super(TAG); + // Service connection to OpenVpnService, shared between threads + private volatile OpenvpnServiceConnection openvpnServiceConnection; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; } @Override public void onCreate() { super.onCreate(); + eipStatus = EipStatus.getInstance(); + eipStatus.addObserver(this); + processCounter = new AtomicInteger(0); preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); } @Override - protected void onHandleIntent(Intent intent) { - String action = intent.getAction(); - if (intent.getParcelableExtra(EIP_RECEIVER) != null) { - mReceiverRef = new WeakReference<>((ResultReceiver) intent.getParcelableExtra(EIP_RECEIVER)); + public void onDestroy() { + super.onDestroy(); + eipStatus.deleteObserver(this); + if (openvpnServiceConnection != null) { + openvpnServiceConnection.close(); + openvpnServiceConnection = null; } + } - if (action == null) { - return; + /** + * update eipStatus whenever it changes + */ + @Override + public void update(Observable observable, Object data) { + if (observable instanceof EipStatus) { + eipStatus = (EipStatus) observable; } + } - switch (action) { - case EIP_ACTION_START: - boolean earlyRoutes = intent.getBooleanExtra(EIP_EARLY_ROUTES, true); - startEIP(earlyRoutes); - break; - case EIP_ACTION_START_ALWAYS_ON_VPN: - startEIPAlwaysOnVpn(); - break; - case EIP_ACTION_STOP: - stopEIP(); - break; - case EIP_ACTION_IS_RUNNING: - isRunning(); - break; - case EIP_ACTION_CHECK_CERT_VALIDITY: - checkVPNCertificateValidity(); - break; + /** + * register new process with processCounter and start it + * @param intent the intent that started this EIP call + */ + @Override + public int onStartCommand(final Intent intent, int flags, int startId) { + Log.d(TAG, "new process counter: " + processCounter.incrementAndGet()); + final String action = intent.getAction(); + if (action != null) { + ResultReceiver resultReceiver = intent.getParcelableExtra(EIP_RECEIVER); + new EipThread(this, action, intent, resultReceiver).start(); + } else { + processCounter.decrementAndGet(); } + return START_STICKY; } /** - * Initiates an EIP connection by selecting a gateway and preparing and sending an - * Intent to {@link de.blinkt.openvpn.LaunchVPN}. - * It also sets up early routes. + * Thread to handle the requests to this service */ - private void startEIP(boolean earlyRoutes) { - if (!EipStatus.getInstance().isBlockingVpnEstablished() && earlyRoutes) { - earlyRoutes(); + class EipThread extends Thread { + EipThread(EIP eipReference, String action, Intent startIntent, ResultReceiver resultReceiver) { + super(new EipRunnable(eipReference, action, startIntent, resultReceiver)); } + } + + /** + * Runnable to be used in the EipThread class + */ + class EipRunnable implements Runnable { + private String action; + private EIP eipReference; + private Intent intent; - Bundle result = new Bundle(); + private WeakReference<ResultReceiver> mReceiverRef = new WeakReference<>(null); - if (!preferences.getBoolean(EIP_RESTART_ON_BOOT, false)){ - preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, true).commit(); + + EipRunnable(EIP eipReference, String action, Intent startIntent, ResultReceiver resultReceiver) { + super(); + this.action = action; + this.eipReference = eipReference; + this.intent = startIntent; + this.mReceiverRef = new WeakReference<ResultReceiver>(resultReceiver); } - GatewaysManager gatewaysManager = gatewaysFromPreferences(); - if (!isVPNCertificateValid()){ - setErrorResult(result, vpn_certificate_is_invalid, ERROR_INVALID_VPN_CERTIFICATE.toString()); - tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_CANCELED, result); - return; + /** + * select correct function to call based upon transmitted action + * after completing check if no other thread is running + * if no other thread is running terminate the EIP service + */ + @Override + public void run() { + Log.d(TAG, "new EIP thread started!"); + switch (action) { + case EIP_ACTION_START: + boolean earlyRoutes = intent.getBooleanExtra(EIP_EARLY_ROUTES, true); + startEIP(earlyRoutes); + break; + case EIP_ACTION_START_ALWAYS_ON_VPN: + startEIPAlwaysOnVpn(); + break; + case EIP_ACTION_STOP: + stopEIP(); + break; + case EIP_ACTION_IS_RUNNING: + isRunning(); + break; + case EIP_ACTION_CHECK_CERT_VALIDITY: + checkVPNCertificateValidity(); + break; + } + if (processCounter.decrementAndGet() == 0) { + Log.d(TAG, "no more running EIP threads!"); + eipReference.stopSelf(); + } } - Gateway gateway = gatewaysManager.select(); - if (gateway != null && gateway.getProfile() != null) { - launchActiveGateway(gateway); - tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_OK); - } else - tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_CANCELED); - } + /** + * Initiates an EIP connection by selecting a gateway and preparing and sending an + * Intent to {@link de.blinkt.openvpn.LaunchVPN}. + * It also sets up early routes. + */ + @SuppressLint("ApplySharedPref") + private void startEIP(boolean earlyRoutes) { + if (!eipStatus.isBlockingVpnEstablished() && earlyRoutes) { + earlyRoutes(); + } - /** - * Tries to start the last used vpn profile when the OS was rebooted and always-on-VPN is enabled. - * The {@link OnBootReceiver} will care if there is no profile. - */ - private void startEIPAlwaysOnVpn() { - Log.d(TAG, "startEIPAlwaysOnVpn vpn"); + Bundle result = new Bundle(); + if (!preferences.getBoolean(EIP_RESTART_ON_BOOT, false)) { + preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, true).commit(); + } - GatewaysManager gatewaysManager = gatewaysFromPreferences(); - Gateway gateway = gatewaysManager.select(); + GatewaysManager gatewaysManager = gatewaysFromPreferences(); + if (!isVPNCertificateValid()) { + setErrorResult(result, vpn_certificate_is_invalid, ERROR_INVALID_VPN_CERTIFICATE.toString()); + tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_CANCELED, result); + return; + } - if (gateway != null && gateway.getProfile() != null) { - Log.d(TAG, "startEIPAlwaysOnVpn eip launch avtive gateway vpn"); - launchActiveGateway(gateway); - } else { - Log.d(TAG, "startEIPAlwaysOnVpn no active profile available!"); + Gateway gateway = gatewaysManager.select(); + if (gateway != null && gateway.getProfile() != null) { + launchActiveGateway(gateway); + tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_OK); + } else + tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_CANCELED); } - } - /** - * Early routes are routes that block traffic until a new - * VpnService is started properly. - */ - private void earlyRoutes() { - Intent voidVpnLauncher = new Intent(getApplicationContext(), VoidVpnLauncher.class); - voidVpnLauncher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(voidVpnLauncher); - } + /** + * Tries to start the last used vpn profile when the OS was rebooted and always-on-VPN is enabled. + * The {@link OnBootReceiver} will care if there is no profile. + */ + private void startEIPAlwaysOnVpn() { + Log.d(TAG, "startEIPAlwaysOnVpn vpn"); + + GatewaysManager gatewaysManager = gatewaysFromPreferences(); + Gateway gateway = gatewaysManager.select(); + + if (gateway != null && gateway.getProfile() != null) { + Log.d(TAG, "startEIPAlwaysOnVpn eip launch avtive gateway vpn"); + launchActiveGateway(gateway); + } else { + Log.d(TAG, "startEIPAlwaysOnVpn no active profile available!"); + } + } - private void launchActiveGateway(Gateway gateway) { - Intent intent = new Intent(this, LaunchVPN.class); - intent.setAction(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); - intent.putExtra(LaunchVPN.EXTRA_TEMP_VPN_PROFILE, gateway.getProfile()); - startActivity(intent); - } + /** + * Early routes are routes that block traffic until a new + * VpnService is started properly. + */ + private void earlyRoutes() { + Intent voidVpnLauncher = new Intent(getApplicationContext(), VoidVpnLauncher.class); + voidVpnLauncher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(voidVpnLauncher); + } - private void stopEIP() { - // TODO stop eip from here if possible... - // TODO then refactor EipFragment.handleSwitchOff - EipStatus eipStatus = EipStatus.getInstance(); - int resultCode = RESULT_CANCELED; - if (eipStatus.isConnected() || eipStatus.isConnecting()) - resultCode = RESULT_OK; + /** + * starts the VPN and connects to the given gateway + * + * @param gateway to connect to + */ + private void launchActiveGateway(Gateway gateway) { + Intent intent = new Intent(eipReference, LaunchVPN.class); + intent.setAction(Intent.ACTION_MAIN); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); + intent.putExtra(LaunchVPN.EXTRA_TEMP_VPN_PROFILE, gateway.getProfile()); + startActivity(intent); + } - tellToReceiverOrBroadcast(EIP_ACTION_STOP, resultCode); - } + /** + * Stop VPN + * First checks if the OpenVpnConnection is open then + * terminates EIP if currently connected or connecting + */ + private void stopEIP() { + int resultCode = stop() ? RESULT_OK : RESULT_CANCELED; + tellToReceiverOrBroadcast(EIP_ACTION_STOP, resultCode); + } - /** - * Checks the last stored status notified by ics-openvpn - * Sends <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the - * request if it's not connected, <code>Activity.RESULT_OK</code> otherwise. - */ - private void isRunning() { - EipStatus eipStatus = EipStatus.getInstance(); - int resultCode = (eipStatus.isConnected()) ? - RESULT_OK : - RESULT_CANCELED; - tellToReceiverOrBroadcast(EIP_ACTION_IS_RUNNING, resultCode); - } + /** + * Checks the last stored status notified by ics-openvpn + * Sends <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the + * request if it's not connected, <code>Activity.RESULT_OK</code> otherwise. + */ + private void isRunning() { + int resultCode = (eipStatus.isConnected()) ? + RESULT_OK : + RESULT_CANCELED; + tellToReceiverOrBroadcast(EIP_ACTION_IS_RUNNING, resultCode); + } - private JSONObject eipDefinitionFromPreferences() { - JSONObject result = new JSONObject(); - try { - String eipDefinitionString = preferences.getString(PROVIDER_EIP_DEFINITION, ""); - if (!eipDefinitionString.isEmpty()) { - result = new JSONObject(eipDefinitionString); + /** + * read eipServiceJson from preferences and parse Gateways + * + * @return GatewaysManager + */ + private GatewaysManager gatewaysFromPreferences() { + GatewaysManager gatewaysManager = new GatewaysManager(eipReference, preferences); + gatewaysManager.configureFromPreferences(); + return gatewaysManager; + } + + /** + * read VPN certificate from preferences and check it + * broadcast result + */ + private void checkVPNCertificateValidity() { + int resultCode = isVPNCertificateValid() ? + RESULT_OK : + RESULT_CANCELED; + tellToReceiverOrBroadcast(EIP_ACTION_CHECK_CERT_VALIDITY, resultCode); + } + + /** + * read VPN certificate from preferences and check it + * + * @return true if VPN certificate is valid false otherwise + */ + private boolean isVPNCertificateValid() { + VpnCertificateValidator validator = new VpnCertificateValidator(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); + return validator.isValid(); + } + + /** + * send resultCode and resultData to receiver or + * broadcast the result if no receiver is defined + * + * @param action the action that has been performed + * @param resultCode RESULT_OK if action was successful RESULT_CANCELED otherwise + * @param resultData other data to broadcast or return to receiver + */ + private void tellToReceiverOrBroadcast(String action, int resultCode, Bundle resultData) { + resultData.putString(EIP_REQUEST, action); + if (mReceiverRef.get() != null) { + mReceiverRef.get().send(resultCode, resultData); + } else { + broadcastEvent(resultCode, resultData); } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } - return result; - } - private GatewaysManager gatewaysFromPreferences() { - GatewaysManager gatewaysManager = new GatewaysManager(this, preferences); - //TODO: THIS IS A QUICK FIX - it deletes all profiles in ProfileManager, thus it's possible - // to add all gateways from prefs without duplicates, but this should be refactored. - gatewaysManager.clearGatewaysAndProfiles(); - gatewaysManager.fromEipServiceJson(eipDefinitionFromPreferences()); - return gatewaysManager; - } + /** + * send resultCode and resultData to receiver or + * broadcast the result if no receiver is defined + * + * @param action the action that has been performed + * @param resultCode RESULT_OK if action was successful RESULT_CANCELED otherwise + */ + private void tellToReceiverOrBroadcast(String action, int resultCode) { + tellToReceiverOrBroadcast(action, resultCode, new Bundle()); + } - private void checkVPNCertificateValidity() { - int resultCode = isVPNCertificateValid() ? - RESULT_OK : - RESULT_CANCELED; - tellToReceiverOrBroadcast(EIP_ACTION_CHECK_CERT_VALIDITY, resultCode); - } + /** + * broadcast result + * + * @param resultCode RESULT_OK if action was successful RESULT_CANCELED otherwise + * @param resultData other data to broadcast or return to receiver + */ + private void broadcastEvent(int resultCode, Bundle resultData) { + Intent intentUpdate = new Intent(BROADCAST_EIP_EVENT); + intentUpdate.addCategory(CATEGORY_DEFAULT); + intentUpdate.putExtra(BROADCAST_RESULT_CODE, resultCode); + intentUpdate.putExtra(BROADCAST_RESULT_KEY, resultData); + Log.d(TAG, "sending broadcast"); + LocalBroadcastManager.getInstance(eipReference).sendBroadcast(intentUpdate); + } - private boolean isVPNCertificateValid() { - VpnCertificateValidator validator = new VpnCertificateValidator(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); - return validator.isValid(); - } - private void tellToReceiverOrBroadcast(String action, int resultCode, Bundle resultData) { - resultData.putString(EIP_REQUEST, action); - if (mReceiverRef.get() != null) { - mReceiverRef.get().send(resultCode, resultData); - } else { - broadcastEvent(resultCode, resultData); + /** + * helper function to add error to result bundle + * + * @param result - result of an action + * @param errorMessageId - id of string resource describing the error + * @param errorId - MainActivityErrorDialog DownloadError id + */ + void setErrorResult(Bundle result, @StringRes int errorMessageId, String errorId) { + JSONObject errorJson = new JSONObject(); + try { + errorJson.put(ERRORS, getResources().getString(errorMessageId)); + errorJson.put(ERROR_ID, errorId); + } catch (JSONException e) { + e.printStackTrace(); + } + result.putString(ERRORS, errorJson.toString()); + result.putBoolean(BROADCAST_RESULT_KEY, false); } - } - private void tellToReceiverOrBroadcast(String action, int resultCode) { - tellToReceiverOrBroadcast(action, resultCode, new Bundle()); - } - private void broadcastEvent(int resultCode , Bundle resultData) { - Intent intentUpdate = new Intent(BROADCAST_EIP_EVENT); - intentUpdate.addCategory(CATEGORY_DEFAULT); - intentUpdate.putExtra(BROADCAST_RESULT_CODE, resultCode); - intentUpdate.putExtra(BROADCAST_RESULT_KEY, resultData); - Log.d(TAG, "sending broadcast"); - LocalBroadcastManager.getInstance(this).sendBroadcast(intentUpdate); - } + /** + * disable Bitmask starting on after phone reboot + * then stop VPN + */ + private boolean stop() { + preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, false).apply(); + if (eipStatus.isBlockingVpnEstablished()) { + stopBlockingVpn(); + } + return disconnect(); + } - Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) { - JSONObject errorJson = new JSONObject(); - addErrorMessageToJson(errorJson, getResources().getString(errorMessageId), errorId); - result.putString(ERRORS, errorJson.toString()); - result.putBoolean(BROADCAST_RESULT_KEY, false); - return result; + /** + * stop void vpn from blocking internet + */ + private void stopBlockingVpn() { + Log.d(TAG, "stop VoidVpn!"); + Intent stopVoidVpnIntent = new Intent(eipReference, VoidVpnService.class); + stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN); + startService(stopVoidVpnIntent); + } + + + /** + * creates a OpenVpnServiceConnection if necessary + * then terminates OpenVPN + */ + private boolean disconnect() { + try { + initOpenVpnServiceConnection(); + } catch (InterruptedException | IllegalStateException e) { + return false; + } + + ProfileManager.setConntectedVpnProfileDisconnected(eipReference); + try { + return openvpnServiceConnection.getService().stopVPN(false); + } catch (RemoteException e) { + VpnStatus.logException(e); + } + return false; + } + + /** + * Assigns a new OpenvpnServiceConnection to EIP's member variable openvpnServiceConnection. + * Only one thread at a time can create the service connection, that will be shared between threads + * + * @throws InterruptedException thrown if thread gets interrupted + * @throws IllegalStateException thrown if this method was not called from a background thread + */ + private void initOpenVpnServiceConnection() throws InterruptedException, IllegalStateException { + synchronized (lock) { + if (openvpnServiceConnection == null) { + Log.d(TAG, "serviceConnection is still null"); + openvpnServiceConnection = new OpenvpnServiceConnection(eipReference); + } + } + } } - private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId) { - try { - jsonObject.put(ERRORS, errorMessage); - jsonObject.put(ERROR_ID, errorId); - } catch (JSONException e) { - e.printStackTrace(); + /** + * Creates a service connection to OpenVpnService. + * The constructor blocks until the service is bound to the given Context. + * Pattern stolen from android.security.KeyChain.java + */ + @WorkerThread + public static class OpenvpnServiceConnection implements Closeable { + private final Context context; + private ServiceConnection serviceConnection; + private IOpenVPNServiceInternal service; + + protected OpenvpnServiceConnection(Context context) throws InterruptedException, IllegalStateException { + this.context = context; + ensureNotOnMainThread(context); + Log.d(TAG, "initSynchronizedServiceConnection!"); + initSynchronizedServiceConnection(context); + } + + private void initSynchronizedServiceConnection(final Context context) throws InterruptedException { + final BlockingQueue<IOpenVPNServiceInternal> blockingQueue = new LinkedBlockingQueue<>(1); + this.serviceConnection = new ServiceConnection() { + volatile boolean mConnectedAtLeastOnce = false; + @Override public void onServiceConnected(ComponentName name, IBinder service) { + if (!mConnectedAtLeastOnce) { + mConnectedAtLeastOnce = true; + try { + Log.d(TAG, "serviceConnection connected! ProcessCounter: " + ((EIP) context).processCounter.get()); + blockingQueue.put(IOpenVPNServiceInternal.Stub.asInterface(service)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + @Override public void onServiceDisconnected(ComponentName name) { + Log.d(TAG, "serviceConnection disconnected! ProcessCounter: " + ((EIP) context).processCounter.get()); + } + }; + + Intent intent = new Intent(context, OpenVPNService.class); + intent.setAction(OpenVPNService.START_SERVICE); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + service = blockingQueue.take(); + } + + @Override public void close() { + context.unbindService(serviceConnection); + } + + public IOpenVPNServiceInternal getService() { + return service; } } + } + |