diff options
| author | Arne Schwabe <arne@rfc2549.org> | 2013-11-19 15:44:06 +0100 | 
|---|---|---|
| committer | Arne Schwabe <arne@rfc2549.org> | 2013-11-19 15:44:06 +0100 | 
| commit | 08fcccc93dce0b7ecdb16af3b5fd2585b452aaf1 (patch) | |
| tree | a7b744693b5b34bd8bfed6416af21bf1c3b56f22 | |
| parent | bf13e848dc3de1b5cf0143d823f8a86a53ac71b8 (diff) | |
Android 4.4 workaround,
| -rw-r--r-- | icsopenvpn.iml | 32 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LogWindow.java | 9 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/api/ExternalOpenVPNService.java | 498 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/OpenVPNThread.java | 3 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/OpenVpnManagementThread.java | 11 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/core/OpenVpnService.java | 33 | 
6 files changed, 320 insertions, 266 deletions
diff --git a/icsopenvpn.iml b/icsopenvpn.iml index 5c38a169..ad327925 100644 --- a/icsopenvpn.iml +++ b/icsopenvpn.iml @@ -27,30 +27,31 @@        <sourceFolder url="file://$MODULE_DIR$/build/source/aidl/debug" isTestSource="false" generated="true" />        <sourceFolder url="file://$MODULE_DIR$/build/source/rs/debug" isTestSource="false" generated="true" />        <sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/debug" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" isTestSource="false" generated="true" /> +      <sourceFolder url="file://$MODULE_DIR$/build/res/rs/debug" type="java-resource" />        <sourceFolder url="file://$MODULE_DIR$/build/source/r/test" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/build/source/aidl/test" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/build/source/rs/test" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/build/source/buildConfig/test" isTestSource="true" /> -      <sourceFolder url="file://$MODULE_DIR$/build/res/rs/test" isTestSource="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/assets" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" generated="true" /> -      <sourceFolder url="file://$MODULE_DIR$/res" isTestSource="false" generated="true" /> +      <sourceFolder url="file://$MODULE_DIR$/build/res/rs/test" type="java-test-resource" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> +      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> +      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/assets" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> +      <sourceFolder url="file://$MODULE_DIR$/res" type="java-resource" /> +      <sourceFolder url="file://$MODULE_DIR$/src" type="java-resource" />        <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/aidl" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/assets" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/java" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/jni" isTestSource="true" />        <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/rs" isTestSource="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/res" isTestSource="true" /> -      <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/resources" isTestSource="true" /> +      <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/res" type="java-test-resource" /> +      <sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/resources" type="java-test-resource" />        <excludeFolder url="file://$MODULE_DIR$/.gradle" />        <excludeFolder url="file://$MODULE_DIR$/.hg" />        <excludeFolder url="file://$MODULE_DIR$/.hgcheck" /> @@ -64,6 +65,7 @@        <excludeFolder url="file://$MODULE_DIR$/build/incremental" />        <excludeFolder url="file://$MODULE_DIR$/build/libs" />        <excludeFolder url="file://$MODULE_DIR$/build/manifests" /> +      <excludeFolder url="file://$MODULE_DIR$/build/res" />        <excludeFolder url="file://$MODULE_DIR$/build/symbols" />        <excludeFolder url="file://$MODULE_DIR$/build/tmp" />      </content> diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 82a2f4b6..843f85cc 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -2,6 +2,7 @@ package de.blinkt.openvpn;  import android.app.Activity;  import android.os.Bundle; +import android.view.MenuItem;  /**   * Created by arne on 13.10.13. @@ -11,5 +12,13 @@ public class LogWindow extends Activity {      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.log_window); +        getActionBar().setDisplayHomeAsUpEnabled(true); + +    } + + +    @Override +    public boolean onOptionsItemSelected(MenuItem item) { +        return super.onOptionsItemSelected(item);      }  } diff --git a/src/de/blinkt/openvpn/api/ExternalOpenVPNService.java b/src/de/blinkt/openvpn/api/ExternalOpenVPNService.java index 77374355..34b61325 100644 --- a/src/de/blinkt/openvpn/api/ExternalOpenVPNService.java +++ b/src/de/blinkt/openvpn/api/ExternalOpenVPNService.java @@ -35,272 +35,272 @@ import de.blinkt.openvpn.core.VPNLaunchHelper;  public class ExternalOpenVPNService extends Service implements StateListener {
 -	private static final int SEND_TOALL = 0;
 +    private static final int SEND_TOALL = 0;
 -	final RemoteCallbackList<IOpenVPNStatusCallback> mCallbacks =
 -			new RemoteCallbackList<IOpenVPNStatusCallback>();
 +    final RemoteCallbackList<IOpenVPNStatusCallback> mCallbacks =
 +            new RemoteCallbackList<IOpenVPNStatusCallback>();
 -	private OpenVpnService mService;
 -	private ExternalAppDatabase mExtAppDb;	
 +    private OpenVpnService mService;
 +    private ExternalAppDatabase mExtAppDb;
 -	private ServiceConnection mConnection = new ServiceConnection() {
 +    private ServiceConnection mConnection = new ServiceConnection() {
 -		@Override
 -		public void onServiceConnected(ComponentName className,
 -				IBinder service) {
 -			// We've bound to LocalService, cast the IBinder and get LocalService instance
 -			LocalBinder binder = (LocalBinder) service;
 -			mService = binder.getService();
 -		}
 +        @Override
 +        public void onServiceConnected(ComponentName className,
 +                                       IBinder service) {
 +            // We've bound to LocalService, cast the IBinder and get LocalService instance
 +            LocalBinder binder = (LocalBinder) service;
 +            mService = binder.getService();
 +        }
 -		@Override
 -		public void onServiceDisconnected(ComponentName arg0) {
 -			mService =null;
 -		}
 -
 -	};
 -
 -	@Override
 -	public void onCreate() {
 -		super.onCreate();
 -		VpnStatus.addStateListener(this);
 -		mExtAppDb = new ExternalAppDatabase(this);
 +        @Override
 +        public void onServiceDisconnected(ComponentName arg0) {
 +            mService = null;
 +        }
 +
 +    };
 +
 +    @Override
 +    public void onCreate() {
 +        super.onCreate();
 +        VpnStatus.addStateListener(this);
 +        mExtAppDb = new ExternalAppDatabase(this);
 -		Intent intent = new Intent(getBaseContext(), OpenVpnService.class);
 -		intent.setAction(OpenVpnService.START_SERVICE);
 -
 -		bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 -		mHandler.setService(this);
 -	}
 -
 -	private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() {
 +        Intent intent = new Intent(getBaseContext(), OpenVpnService.class);
 +        intent.setAction(OpenVpnService.START_SERVICE);
 +
 +        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
 +        mHandler.setService(this);
 +    }
 +
 +    private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() {
 -        private void checkOpenVPNPermission()  throws SecurityRemoteException{
 -			PackageManager pm = getPackageManager();
 -
 -			for (String apppackage:mExtAppDb.getExtAppList()) {
 -				ApplicationInfo app;
 -				try {
 -					app = pm.getApplicationInfo(apppackage, 0);
 -					if (Binder.getCallingUid() == app.uid) {
 -						return;
 -					}
 -				} catch (NameNotFoundException e) {
 -					// App not found. Remove it from the list
 -					mExtAppDb.removeApp(apppackage);
 -					e.printStackTrace();
 -				}
 +        private void checkOpenVPNPermission() throws SecurityRemoteException {
 +            PackageManager pm = getPackageManager();
 +
 +            for (String apppackage : mExtAppDb.getExtAppList()) {
 +                ApplicationInfo app;
 +                try {
 +                    app = pm.getApplicationInfo(apppackage, 0);
 +                    if (Binder.getCallingUid() == app.uid) {
 +                        return;
 +                    }
 +                } catch (NameNotFoundException e) {
 +                    // App not found. Remove it from the list
 +                    mExtAppDb.removeApp(apppackage);
 +                    e.printStackTrace();
 +                }
 -			}
 -			throw new SecurityException("Unauthorized OpenVPN API Caller");
 -		}
 -
 -		@Override
 -		public List<APIVpnProfile> getProfiles() throws RemoteException {
 -			checkOpenVPNPermission();
 +            }
 +            throw new SecurityException("Unauthorized OpenVPN API Caller");
 +        }
 +
 +        @Override
 +        public List<APIVpnProfile> getProfiles() throws RemoteException {
 +            checkOpenVPNPermission();
 -			ProfileManager pm = ProfileManager.getInstance(getBaseContext());
 +            ProfileManager pm = ProfileManager.getInstance(getBaseContext());
 -			List<APIVpnProfile> profiles = new LinkedList<APIVpnProfile>();
 +            List<APIVpnProfile> profiles = new LinkedList<APIVpnProfile>();
 -			for(VpnProfile vp: pm.getProfiles())
 -				profiles.add(new APIVpnProfile(vp.getUUIDString(),vp.mName,vp.mUserEditable));
 +            for (VpnProfile vp : pm.getProfiles())
 +                profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable));
 -			return profiles;
 -		}
 +            return profiles;
 +        }
 -		@Override
 -		public void startProfile(String profileUUID) throws RemoteException {
 -			checkOpenVPNPermission();
 -
 -			Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN);
 -			shortVPNIntent.setClass(getBaseContext(),de.blinkt.openvpn.LaunchVPN.class);
 -			shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY,profileUUID);
 -			shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 -			startActivity(shortVPNIntent);
 -		}
 +        @Override
 +        public void startProfile(String profileUUID) throws RemoteException {
 +            checkOpenVPNPermission();
 +
 +            Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN);
 +            shortVPNIntent.setClass(getBaseContext(), de.blinkt.openvpn.LaunchVPN.class);
 +            shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, profileUUID);
 +            shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 +            startActivity(shortVPNIntent);
 +        }
 -		public void startVPN(String inlineconfig) throws RemoteException {
 -			checkOpenVPNPermission();
 +        public void startVPN(String inlineconfig) throws RemoteException {
 +            checkOpenVPNPermission();
 -			ConfigParser cp = new ConfigParser();
 -			try {
 -				cp.parseConfig(new StringReader(inlineconfig));
 -				VpnProfile vp = cp.convertProfile();
 -				if(vp.checkProfile(getApplicationContext()) != R.string.no_error_found)
 -					throw new RemoteException(getString(vp.checkProfile(getApplicationContext())));
 -
 -
 -				ProfileManager.setTemporaryProfile(vp);
 -				VPNLaunchHelper.startOpenVpn(vp, getBaseContext());
 -
 -
 -			} catch (IOException e) {
 -				throw new RemoteException(e.getMessage());
 -			} catch (ConfigParseError e) {
 -				throw new RemoteException(e.getMessage());
 -			}
 -		}
 -
 -		@Override
 -		public boolean addVPNProfile(String name, String config) throws RemoteException {
 -			checkOpenVPNPermission();
 -
 -			ConfigParser cp = new ConfigParser();
 -			try {
 -				cp.parseConfig(new StringReader(config));
 -				VpnProfile vp = cp.convertProfile();
 -				vp.mName = name;
 -				ProfileManager pm = ProfileManager.getInstance(getBaseContext());
 -				pm.addProfile(vp);
 -			} catch (IOException e) {
 -				e.printStackTrace();
 -				return false;
 -			} catch (ConfigParseError e) {
 -				e.printStackTrace();
 -				return false;
 -			}
 -
 -			return true;
 -		}
 -
 -
 -		@Override
 -		public Intent prepare(String packagename) {
 -			if (new ExternalAppDatabase(ExternalOpenVPNService.this).isAllowed(packagename))
 -				return null;
 -
 -			Intent intent = new Intent();
 -			intent.setClass(ExternalOpenVPNService.this, ConfirmDialog.class);
 -			return intent;
 -		}
 -
 -		@Override
 -		public Intent prepareVPNService() throws RemoteException {
 -			checkOpenVPNPermission();
 -
 -			if(VpnService.prepare(ExternalOpenVPNService.this)==null)
 -				return null;
 -			else 
 -				return new  Intent(getBaseContext(), GrantPermissionsActivity.class);
 -		}
 -
 -
 -		@Override
 -		public void registerStatusCallback(IOpenVPNStatusCallback cb)
 -				throws RemoteException {
 -			checkOpenVPNPermission();
 -
 -			if (cb != null) {
 -				cb.newStatus(mMostRecentState.vpnUUID, mMostRecentState.state,
 -						mMostRecentState.logmessage, mMostRecentState.level.name());
 -				mCallbacks.register(cb);
 -			}
 -
 -
 -		}
 -
 -		@Override
 -		public void unregisterStatusCallback(IOpenVPNStatusCallback cb)
 -				throws RemoteException {
 -			checkOpenVPNPermission();
 -
 -			if (cb != null)  
 -				mCallbacks.unregister(cb);
 -		}
 -
 -		@Override
 -		public void disconnect() throws RemoteException {
 -			checkOpenVPNPermission();
 -			if(mService!=null && mService.getManagement()!=null)
 -				mService.getManagement().stopVPN();
 -		}
 -	};
 -
 -
 -
 -	private UpdateMessage mMostRecentState;	@Override
 -	public IBinder onBind(Intent intent) {
 -		return mBinder;
 -	}
 -
 -	@Override
 -	public void onDestroy() {
 -		super.onDestroy();
 -		mCallbacks.kill();
 -		unbindService(mConnection);
 -		VpnStatus.removeStateListener(this);
 -	}
 -
 -	class UpdateMessage {
 -		public String state;
 -		public String logmessage;
 -		public ConnectionStatus level;
 -		public String vpnUUID;
 -
 -		public UpdateMessage(String state, String logmessage, ConnectionStatus level) {
 -			this.state = state;
 -			this.logmessage = logmessage;
 -			this.level = level;
 -		}
 -	}
 -
 -	@Override
 -	public void updateState (String state, String logmessage, int resid, ConnectionStatus level) {
 -		mMostRecentState =  new UpdateMessage(state, logmessage, level);
 -		if (ProfileManager.getLastConnectedVpn()!=null)
 -			mMostRecentState.vpnUUID = ProfileManager.getLastConnectedVpn().getUUIDString();
 -
 -		Message msg = mHandler.obtainMessage(SEND_TOALL, mMostRecentState);
 -		msg.sendToTarget();
 -
 -	}
 -
 -	private static final OpenVPNServiceHandler mHandler = new OpenVPNServiceHandler();
 -
 -
 -	static class OpenVPNServiceHandler extends Handler {
 -		WeakReference<ExternalOpenVPNService> service= null;
 -
 -		private void setService(ExternalOpenVPNService eos)
 -		{
 -			service = new WeakReference<ExternalOpenVPNService>(eos);
 -		}
 -
 -		@Override public void handleMessage(Message msg) {
 -
 -			RemoteCallbackList<IOpenVPNStatusCallback> callbacks;
 -			switch (msg.what) {
 -			case SEND_TOALL:
 -				if(service ==null || service.get() == null)
 -					return;
 -
 -				callbacks = service.get().mCallbacks;
 -
 -
 -				// Broadcast to all clients the new value.
 -				final int N = callbacks.beginBroadcast();
 -				for (int i=0; i<N; i++) {
 -					try {
 -						sendUpdate(callbacks.getBroadcastItem(i),(UpdateMessage) msg.obj);
 -					} catch (RemoteException e) {
 -						// The RemoteCallbackList will take care of removing
 -						// the dead object for us.
 -					}
 -				}
 -				callbacks.finishBroadcast();
 -				break;
 -			}
 -		}
 -
 -		private void sendUpdate(IOpenVPNStatusCallback broadcastItem,
 -				UpdateMessage um) throws RemoteException 
 -				{
 -			broadcastItem.newStatus(um.vpnUUID, um.state, um.logmessage, um.level.name());
 -				}
 -	}
 +            ConfigParser cp = new ConfigParser();
 +            try {
 +                cp.parseConfig(new StringReader(inlineconfig));
 +                VpnProfile vp = cp.convertProfile();
 +                if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found)
 +                    throw new RemoteException(getString(vp.checkProfile(getApplicationContext())));
 +
 +
 +                ProfileManager.setTemporaryProfile(vp);
 +                VPNLaunchHelper.startOpenVpn(vp, getBaseContext());
 +
 +
 +            } catch (IOException e) {
 +                throw new RemoteException(e.getMessage());
 +            } catch (ConfigParseError e) {
 +                throw new RemoteException(e.getMessage());
 +            }
 +        }
 +
 +        @Override
 +        public boolean addVPNProfile(String name, String config) throws RemoteException {
 +            checkOpenVPNPermission();
 +
 +            ConfigParser cp = new ConfigParser();
 +            try {
 +                cp.parseConfig(new StringReader(config));
 +                VpnProfile vp = cp.convertProfile();
 +                vp.mName = name;
 +                ProfileManager pm = ProfileManager.getInstance(getBaseContext());
 +                pm.addProfile(vp);
 +            } catch (IOException e) {
 +                e.printStackTrace();
 +                return false;
 +            } catch (ConfigParseError e) {
 +                e.printStackTrace();
 +                return false;
 +            }
 +
 +            return true;
 +        }
 +
 +
 +        @Override
 +        public Intent prepare(String packagename) {
 +            if (new ExternalAppDatabase(ExternalOpenVPNService.this).isAllowed(packagename))
 +                return null;
 +
 +            Intent intent = new Intent();
 +            intent.setClass(ExternalOpenVPNService.this, ConfirmDialog.class);
 +            return intent;
 +        }
 +
 +        @Override
 +        public Intent prepareVPNService() throws RemoteException {
 +            checkOpenVPNPermission();
 +
 +            if (VpnService.prepare(ExternalOpenVPNService.this) == null)
 +                return null;
 +            else
 +                return new Intent(getBaseContext(), GrantPermissionsActivity.class);
 +        }
 +
 +
 +        @Override
 +        public void registerStatusCallback(IOpenVPNStatusCallback cb)
 +                throws RemoteException {
 +            checkOpenVPNPermission();
 +
 +            if (cb != null) {
 +                cb.newStatus(mMostRecentState.vpnUUID, mMostRecentState.state,
 +                        mMostRecentState.logmessage, mMostRecentState.level.name());
 +                mCallbacks.register(cb);
 +            }
 +
 +
 +        }
 +
 +        @Override
 +        public void unregisterStatusCallback(IOpenVPNStatusCallback cb)
 +                throws RemoteException {
 +            checkOpenVPNPermission();
 +
 +            if (cb != null)
 +                mCallbacks.unregister(cb);
 +        }
 +
 +        @Override
 +        public void disconnect() throws RemoteException {
 +            checkOpenVPNPermission();
 +            if (mService != null && mService.getManagement() != null)
 +                mService.getManagement().stopVPN();
 +        }
 +    };
 +
 +
 +    private UpdateMessage mMostRecentState;
 +
 +    @Override
 +    public IBinder onBind(Intent intent) {
 +        return mBinder;
 +    }
 +
 +    @Override
 +    public void onDestroy() {
 +        super.onDestroy();
 +        mCallbacks.kill();
 +        unbindService(mConnection);
 +        VpnStatus.removeStateListener(this);
 +    }
 +
 +    class UpdateMessage {
 +        public String state;
 +        public String logmessage;
 +        public ConnectionStatus level;
 +        public String vpnUUID;
 +
 +        public UpdateMessage(String state, String logmessage, ConnectionStatus level) {
 +            this.state = state;
 +            this.logmessage = logmessage;
 +            this.level = level;
 +        }
 +    }
 +
 +    @Override
 +    public void updateState(String state, String logmessage, int resid, ConnectionStatus level) {
 +        mMostRecentState = new UpdateMessage(state, logmessage, level);
 +        if (ProfileManager.getLastConnectedVpn() != null)
 +            mMostRecentState.vpnUUID = ProfileManager.getLastConnectedVpn().getUUIDString();
 +
 +        Message msg = mHandler.obtainMessage(SEND_TOALL, mMostRecentState);
 +        msg.sendToTarget();
 +
 +    }
 +
 +    private static final OpenVPNServiceHandler mHandler = new OpenVPNServiceHandler();
 +
 +
 +    static class OpenVPNServiceHandler extends Handler {
 +        WeakReference<ExternalOpenVPNService> service = null;
 +
 +        private void setService(ExternalOpenVPNService eos) {
 +            service = new WeakReference<ExternalOpenVPNService>(eos);
 +        }
 +
 +        @Override
 +        public void handleMessage(Message msg) {
 +
 +            RemoteCallbackList<IOpenVPNStatusCallback> callbacks;
 +            switch (msg.what) {
 +                case SEND_TOALL:
 +                    if (service == null || service.get() == null)
 +                        return;
 +
 +                    callbacks = service.get().mCallbacks;
 +
 +
 +                    // Broadcast to all clients the new value.
 +                    final int N = callbacks.beginBroadcast();
 +                    for (int i = 0; i < N; i++) {
 +                        try {
 +                            sendUpdate(callbacks.getBroadcastItem(i), (UpdateMessage) msg.obj);
 +                        } catch (RemoteException e) {
 +                            // The RemoteCallbackList will take care of removing
 +                            // the dead object for us.
 +                        }
 +                    }
 +                    callbacks.finishBroadcast();
 +                    break;
 +            }
 +        }
 +
 +        private void sendUpdate(IOpenVPNStatusCallback broadcastItem,
 +                                UpdateMessage um) throws RemoteException {
 +            broadcastItem.newStatus(um.vpnUUID, um.state, um.logmessage, um.level.name());
 +        }
 +    }
  }
