Merge change 6883 into donut
* changes: Add error code in vpn connectivity broadcast.
This commit is contained in:
@@ -18,6 +18,7 @@ package com.android.server.vpn;
|
|||||||
|
|
||||||
import android.net.LocalSocket;
|
import android.net.LocalSocket;
|
||||||
import android.net.LocalSocketAddress;
|
import android.net.LocalSocketAddress;
|
||||||
|
import android.net.vpn.VpnManager;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.util.Log;
|
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 END_OF_ARGUMENTS = 255;
|
||||||
|
|
||||||
|
private static final int STOP_SERVICE = -1;
|
||||||
|
private static final int AUTH_ERROR_CODE = 51;
|
||||||
|
|
||||||
private String mServiceName;
|
private String mServiceName;
|
||||||
private String mSocketName;
|
private String mSocketName;
|
||||||
private LocalSocket mKeepaliveSocket;
|
private LocalSocket mKeepaliveSocket;
|
||||||
@@ -72,14 +76,21 @@ public class AndroidServiceProxy extends ProcessProxy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void stop() {
|
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);
|
SystemProperties.set(SVC_STOP_CMD, mServiceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a command with arguments to the service through the control socket.
|
* 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();
|
OutputStream out = getControlSocketOutput();
|
||||||
for (String arg : args) outputString(out, arg);
|
for (String arg : args) outputString(out, arg);
|
||||||
out.write(END_OF_ARGUMENTS);
|
out.write(END_OF_ARGUMENTS);
|
||||||
@@ -114,30 +125,22 @@ public class AndroidServiceProxy extends ProcessProxy {
|
|||||||
InputStream in = s.getInputStream();
|
InputStream in = s.getInputStream();
|
||||||
int data = in.read();
|
int data = in.read();
|
||||||
if (data >= 0) {
|
if (data >= 0) {
|
||||||
Log.d(mTag, "got data from keepalive socket: " + data);
|
Log.d(mTag, "got data from control socket: " + data);
|
||||||
|
|
||||||
if (data == 0) {
|
setSocketResult(data);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// service is gone
|
// service is gone
|
||||||
if (mControlSocketInUse) setSocketResult(-1);
|
if (mControlSocketInUse) setSocketResult(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(mTag, "keepalive connection closed");
|
Log.d(mTag, "control connection closed");
|
||||||
} catch (IOException e) {
|
} 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
|
// 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 {
|
try {
|
||||||
// will be notified when the result comes back from service
|
// will be notified when the result comes back from service
|
||||||
if (mSocketResult == null) wait();
|
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) {
|
if (mControlSocketInUse) {
|
||||||
mSocketResult = result;
|
mSocketResult = result;
|
||||||
notifyAll();
|
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);
|
setSocketResult(result);
|
||||||
try {
|
try {
|
||||||
mKeepaliveSocket.shutdownInput();
|
mKeepaliveSocket.shutdownInput();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ import java.io.IOException;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
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 DNS2 = "net.dns2";
|
||||||
private static final String VPN_DNS1 = "vpn.dns1";
|
private static final String VPN_DNS1 = "vpn.dns1";
|
||||||
private static final String VPN_DNS2 = "vpn.dns2";
|
private static final String VPN_DNS2 = "vpn.dns2";
|
||||||
private static final String VPN_UP = "vpn.up";
|
private static final String VPN_STATUS = "vpn.status";
|
||||||
private static final String VPN_IS_UP = "1";
|
private static final String VPN_IS_UP = "ok";
|
||||||
private static final String VPN_IS_DOWN = "0";
|
private static final String VPN_IS_DOWN = "down";
|
||||||
|
|
||||||
private static final String REMOTE_IP = "net.ipremote";
|
private static final String REMOTE_IP = "net.ipremote";
|
||||||
private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
|
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 VpnState mState = VpnState.IDLE;
|
||||||
private boolean mInError;
|
private boolean mInError;
|
||||||
|
private VpnConnectingError mError;
|
||||||
|
|
||||||
// connection settings
|
// connection settings
|
||||||
private String mOriginalDns1;
|
private String mOriginalDns1;
|
||||||
@@ -166,16 +168,23 @@ abstract class VpnService<E extends VpnProfile> {
|
|||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void onConnect(String username, String password)
|
synchronized boolean onConnect(String username, String password) {
|
||||||
throws IOException {
|
try {
|
||||||
mState = VpnState.CONNECTING;
|
mState = VpnState.CONNECTING;
|
||||||
broadcastConnectivity(VpnState.CONNECTING);
|
broadcastConnectivity(VpnState.CONNECTING);
|
||||||
|
|
||||||
String serverIp = getIp(getProfile().getServerName());
|
String serverIp = getIp(getProfile().getServerName());
|
||||||
|
|
||||||
onBeforeConnect();
|
onBeforeConnect();
|
||||||
connect(serverIp, username, password);
|
connect(serverIp, username, password);
|
||||||
waitUntilConnectedOrTimedout();
|
waitUntilConnectedOrTimedout();
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.e(TAG, "onConnect()", e);
|
||||||
|
mError = newConnectingError(e);
|
||||||
|
onError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void onDisconnect(boolean cleanUpServices) {
|
synchronized void onDisconnect(boolean cleanUpServices) {
|
||||||
@@ -214,8 +223,8 @@ abstract class VpnService<E extends VpnProfile> {
|
|||||||
|
|
||||||
SystemProperties.set(VPN_DNS1, "-");
|
SystemProperties.set(VPN_DNS1, "-");
|
||||||
SystemProperties.set(VPN_DNS2, "-");
|
SystemProperties.set(VPN_DNS2, "-");
|
||||||
SystemProperties.set(VPN_UP, VPN_IS_DOWN);
|
SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
|
||||||
Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_UP));
|
Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitUntilConnectedOrTimedout() {
|
private void waitUntilConnectedOrTimedout() {
|
||||||
@@ -224,7 +233,7 @@ abstract class VpnService<E extends VpnProfile> {
|
|||||||
public void run() {
|
public void run() {
|
||||||
sleep(2000); // 2 seconds
|
sleep(2000); // 2 seconds
|
||||||
for (int i = 0; i < 60; i++) {
|
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();
|
onConnected();
|
||||||
return;
|
return;
|
||||||
} else if (mState != VpnState.CONNECTING) {
|
} else if (mState != VpnState.CONNECTING) {
|
||||||
@@ -271,6 +280,13 @@ abstract class VpnService<E extends VpnProfile> {
|
|||||||
mContext.stopSelf();
|
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() {
|
private synchronized void onOneServiceGone() {
|
||||||
switch (mState) {
|
switch (mState) {
|
||||||
case IDLE:
|
case IDLE:
|
||||||
@@ -347,7 +363,13 @@ abstract class VpnService<E extends VpnProfile> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void broadcastConnectivity(VpnState s) {
|
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() {
|
private void startConnectivityMonitor() {
|
||||||
@@ -447,6 +469,9 @@ abstract class VpnService<E extends VpnProfile> {
|
|||||||
//@Override
|
//@Override
|
||||||
public void error(ProcessProxy p, Throwable e) {
|
public void error(ProcessProxy p, Throwable e) {
|
||||||
Log.e(TAG, "service error: " + p.getName(), e);
|
Log.e(TAG, "service error: " + p.getName(), e);
|
||||||
|
if (e instanceof VpnConnectingError) {
|
||||||
|
mError = (VpnConnectingError) e;
|
||||||
|
}
|
||||||
commonCallback((AndroidServiceProxy) p);
|
commonCallback((AndroidServiceProxy) p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import android.net.vpn.VpnManager;
|
|||||||
import android.net.vpn.VpnProfile;
|
import android.net.vpn.VpnProfile;
|
||||||
import android.net.vpn.VpnState;
|
import android.net.vpn.VpnState;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
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) {
|
public IBinder onBind(Intent intent) {
|
||||||
return mBinder;
|
return mBinder;
|
||||||
}
|
}
|
||||||
@@ -62,15 +66,8 @@ public class VpnServiceBinder extends Service {
|
|||||||
private synchronized boolean connect(
|
private synchronized boolean connect(
|
||||||
VpnProfile p, String username, String password) {
|
VpnProfile p, String username, String password) {
|
||||||
if (mService != null) return false;
|
if (mService != null) return false;
|
||||||
try {
|
mService = createService(p);
|
||||||
mService = createService(p);
|
return mService.onConnect(username, password);
|
||||||
mService.onConnect(username, password);
|
|
||||||
return true;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Log.e(TAG, "connect()", e);
|
|
||||||
if (mService != null) mService.onError();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void checkStatus(VpnProfile p) {
|
private synchronized void checkStatus(VpnProfile p) {
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ public class VpnManager {
|
|||||||
public static final String BROADCAST_PROFILE_NAME = "profile_name";
|
public static final String BROADCAST_PROFILE_NAME = "profile_name";
|
||||||
/** Key to the connectivity state of a connectivity broadcast event. */
|
/** Key to the connectivity state of a connectivity broadcast event. */
|
||||||
public static final String BROADCAST_CONNECTION_STATE = "connection_state";
|
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";
|
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";
|
private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE";
|
||||||
|
|
||||||
// Action to start VPN settings
|
// 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();
|
private static final String TAG = VpnManager.class.getSimpleName();
|
||||||
|
|
||||||
@@ -130,9 +140,18 @@ public class VpnManager {
|
|||||||
|
|
||||||
/** Broadcasts the connectivity state of the specified profile. */
|
/** Broadcasts the connectivity state of the specified profile. */
|
||||||
public void broadcastConnectivity(String profileName, VpnState s) {
|
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 intent = new Intent(ACTION_VPN_CONNECTIVITY);
|
||||||
intent.putExtra(BROADCAST_PROFILE_NAME, profileName);
|
intent.putExtra(BROADCAST_PROFILE_NAME, profileName);
|
||||||
intent.putExtra(BROADCAST_CONNECTION_STATE, s);
|
intent.putExtra(BROADCAST_CONNECTION_STATE, s);
|
||||||
|
if (error != VPN_ERROR_NO_ERROR) {
|
||||||
|
intent.putExtra(BROADCAST_ERROR_CODE, error);
|
||||||
|
}
|
||||||
mContext.sendBroadcast(intent);
|
mContext.sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user