diff options
author | Hung-ying Tyan <tyanh@google.com> | 2009-07-11 22:23:30 +0800 |
---|---|---|
committer | Hung-ying Tyan <tyanh@google.com> | 2009-07-13 13:11:36 +0800 |
commit | df1aa3359ccfe81a3f79ed457c7bfc75942a9d91 (patch) | |
tree | 8d915f8762b7ce3271a0a0d2b4f84287b9cda059 | |
parent | cf29e116129f38309c18ba14b9893b079a712289 (diff) | |
download | frameworks_base-df1aa3359ccfe81a3f79ed457c7bfc75942a9d91.zip frameworks_base-df1aa3359ccfe81a3f79ed457c7bfc75942a9d91.tar.gz frameworks_base-df1aa3359ccfe81a3f79ed457c7bfc75942a9d91.tar.bz2 |
Add error code in vpn connectivity broadcast.
* Changes
+ Add VpnConnectingError.java.
+ Broadcast the error returned by daemons.
+ Add error codes to VpnManager.java.
+ Add error code to VpnManager.broadcastConnectivity().
Patch Set 4:
+ Replace VPN_UP with VPN_STATUS in response to ip-up-vpn changes.
+ Make VpnServiceBinder a foreground service so that it won't be
interrupted by the system.
Patch Set 5:
+ Remove the support of returning 0 from daemon and restart socket in
AndroidServiceProxy.
5 files changed, 134 insertions, 48 deletions
diff --git a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java index 7dd9d9e..7e8185e 100644 --- a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java +++ b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java @@ -18,6 +18,7 @@ package com.android.server.vpn; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.net.vpn.VpnManager; import android.os.SystemProperties; import android.util.Log; @@ -48,6 +49,9 @@ public class AndroidServiceProxy extends ProcessProxy { private static final int END_OF_ARGUMENTS = 255; + private static final int STOP_SERVICE = -1; + private static final int AUTH_ERROR_CODE = 51; + private String mServiceName; private String mSocketName; private LocalSocket mKeepaliveSocket; @@ -72,14 +76,21 @@ public class AndroidServiceProxy extends ProcessProxy { @Override public synchronized void stop() { - if (isRunning()) setResultAndCloseControlSocket(-1); + if (isRunning()) { + try { + setResultAndCloseControlSocket(STOP_SERVICE); + } catch (IOException e) { + // should not occur + throw new RuntimeException(e); + } + } SystemProperties.set(SVC_STOP_CMD, mServiceName); } /** * Sends a command with arguments to the service through the control socket. */ - public void sendCommand(String ...args) throws IOException { + public synchronized void sendCommand(String ...args) throws IOException { OutputStream out = getControlSocketOutput(); for (String arg : args) outputString(out, arg); out.write(END_OF_ARGUMENTS); @@ -114,30 +125,22 @@ public class AndroidServiceProxy extends ProcessProxy { InputStream in = s.getInputStream(); int data = in.read(); if (data >= 0) { - Log.d(mTag, "got data from keepalive socket: " + data); - - if (data == 0) { - // re-establish the connection: - // synchronized here so that checkSocketResult() - // returns when new mKeepaliveSocket is available for - // next cmd - synchronized (this) { - setResultAndCloseControlSocket((byte) data); - s = mKeepaliveSocket = createServiceSocket(); - } - } else { - // keep the socket - setSocketResult(data); - } + Log.d(mTag, "got data from control socket: " + data); + + setSocketResult(data); } else { // service is gone if (mControlSocketInUse) setSocketResult(-1); break; } } - Log.d(mTag, "keepalive connection closed"); + Log.d(mTag, "control connection closed"); } catch (IOException e) { - Log.d(mTag, "keepalive socket broken: " + e.getMessage()); + if (e instanceof VpnConnectingError) { + throw e; + } else { + Log.d(mTag, "control socket broken: " + e.getMessage()); + } } // Wait 5 seconds for the service to exit @@ -179,7 +182,7 @@ public class AndroidServiceProxy extends ProcessProxy { } } - private synchronized void checkSocketResult() throws IOException { + private void checkSocketResult() throws IOException { try { // will be notified when the result comes back from service if (mSocketResult == null) wait(); @@ -194,14 +197,21 @@ public class AndroidServiceProxy extends ProcessProxy { } } - private synchronized void setSocketResult(int result) { + private synchronized void setSocketResult(int result) + throws VpnConnectingError { if (mControlSocketInUse) { mSocketResult = result; notifyAll(); + } else if (result > 0) { + // error from daemon + throw new VpnConnectingError((result == AUTH_ERROR_CODE) + ? VpnManager.VPN_ERROR_AUTH + : VpnManager.VPN_ERROR_CONNECTION_FAILED); } } - private void setResultAndCloseControlSocket(int result) { + private void setResultAndCloseControlSocket(int result) + throws VpnConnectingError { setSocketResult(result); try { mKeepaliveSocket.shutdownInput(); diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java b/packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java new file mode 100644 index 0000000..3c4ec7d --- /dev/null +++ b/packages/VpnServices/src/com/android/server/vpn/VpnConnectingError.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.vpn; + +import java.io.IOException; + +/** + * Exception thrown when a connecting attempt fails. + */ +class VpnConnectingError extends IOException { + private int mErrorCode; + + VpnConnectingError(int errorCode) { + super("Connecting error: " + errorCode); + mErrorCode = errorCode; + } + + int getErrorCode() { + return mErrorCode; + } +} diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java index 22669d2..47baf48 100644 --- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java +++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.Socket; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; @@ -46,9 +47,9 @@ abstract class VpnService<E extends VpnProfile> { private static final String DNS2 = "net.dns2"; private static final String VPN_DNS1 = "vpn.dns1"; private static final String VPN_DNS2 = "vpn.dns2"; - private static final String VPN_UP = "vpn.up"; - private static final String VPN_IS_UP = "1"; - private static final String VPN_IS_DOWN = "0"; + private static final String VPN_STATUS = "vpn.status"; + private static final String VPN_IS_UP = "ok"; + private static final String VPN_IS_DOWN = "down"; private static final String REMOTE_IP = "net.ipremote"; private static final String DNS_DOMAIN_SUFFICES = "net.dns.search"; @@ -60,6 +61,7 @@ abstract class VpnService<E extends VpnProfile> { private VpnState mState = VpnState.IDLE; private boolean mInError; + private VpnConnectingError mError; // connection settings private String mOriginalDns1; @@ -166,16 +168,23 @@ abstract class VpnService<E extends VpnProfile> { return mState; } - synchronized void onConnect(String username, String password) - throws IOException { - mState = VpnState.CONNECTING; - broadcastConnectivity(VpnState.CONNECTING); + synchronized boolean onConnect(String username, String password) { + try { + mState = VpnState.CONNECTING; + broadcastConnectivity(VpnState.CONNECTING); - String serverIp = getIp(getProfile().getServerName()); + String serverIp = getIp(getProfile().getServerName()); - onBeforeConnect(); - connect(serverIp, username, password); - waitUntilConnectedOrTimedout(); + onBeforeConnect(); + connect(serverIp, username, password); + waitUntilConnectedOrTimedout(); + return true; + } catch (Throwable e) { + Log.e(TAG, "onConnect()", e); + mError = newConnectingError(e); + onError(); + return false; + } } synchronized void onDisconnect(boolean cleanUpServices) { @@ -214,8 +223,8 @@ abstract class VpnService<E extends VpnProfile> { SystemProperties.set(VPN_DNS1, "-"); SystemProperties.set(VPN_DNS2, "-"); - SystemProperties.set(VPN_UP, VPN_IS_DOWN); - Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_UP)); + SystemProperties.set(VPN_STATUS, VPN_IS_DOWN); + Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS)); } private void waitUntilConnectedOrTimedout() { @@ -224,7 +233,7 @@ abstract class VpnService<E extends VpnProfile> { public void run() { sleep(2000); // 2 seconds for (int i = 0; i < 60; i++) { - if (VPN_IS_UP.equals(SystemProperties.get(VPN_UP))) { + if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) { onConnected(); return; } else if (mState != VpnState.CONNECTING) { @@ -271,6 +280,13 @@ abstract class VpnService<E extends VpnProfile> { mContext.stopSelf(); } + private VpnConnectingError newConnectingError(Throwable e) { + return new VpnConnectingError( + (e instanceof UnknownHostException) + ? VpnManager.VPN_ERROR_UNKNOWN_SERVER + : VpnManager.VPN_ERROR_CONNECTION_FAILED); + } + private synchronized void onOneServiceGone() { switch (mState) { case IDLE: @@ -347,7 +363,13 @@ abstract class VpnService<E extends VpnProfile> { } private void broadcastConnectivity(VpnState s) { - new VpnManager(mContext).broadcastConnectivity(mProfile.getName(), s); + VpnManager m = new VpnManager(mContext); + if ((s == VpnState.IDLE) && (mError != null)) { + m.broadcastConnectivity(mProfile.getName(), s, + mError.getErrorCode()); + } else { + m.broadcastConnectivity(mProfile.getName(), s); + } } private void startConnectivityMonitor() { @@ -447,6 +469,9 @@ abstract class VpnService<E extends VpnProfile> { //@Override public void error(ProcessProxy p, Throwable e) { Log.e(TAG, "service error: " + p.getName(), e); + if (e instanceof VpnConnectingError) { + mError = (VpnConnectingError) e; + } commonCallback((AndroidServiceProxy) p); } diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java index 617875e..cf153e3 100644 --- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java +++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java @@ -27,7 +27,6 @@ import android.net.vpn.VpnManager; import android.net.vpn.VpnProfile; import android.net.vpn.VpnState; import android.os.IBinder; -import android.util.Log; import java.io.IOException; @@ -55,6 +54,11 @@ public class VpnServiceBinder extends Service { } }; + public void onStart (Intent intent, int startId) { + super.onStart(intent, startId); + setForeground(true); + } + public IBinder onBind(Intent intent) { return mBinder; } @@ -62,15 +66,8 @@ public class VpnServiceBinder extends Service { private synchronized boolean connect( VpnProfile p, String username, String password) { if (mService != null) return false; - try { - mService = createService(p); - mService.onConnect(username, password); - return true; - } catch (Throwable e) { - Log.e(TAG, "connect()", e); - if (mService != null) mService.onError(); - return false; - } + mService = createService(p); + return mService.onConnect(username, password); } private synchronized void checkStatus(VpnProfile p) { diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java index dc70b26..0bf2346 100644 --- a/vpn/java/android/net/vpn/VpnManager.java +++ b/vpn/java/android/net/vpn/VpnManager.java @@ -42,6 +42,15 @@ public class VpnManager { public static final String BROADCAST_PROFILE_NAME = "profile_name"; /** Key to the connectivity state of a connectivity broadcast event. */ public static final String BROADCAST_CONNECTION_STATE = "connection_state"; + /** Key to the error code of a connectivity broadcast event. */ + public static final String BROADCAST_ERROR_CODE = "err"; + /** Error code to indicate an error from authentication. */ + public static final int VPN_ERROR_AUTH = 1; + /** Error code to indicate the connection attempt failed. */ + public static final int VPN_ERROR_CONNECTION_FAILED = 2; + /** Error code to indicate the server is not known. */ + public static final int VPN_ERROR_UNKNOWN_SERVER = 3; + private static final int VPN_ERROR_NO_ERROR = 0; public static final String PROFILES_PATH = "/data/misc/vpn/profiles"; @@ -52,7 +61,8 @@ public class VpnManager { private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE"; // Action to start VPN settings - private static final String ACTION_VPN_SETTINGS = PACKAGE_PREFIX + "SETTINGS"; + private static final String ACTION_VPN_SETTINGS = + PACKAGE_PREFIX + "SETTINGS"; private static final String TAG = VpnManager.class.getSimpleName(); @@ -130,9 +140,18 @@ public class VpnManager { /** Broadcasts the connectivity state of the specified profile. */ public void broadcastConnectivity(String profileName, VpnState s) { + broadcastConnectivity(profileName, s, VPN_ERROR_NO_ERROR); + } + + /** Broadcasts the connectivity state with an error code. */ + public void broadcastConnectivity(String profileName, VpnState s, + int error) { Intent intent = new Intent(ACTION_VPN_CONNECTIVITY); intent.putExtra(BROADCAST_PROFILE_NAME, profileName); intent.putExtra(BROADCAST_CONNECTION_STATE, s); + if (error != VPN_ERROR_NO_ERROR) { + intent.putExtra(BROADCAST_ERROR_CODE, error); + } mContext.sendBroadcast(intent); } |