\ No newline at end of file diff --git a/src/de/blinkt/openvpn/core/OpenVPNThread.java b/src/de/blinkt/openvpn/core/OpenVPNThread.java index 0807b33d..f814ff29 100644 --- a/src/de/blinkt/openvpn/core/OpenVPNThread.java +++ b/src/de/blinkt/openvpn/core/OpenVPNThread.java @@ -137,6 +137,9 @@ public class OpenVPNThread implements Runnable {                      else if ((flags & M_DEBUG)!=0)
                          logStatus = VpnStatus.LogLevel.VERBOSE;
 +                    if (msg.startsWith("MANAGEMENT: CMD"))
 +                        logLevel = Math.max(4, logLevel);
 +
                      VpnStatus.logMessageOpenVPN(logStatus,logLevel,msg);
                  } else {
 diff --git a/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java index 03b36144..abca275a 100644 --- a/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -273,8 +273,12 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {          }
          int ovpnlevel = Integer.parseInt(args[2]) & 0x0F;
 +        String msg = args[3];
 -        VpnStatus.logMessageOpenVPN(level,ovpnlevel, args[3]);
 +        if (msg.startsWith("MANAGEMENT: CMD"))
 +            ovpnlevel = Math.max(4, ovpnlevel);
 +
 +        VpnStatus.logMessageOpenVPN(level,ovpnlevel, msg);
      }
      private void handleHold() {
 @@ -387,7 +391,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {  		} else if (needed.equals("IFCONFIG6")) {
  			mOpenVPNService.setLocalIPv6(extra);
 -		} else if (needed.equals("OPENTUN")) {
 +		} else if (needed.equals("PERSIST_TUN_ACTION")) {
 +            // check if tun cfg stayed the same
 +            status = mOpenVPNService.getTunReopenStatus();
 +        } else if (needed.equals("OPENTUN")) {
  			if(sendTunFD(needed,extra))
  				return;
  			else
 diff --git a/src/de/blinkt/openvpn/core/OpenVpnService.java b/src/de/blinkt/openvpn/core/OpenVpnService.java index e4437d2c..ab21fc1b 100644 --- a/src/de/blinkt/openvpn/core/OpenVpnService.java +++ b/src/de/blinkt/openvpn/core/OpenVpnService.java @@ -14,6 +14,7 @@ import android.net.VpnService;  import android.os.*;  import android.os.Handler.Callback;  import android.preference.PreferenceManager; +import android.text.TextUtils;  import de.blinkt.openvpn.DisconnectVPN;  import de.blinkt.openvpn.LogWindow;  import de.blinkt.openvpn.R; @@ -24,6 +25,7 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener;  import java.lang.reflect.InvocationTargetException;  import java.lang.reflect.Method; +import java.security.MessageDigest;  import java.util.HashMap;  import java.util.Locale;  import java.util.Vector; @@ -55,6 +57,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac      private long mConnecttime;      private boolean mOvpn3 = false;      private OpenVPNManagement mManagement; +    private String mLastTunCfg;      // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java      public static String humanReadableByteCount(long bytes, boolean mbit) { @@ -386,6 +389,24 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac      } +    private String getTunConfigString() +    { +        // The format of the string is not important, only that +        // two identical configurations produce the same result +        String cfg="TUNCFG UNQIUE STRING ips:"; + +        if (mLocalIP!=null) +            cfg+=mLocalIP.toString(); +        if (mLocalIPv6!=null) +            cfg+=mLocalIPv6.toString(); + +        cfg+= "routes: " + TextUtils.join("|",mRoutes) + TextUtils.join("|",mRoutesv6); +        cfg+= "dns: " + TextUtils.join("|",mDnslist); +        cfg+= "domain: " + mDomain; +        cfg+= "mtu: " + mMtu; +        return cfg; +    } +      public ParcelFileDescriptor openTun() {          Builder builder = new Builder(); @@ -465,6 +486,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac          if (mDnslist.size() == 0)              VpnStatus.logInfo(R.string.warn_no_dns); +        mLastTunCfg = getTunConfigString(); +          // Reset information          mDnslist.clear();          mRoutes.clear(); @@ -625,6 +648,16 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac          return mManagement;      } +    public String getTunReopenStatus() { +        String currentConfiguration = getTunConfigString(); +        if(currentConfiguration.equals(mLastTunCfg)) +            return "NOACTION"; +        else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) +            return "OPEN_AFTER_CLOSE"; +        else +            return "OPEN_BEFORE_CLOSE"; +    } +      public class LocalBinder extends Binder {          public OpenVpnService getService() {              // Return this instance of LocalService so clients can call public methods  | 
