@Override
  public void onDestroy() {
    synchronized (mProcessLock) {
      if (mProcessThread != null) {
        mManagement.stopVPN();
      }
    }

    if (mDeviceStateReceiver != null) {
      this.unregisterReceiver(mDeviceStateReceiver);
    }
    // Just in case unregister for state
    VpnStatus.removeStateListener(this);
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent != null && intent.getBooleanExtra(ALWAYS_SHOW_NOTIFICATION, false))
      mNotificationAlwaysVisible = true;

    VpnStatus.addStateListener(this);
    VpnStatus.addByteCountListener(this);

    if (intent != null && PAUSE_VPN.equals(intent.getAction())) {
      if (mDeviceStateReceiver != null) mDeviceStateReceiver.userPause(true);
      return START_NOT_STICKY;
    }

    if (intent != null && RESUME_VPN.equals(intent.getAction())) {
      if (mDeviceStateReceiver != null) mDeviceStateReceiver.userPause(false);
      return START_NOT_STICKY;
    }

    if (intent != null && START_SERVICE.equals(intent.getAction())) return START_NOT_STICKY;
    if (intent != null && START_SERVICE_STICKY.equals(intent.getAction())) {
      return START_REDELIVER_INTENT;
    }

    /* The intent is null when the service has been restarted */
    if (intent == null) {
      mProfile = ProfileManager.getLastConnectedProfile(this, false);
      VpnStatus.logInfo(R.string.service_restarted);

      /* Got no profile, just stop */
      if (mProfile == null) {
        Log.d("OpenVPN", "Got no last connected profile on null intent. Stopping");
        stopSelf(startId);
        return START_NOT_STICKY;
      }
      /* Do the asynchronous keychain certificate stuff */
      mProfile.checkForRestart(this);

      /* Recreate the intent */
      intent = mProfile.getStartServiceIntent(this);

    } else {
      String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID");
      mProfile = ProfileManager.get(this, profileUUID);
    }

    // Extract information from the intent.
    String prefix = getPackageName();
    String[] argv = intent.getStringArrayExtra(prefix + ".ARGV");
    String nativeLibraryDirectory = intent.getStringExtra(prefix + ".nativelib");

    String startTitle = getString(R.string.start_vpn_title, mProfile.mName);
    String startTicker = getString(R.string.start_vpn_ticker, mProfile.mName);
    showNotification(startTitle, startTicker, false, 0, LEVEL_CONNECTING_NO_SERVER_REPLY_YET);

    // Set a flag that we are starting a new VPN
    mStarting = true;
    // Stop the previous session by interrupting the thread.
    if (mManagement != null && mManagement.stopVPN())
      // an old was asked to exit, wait 1s
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        // ignore
      }

    synchronized (mProcessLock) {
      if (mProcessThread != null) {
        mProcessThread.interrupt();
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          // ignore
        }
      }
    }
    // An old running VPN should now be exited
    mStarting = false;

    // Start a new session by creating a new thread.
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

    mOvpn3 = prefs.getBoolean("ovpn3", false);
    if (!"ovpn3".equals(BuildConfig.FLAVOR)) mOvpn3 = false;

    // Open the Management Interface
    if (!mOvpn3) {

      // start a Thread that handles incoming messages of the managment socket
      OpenVpnManagementThread ovpnManagementThread = new OpenVpnManagementThread(mProfile, this);
      if (ovpnManagementThread.openManagementInterface(this)) {

        Thread mSocketManagerThread = new Thread(ovpnManagementThread, "OpenVPNManagementThread");
        mSocketManagerThread.start();
        mManagement = ovpnManagementThread;
        VpnStatus.logInfo("started Socket Thread");
      } else {
        return START_NOT_STICKY;
      }
    }

    Runnable processThread;
    if (mOvpn3) {

      OpenVPNManagement mOpenVPN3 = instantiateOpenVPN3Core();
      processThread = (Runnable) mOpenVPN3;
      mManagement = mOpenVPN3;

    } else {
      HashMap<String, String> env = new HashMap<>();
      processThread = new OpenVPNThread(this, argv, env, nativeLibraryDirectory);
    }

    synchronized (mProcessLock) {
      mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
      mProcessThread.start();
    }
    if (mDeviceStateReceiver != null) unregisterDeviceStateReceiver();

    registerDeviceStateReceiver(mManagement);

    ProfileManager.setConnectedVpnProfile(this, mProfile);
    /* TODO: At the moment we have no way to handle asynchronous PW input
     * Fixing will also allow to handle challenge/response authentication */
    if (mProfile.needUserPWInput(true) != 0) return START_NOT_STICKY;

    return START_STICKY;
  }
 @Override
 public void onRevoke() {
   VpnStatus.logInfo(R.string.permission_revoked);
   mManagement.stopVPN();
   endVpnService();
 }