summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorHung-ying Tyan <tyanh@google.com>2009-07-30 14:02:48 +0800
committerHung-ying Tyan <tyanh@google.com>2009-07-30 19:14:50 +0800
commitfe8e48cdd5e621905b8c07325dbe77bffffdb4bb (patch)
tree0b627a159a56a490ff1f655aea85d214da423b2a /packages
parentb91e2b0292f9f4f76175a18e6e3cf392f3967ae8 (diff)
downloadframeworks_base-fe8e48cdd5e621905b8c07325dbe77bffffdb4bb.zip
frameworks_base-fe8e48cdd5e621905b8c07325dbe77bffffdb4bb.tar.gz
frameworks_base-fe8e48cdd5e621905b8c07325dbe77bffffdb4bb.tar.bz2
Add state saving mechanism to support proc restart
Also... + stop daemons before getting server IP; + remove setForeground(); + add the DBG flag for Log.d calls. PatchSet 3: + add CHALLENGE_ERROR and REMOTE_HUNG_UP to VpnManager + broadcast new error codes in VpnService + check local IP change instead of dns change + move removeStates() to VpnService.onFinalCleanUp() PatchSet 7: + add encryption flag to PptpProfile + PptpService and MtpdHelper are revised accordingly
Diffstat (limited to 'packages')
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java32
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java6
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java6
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/L2tpService.java5
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java20
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/PptpService.java8
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnService.java217
-rw-r--r--packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java61
8 files changed, 253 insertions, 102 deletions
diff --git a/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java b/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java
index b749821..289ee45 100644
--- a/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java
@@ -25,6 +25,7 @@ import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Serializable;
/**
* Proxy to start, stop and interact with a VPN daemon.
@@ -33,7 +34,10 @@ import java.io.OutputStream;
* connection with the daemon, to both send commands to the daemon and receive
* response and connecting error code from the daemon.
*/
-class DaemonProxy {
+class DaemonProxy implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private static final boolean DBG = true;
+
private static final int WAITING_TIME = 15; // sec
private static final String SVC_STATE_CMD_PREFIX = "init.svc.";
@@ -45,8 +49,8 @@ class DaemonProxy {
private static final int END_OF_ARGUMENTS = 255;
private String mName;
- private LocalSocket mControlSocket;
private String mTag;
+ private transient LocalSocket mControlSocket;
/**
* Creates a proxy of the specified daemon.
@@ -63,14 +67,8 @@ class DaemonProxy {
void start() throws IOException {
String svc = mName;
- Log.d(mTag, "----- Stop the daemon just in case: " + mName);
- SystemProperties.set(SVC_STOP_CMD, mName);
- if (!blockUntil(SVC_STATE_STOPPED, 5)) {
- throw new IOException("cannot start service anew: " + svc
- + ", it is still running");
- }
- Log.d(mTag, "+++++ Start: " + svc);
+ Log.i(mTag, "Start VPN daemon: " + svc);
SystemProperties.set(SVC_START_CMD, svc);
if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) {
@@ -103,7 +101,7 @@ class DaemonProxy {
try {
mControlSocket.close();
} catch (IOException e) {
- Log.e(mTag, "close control socket", e);
+ Log.w(mTag, "close control socket", e);
} finally {
mControlSocket = null;
}
@@ -111,10 +109,10 @@ class DaemonProxy {
void stop() {
String svc = mName;
- Log.d(mTag, "----- Stop: " + svc);
+ Log.i(mTag, "Stop VPN daemon: " + svc);
SystemProperties.set(SVC_STOP_CMD, svc);
boolean success = blockUntil(SVC_STATE_STOPPED, 5);
- Log.d(mTag, "stopping " + svc + ", success? " + success);
+ if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success);
}
boolean isStopped() {
@@ -129,7 +127,7 @@ class DaemonProxy {
if (!blocking && in.available() == 0) return 0;
int data = in.read();
- Log.d(mTag, "got data from control socket: " + data);
+ Log.i(mTag, "got data from control socket: " + data);
return data;
}
@@ -146,7 +144,7 @@ class DaemonProxy {
s.connect(a);
return s;
} catch (IOException e) {
- Log.d(mTag, "service not yet listen()ing; try again");
+ if (DBG) Log.d(mTag, "service not yet listen()ing; try again");
excp = e;
sleep(500);
}
@@ -173,8 +171,10 @@ class DaemonProxy {
int n = waitTime * 1000 / sleepTime;
for (int i = 0; i < n; i++) {
if (expectedState.equals(SystemProperties.get(cmd))) {
- Log.d(mTag, mName + " is " + expectedState + " after "
- + (i * sleepTime) + " msec");
+ if (DBG) {
+ Log.d(mTag, mName + " is " + expectedState + " after "
+ + (i * sleepTime) + " msec");
+ }
break;
}
sleep(sleepTime);
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
index 8efd7c4..7910f4a 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
@@ -45,4 +45,10 @@ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> {
(p.isSecretEnabled() ? p.getSecretString() : null),
username, password);
}
+
+ @Override
+ protected void stopPreviouslyRunDaemons() {
+ stopDaemon(IPSEC);
+ stopDaemon(MtpdHelper.MTPD);
+ }
}
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index 56694b6..13b4952 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -46,6 +46,12 @@ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> {
username, password);
}
+ @Override
+ protected void stopPreviouslyRunDaemons() {
+ stopDaemon(IPSEC);
+ stopDaemon(MtpdHelper.MTPD);
+ }
+
private String getCaCertPath() {
return CertTool.getInstance().getCaCertificate(
getProfile().getCaCertificate());
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
index 9273f35..d658a36 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
@@ -35,4 +35,9 @@ class L2tpService extends VpnService<L2tpProfile> {
(p.isSecretEnabled() ? p.getSecretString() : null),
username, password);
}
+
+ @Override
+ protected void stopPreviouslyRunDaemons() {
+ stopDaemon(MtpdHelper.MTPD);
+ }
}
diff --git a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
index 805a5b5..9078d9b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
+++ b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
@@ -24,26 +24,33 @@ import java.util.Arrays;
* A helper class for sending commands to the MTP daemon (mtpd).
*/
class MtpdHelper {
- private static final String MTPD = "mtpd";
+ static final String MTPD = "mtpd";
private static final String VPN_LINKNAME = "vpn";
private static final String PPP_ARGS_SEPARATOR = "";
static void sendCommand(VpnService<?> vpnService, String protocol,
String serverIp, String port, String secret, String username,
String password) throws IOException {
+ sendCommand(vpnService, protocol, serverIp, port, secret, username,
+ password, false);
+ }
+
+ static void sendCommand(VpnService<?> vpnService, String protocol,
+ String serverIp, String port, String secret, String username,
+ String password, boolean encryption) throws IOException {
ArrayList<String> args = new ArrayList<String>();
args.addAll(Arrays.asList(protocol, serverIp, port));
if (secret != null) args.add(secret);
args.add(PPP_ARGS_SEPARATOR);
- addPppArguments(vpnService, args, serverIp, username, password);
+ addPppArguments(args, serverIp, username, password, encryption);
DaemonProxy mtpd = vpnService.startDaemon(MTPD);
mtpd.sendCommand(args.toArray(new String[args.size()]));
}
- private static void addPppArguments(VpnService<?> vpnService,
- ArrayList<String> args, String serverIp, String username,
- String password) throws IOException {
+ private static void addPppArguments(ArrayList<String> args, String serverIp,
+ String username, String password, boolean encryption)
+ throws IOException {
args.addAll(Arrays.asList(
"linkname", VPN_LINKNAME,
"name", username,
@@ -52,6 +59,9 @@ class MtpdHelper {
"idle", "1800",
"mtu", "1400",
"mru", "1400"));
+ if (encryption) {
+ args.add("+mppe");
+ }
}
private MtpdHelper() {
diff --git a/packages/VpnServices/src/com/android/server/vpn/PptpService.java b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
index 01362a5..d903d1b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/PptpService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
@@ -26,11 +26,17 @@ import java.io.IOException;
class PptpService extends VpnService<PptpProfile> {
static final String PPTP_DAEMON = "pptp";
static final String PPTP_PORT = "1723";
+
@Override
protected void connect(String serverIp, String username, String password)
throws IOException {
+ PptpProfile p = getProfile();
MtpdHelper.sendCommand(this, PPTP_DAEMON, serverIp, PPTP_PORT, null,
- username, password);
+ username, password, p.isEncryptionEnabled());
}
+ @Override
+ protected void stopPreviouslyRunDaemons() {
+ stopDaemon(MtpdHelper.MTPD);
+ }
}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index 60a07d5..b107c7d 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -28,7 +28,11 @@ import android.text.TextUtils;
import android.util.Log;
import java.io.IOException;
+import java.io.Serializable;
+import java.net.DatagramSocket;
+import java.net.Socket;
import java.net.InetAddress;
+import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
@@ -36,7 +40,9 @@ import java.util.List;
/**
* The service base class for managing a type of VPN connection.
*/
-abstract class VpnService<E extends VpnProfile> {
+abstract class VpnService<E extends VpnProfile> implements Serializable {
+ protected static final long serialVersionUID = 1L;
+ private static final boolean DBG = true;
private static final int NOTIFICATION_ID = 1;
private static final String DNS1 = "net.dns1";
@@ -50,12 +56,16 @@ abstract class VpnService<E extends VpnProfile> {
private static final String REMOTE_IP = "net.ipremote";
private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
+ private static final int CHALLENGE_ERROR_CODE = 5;
+ private static final int REMOTE_HUNG_UP_ERROR_CODE = 7;
private static final int AUTH_ERROR_CODE = 51;
private final String TAG = VpnService.class.getSimpleName();
+ // FIXME: profile is only needed in connecting phase, so we can just save
+ // the profile name and service class name for recovery
E mProfile;
- VpnServiceBinder mContext;
+ transient VpnServiceBinder mContext;
private VpnState mState = VpnState.IDLE;
private Throwable mError;
@@ -63,9 +73,9 @@ abstract class VpnService<E extends VpnProfile> {
// connection settings
private String mOriginalDns1;
private String mOriginalDns2;
- private String mVpnDns1 = "";
- private String mVpnDns2 = "";
private String mOriginalDomainSuffices;
+ private String mLocalIp;
+ private String mLocalIf;
private long mStartTime; // VPN connection start time
@@ -73,7 +83,7 @@ abstract class VpnService<E extends VpnProfile> {
private DaemonHelper mDaemonHelper = new DaemonHelper();
// for helping showing, updating notification
- private NotificationHelper mNotification = new NotificationHelper();
+ private transient NotificationHelper mNotification;
/**
* Establishes a VPN connection with the specified username and password.
@@ -81,6 +91,8 @@ abstract class VpnService<E extends VpnProfile> {
protected abstract void connect(String serverIp, String username,
String password) throws IOException;
+ protected abstract void stopPreviouslyRunDaemons();
+
/**
* Starts a VPN daemon.
*/
@@ -90,6 +102,13 @@ abstract class VpnService<E extends VpnProfile> {
}
/**
+ * Stops a VPN daemon.
+ */
+ protected void stopDaemon(String daemonName) {
+ new DaemonProxy(daemonName).stop();
+ }
+
+ /**
* Returns the VPN profile associated with the connection.
*/
protected E getProfile() {
@@ -104,8 +123,22 @@ abstract class VpnService<E extends VpnProfile> {
}
void setContext(VpnServiceBinder context, E profile) {
- mContext = context;
mProfile = profile;
+ recover(context);
+ }
+
+ void recover(VpnServiceBinder context) {
+ mContext = context;
+ mNotification = new NotificationHelper();
+
+ if (VpnState.CONNECTED.equals(mState)) {
+ Log.i("VpnService", " recovered: " + mProfile.getName());
+ new Thread(new Runnable() {
+ public void run() {
+ enterConnectivityLoop();
+ }
+ }).start();
+ }
}
VpnState getState() {
@@ -117,14 +150,14 @@ abstract class VpnService<E extends VpnProfile> {
mState = VpnState.CONNECTING;
broadcastConnectivity(VpnState.CONNECTING);
+ stopPreviouslyRunDaemons();
String serverIp = getIp(getProfile().getServerName());
-
+ saveLocalIpAndInterface(serverIp);
onBeforeConnect();
connect(serverIp, username, password);
waitUntilConnectedOrTimedout();
return true;
} catch (Throwable e) {
- Log.e(TAG, "onConnect()", e);
onError(e);
return false;
}
@@ -132,7 +165,7 @@ abstract class VpnService<E extends VpnProfile> {
synchronized void onDisconnect() {
try {
- Log.d(TAG, " disconnecting VPN...");
+ Log.i(TAG, "disconnecting VPN...");
mState = VpnState.DISCONNECTING;
broadcastConnectivity(VpnState.DISCONNECTING);
mNotification.showDisconnect();
@@ -152,6 +185,7 @@ abstract class VpnService<E extends VpnProfile> {
Log.w(TAG, " multiple errors occur, record the last one: "
+ error);
}
+ Log.e(TAG, "onError()", error);
mError = error;
onDisconnect();
}
@@ -161,16 +195,18 @@ abstract class VpnService<E extends VpnProfile> {
}
- private void onBeforeConnect() {
+ private void onBeforeConnect() throws IOException {
mNotification.disableNotification();
- SystemProperties.set(VPN_DNS1, "-");
- SystemProperties.set(VPN_DNS2, "-");
+ SystemProperties.set(VPN_DNS1, "");
+ SystemProperties.set(VPN_DNS2, "");
SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
- Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
+ if (DBG) {
+ Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS));
+ }
}
- private void waitUntilConnectedOrTimedout() {
+ private void waitUntilConnectedOrTimedout() throws IOException {
sleep(2000); // 2 seconds
for (int i = 0; i < 60; i++) {
if (mState != VpnState.CONNECTING) {
@@ -187,39 +223,49 @@ abstract class VpnService<E extends VpnProfile> {
synchronized (VpnService.this) {
if (mState == VpnState.CONNECTING) {
- Log.d(TAG, " connecting timed out !!");
onError(new IOException("Connecting timed out"));
}
}
}
- private synchronized void onConnected() {
- Log.d(TAG, "onConnected()");
+ private synchronized void onConnected() throws IOException {
+ if (DBG) Log.d(TAG, "onConnected()");
mDaemonHelper.closeSockets();
- saveVpnDnsProperties();
+ saveOriginalDns();
saveAndSetDomainSuffices();
mState = VpnState.CONNECTED;
+ mStartTime = System.currentTimeMillis();
+
+ // set DNS after saving the states in case the process gets killed
+ // before states are saved
+ saveSelf();
+ setVpnDns();
broadcastConnectivity(VpnState.CONNECTED);
enterConnectivityLoop();
}
+ private void saveSelf() throws IOException {
+ mContext.saveStates();
+ }
+
private synchronized void onFinalCleanUp() {
- Log.d(TAG, "onFinalCleanUp()");
+ if (DBG) Log.d(TAG, "onFinalCleanUp()");
if (mState == VpnState.IDLE) return;
// keep the notification when error occurs
if (!anyError()) mNotification.disableNotification();
- restoreOriginalDnsProperties();
+ restoreOriginalDns();
restoreOriginalDomainSuffices();
mState = VpnState.IDLE;
broadcastConnectivity(VpnState.IDLE);
// stop the service itself
+ mContext.removeStates();
mContext.stopSelf();
}
@@ -227,46 +273,38 @@ abstract class VpnService<E extends VpnProfile> {
return (mError != null);
}
- private void restoreOriginalDnsProperties() {
+ private void restoreOriginalDns() {
// restore only if they are not overridden
- if (mVpnDns1.equals(SystemProperties.get(DNS1))) {
- Log.d(TAG, String.format("restore original dns prop: %s --> %s",
+ String vpnDns1 = SystemProperties.get(VPN_DNS1);
+ if (vpnDns1.equals(SystemProperties.get(DNS1))) {
+ Log.i(TAG, String.format("restore original dns prop: %s --> %s",
SystemProperties.get(DNS1), mOriginalDns1));
- Log.d(TAG, String.format("restore original dns prop: %s --> %s",
+ Log.i(TAG, String.format("restore original dns prop: %s --> %s",
SystemProperties.get(DNS2), mOriginalDns2));
SystemProperties.set(DNS1, mOriginalDns1);
SystemProperties.set(DNS2, mOriginalDns2);
}
}
- private void saveVpnDnsProperties() {
- mOriginalDns1 = mOriginalDns2 = "";
- for (int i = 0; i < 5; i++) {
- mVpnDns1 = SystemProperties.get(VPN_DNS1);
- mVpnDns2 = SystemProperties.get(VPN_DNS2);
- if (mOriginalDns1.equals(mVpnDns1)) {
- Log.d(TAG, "wait for vpn dns to settle in..." + i);
- sleep(200);
- } else {
- mOriginalDns1 = SystemProperties.get(DNS1);
- mOriginalDns2 = SystemProperties.get(DNS2);
- SystemProperties.set(DNS1, mVpnDns1);
- SystemProperties.set(DNS2, mVpnDns2);
- Log.d(TAG, String.format("save original dns prop: %s, %s",
- mOriginalDns1, mOriginalDns2));
- Log.d(TAG, String.format("set vpn dns prop: %s, %s",
- mVpnDns1, mVpnDns2));
- return;
- }
- }
- Log.d(TAG, "saveVpnDnsProperties(): DNS not updated??");
- mOriginalDns1 = mVpnDns1 = SystemProperties.get(DNS1);
- mOriginalDns2 = mVpnDns2 = SystemProperties.get(DNS2);
+ private void saveOriginalDns() {
+ mOriginalDns1 = SystemProperties.get(DNS1);
+ mOriginalDns2 = SystemProperties.get(DNS2);
+ Log.i(TAG, String.format("save original dns prop: %s, %s",
+ mOriginalDns1, mOriginalDns2));
+ }
+
+ private void setVpnDns() {
+ String vpnDns1 = SystemProperties.get(VPN_DNS1);
+ String vpnDns2 = SystemProperties.get(VPN_DNS2);
+ SystemProperties.set(DNS1, vpnDns1);
+ SystemProperties.set(DNS2, vpnDns2);
+ Log.i(TAG, String.format("set vpn dns prop: %s, %s",
+ vpnDns1, vpnDns2));
}
private void saveAndSetDomainSuffices() {
mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES);
- Log.d(TAG, "save original dns search: " + mOriginalDomainSuffices);
+ Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices);
String list = mProfile.getDomainSuffices();
if (!TextUtils.isEmpty(list)) {
SystemProperties.set(DNS_DOMAIN_SUFFICES, list);
@@ -274,7 +312,7 @@ abstract class VpnService<E extends VpnProfile> {
}
private void restoreOriginalDomainSuffices() {
- Log.d(TAG, "restore original dns search --> " + mOriginalDomainSuffices);
+ Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices);
SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices);
}
@@ -298,46 +336,73 @@ abstract class VpnService<E extends VpnProfile> {
}
private void enterConnectivityLoop() {
- mStartTime = System.currentTimeMillis();
-
- Log.d(TAG, " +++++ connectivity monitor running");
+ Log.i(TAG, "VPN connectivity monitor running");
try {
for (;;) {
synchronized (VpnService.this) {
- if (mState != VpnState.CONNECTED) break;
+ if (mState != VpnState.CONNECTED || !checkConnectivity()) {
+ break;
+ }
mNotification.update();
- checkConnectivity();
+ checkDns();
VpnService.this.wait(1000); // 1 second
}
}
} catch (InterruptedException e) {
- Log.e(TAG, "connectivity monitor", e);
+ onError(e);
}
- Log.d(TAG, " ----- connectivity monitor stopped");
+ Log.i(TAG, "VPN connectivity monitor stopped");
}
- private void checkConnectivity() {
- if (mDaemonHelper.anyDaemonStopped() || isLocalIpChanged()) {
- onDisconnect();
+ private void saveLocalIpAndInterface(String serverIp) throws IOException {
+ DatagramSocket s = new DatagramSocket();
+ int port = 80; // arbitrary
+ s.connect(InetAddress.getByName(serverIp), port);
+ InetAddress localIp = s.getLocalAddress();
+ mLocalIp = localIp.getHostAddress();
+ NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp);
+ mLocalIf = (localIf == null) ? null : localIf.getName();
+ if (TextUtils.isEmpty(mLocalIf)) {
+ throw new IOException("Local interface is empty!");
+ }
+ if (DBG) {
+ Log.d(TAG, " Local IP: " + mLocalIp + ", if: " + mLocalIf);
}
}
- private boolean isLocalIpChanged() {
- // TODO
- if (!isDnsIntact()) {
- Log.w(TAG, " local IP changed");
- return true;
- } else {
+ // returns false if vpn connectivity is broken
+ private boolean checkConnectivity() {
+ if (mDaemonHelper.anyDaemonStopped() || isLocalIpChanged()) {
+ onDisconnect();
return false;
+ } else {
+ return true;
}
}
- private boolean isDnsIntact() {
+ private void checkDns() {
String dns1 = SystemProperties.get(DNS1);
- if (!mVpnDns1.equals(dns1)) {
- Log.w(TAG, " dns being overridden by: " + dns1);
- return false;
- } else {
+ String vpnDns1 = SystemProperties.get(VPN_DNS1);
+ if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) {
+ // dhcp expires?
+ setVpnDns();
+ }
+ }
+
+ private boolean isLocalIpChanged() {
+ try {
+ InetAddress localIp = InetAddress.getByName(mLocalIp);
+ NetworkInterface localIf =
+ NetworkInterface.getByInetAddress(localIp);
+ if (localIf == null || !mLocalIf.equals(localIf.getName())) {
+ Log.w(TAG, " local If changed from " + mLocalIf
+ + " to " + localIf);
+ return true;
+ } else {
+ return false;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "isLocalIpChanged()", e);
return true;
}
}
@@ -349,7 +414,7 @@ abstract class VpnService<E extends VpnProfile> {
}
}
- private class DaemonHelper {
+ private class DaemonHelper implements Serializable {
private List<DaemonProxy> mDaemonList =
new ArrayList<DaemonProxy>();
@@ -376,7 +441,7 @@ abstract class VpnService<E extends VpnProfile> {
synchronized boolean anyDaemonStopped() {
for (DaemonProxy s : mDaemonList) {
if (s.isStopped()) {
- Log.w(TAG, " daemon gone: " + s.getName());
+ Log.w(TAG, " VPN daemon gone: " + s.getName());
return true;
}
}
@@ -401,6 +466,14 @@ abstract class VpnService<E extends VpnProfile> {
onError(VpnManager.VPN_ERROR_AUTH);
return true;
+ case CHALLENGE_ERROR_CODE:
+ onError(VpnManager.VPN_ERROR_CHALLENGE);
+ return true;
+
+ case REMOTE_HUNG_UP_ERROR_CODE:
+ onError(VpnManager.VPN_ERROR_REMOTE_HUNG_UP);
+ return true;
+
default:
onError(VpnManager.VPN_ERROR_CONNECTION_FAILED);
return true;
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 513a2c9..4892a7b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -27,23 +27,31 @@ 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.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
/**
* The service class for managing a VPN connection. It implements the
* {@link IVpnService} binder interface.
*/
public class VpnServiceBinder extends Service {
- private final String TAG = VpnServiceBinder.class.getSimpleName();
+ private static final String TAG = VpnServiceBinder.class.getSimpleName();
+ private static final boolean DBG = true;
+
+ private static final String STATES_FILE_PATH = "/data/misc/vpn/.states";
// The actual implementation is delegated to the VpnService class.
private VpnService<? extends VpnProfile> mService;
private final IBinder mBinder = new IVpnService.Stub() {
public boolean connect(VpnProfile p, String username, String password) {
- android.util.Log.d("VpnServiceBinder", "becoming foreground");
- setForeground(true);
return VpnServiceBinder.this.connect(p, username, password);
}
@@ -57,6 +65,13 @@ public class VpnServiceBinder extends Service {
};
@Override
+ public void onCreate() {
+ super.onCreate();
+ checkSavedStates();
+ }
+
+
+ @Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@@ -66,14 +81,30 @@ public class VpnServiceBinder extends Service {
return mBinder;
}
+ void saveStates() throws IOException {
+ if (DBG) Log.d("VpnServiceBinder", " saving states");
+ ObjectOutputStream oos =
+ new ObjectOutputStream(new FileOutputStream(STATES_FILE_PATH));
+ oos.writeObject(mService);
+ oos.close();
+ }
+
+ void removeStates() {
+ try {
+ new File(STATES_FILE_PATH).delete();
+ } catch (Throwable e) {
+ if (DBG) Log.d("VpnServiceBinder", " remove states: " + e);
+ }
+ }
+
private synchronized boolean connect(final VpnProfile p,
final String username, final String password) {
if (mService != null) return false;
+ final VpnService s = mService = createService(p);
new Thread(new Runnable() {
public void run() {
- mService = createService(p);
- mService.onConnect(username, password);
+ s.onConnect(username, password);
}
}).start();
return true;
@@ -81,12 +112,11 @@ public class VpnServiceBinder extends Service {
private synchronized void disconnect() {
if (mService == null) return;
+ final VpnService s = mService;
new Thread(new Runnable() {
public void run() {
- mService.onDisconnect();
- android.util.Log.d("VpnServiceBinder", "becoming background");
- setForeground(false);
+ s.onDisconnect();
}
}).start();
}
@@ -100,6 +130,21 @@ public class VpnServiceBinder extends Service {
}
}
+ private void checkSavedStates() {
+ try {
+ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
+ STATES_FILE_PATH));
+ mService = (VpnService<? extends VpnProfile>) ois.readObject();
+ mService.recover(this);
+ ois.close();
+ } catch (FileNotFoundException e) {
+ // do nothing
+ } catch (Throwable e) {
+ Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
+ removeStates();
+ }
+ }
+
private VpnService<? extends VpnProfile> createService(VpnProfile p) {
switch (p.getType()) {
case L2TP: