diff options
author | Hung-ying Tyan <tyanh@google.com> | 2009-09-30 16:57:51 +0800 |
---|---|---|
committer | Hung-ying Tyan <tyanh@google.com> | 2009-10-01 15:18:28 +0800 |
commit | c8217638be7e39161fa31bfe240a64a563690dbf (patch) | |
tree | a6f5e9f6b160d751bc28dfc79156ff1a0f11fd36 /packages/VpnServices/src/com/android/server | |
parent | c868acf442a69429056a574c67a5e0187e2b9536 (diff) | |
download | frameworks_base-c8217638be7e39161fa31bfe240a64a563690dbf.zip frameworks_base-c8217638be7e39161fa31bfe240a64a563690dbf.tar.gz frameworks_base-c8217638be7e39161fa31bfe240a64a563690dbf.tar.bz2 |
Fix stopping all vpn daemons before connect and more.
* move DaemonHelper out from VpnService to VpnDaemons for better
managing native daemons.
* check connectivity and dns less frequently to save battery.
Diffstat (limited to 'packages/VpnServices/src/com/android/server')
7 files changed, 195 insertions, 197 deletions
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java index 7910f4a..50e0de1 100644 --- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java +++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java @@ -31,24 +31,17 @@ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> { protected void connect(String serverIp, String username, String password) throws IOException { L2tpIpsecPskProfile p = getProfile(); + VpnDaemons daemons = getDaemons(); // IPSEC - DaemonProxy ipsec = startDaemon(IPSEC); - ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, p.getPresharedKey()); - ipsec.closeControlSocket(); + daemons.startIpsecForL2tp(serverIp, p.getPresharedKey()) + .closeControlSocket(); sleep(2000); // 2 seconds // L2TP - MtpdHelper.sendCommand(this, L2tpService.L2TP_DAEMON, serverIp, - L2tpService.L2TP_PORT, + daemons.startL2tp(serverIp, (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 9909905..663b0e8 100644 --- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java +++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java @@ -31,9 +31,10 @@ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> { protected void connect(String serverIp, String username, String password) throws IOException { L2tpIpsecProfile p = getProfile(); + VpnDaemons daemons = getDaemons(); + // IPSEC - DaemonProxy ipsec = startDaemon(IPSEC); - ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, + DaemonProxy ipsec = daemons.startIpsecForL2tp(serverIp, Credentials.USER_PRIVATE_KEY + p.getUserCertificate(), Credentials.USER_CERTIFICATE + p.getUserCertificate(), Credentials.CA_CERTIFICATE + p.getCaCertificate()); @@ -42,15 +43,8 @@ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> { sleep(2000); // 2 seconds // L2TP - MtpdHelper.sendCommand(this, L2tpService.L2TP_DAEMON, serverIp, - L2tpService.L2TP_PORT, + daemons.startL2tp(serverIp, (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/L2tpService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java index d658a36..784a366 100644 --- a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java +++ b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java @@ -24,20 +24,12 @@ import java.io.IOException; * The service that manages the L2TP VPN connection. */ class L2tpService extends VpnService<L2tpProfile> { - static final String L2TP_DAEMON = "l2tp"; - static final String L2TP_PORT = "1701"; - @Override protected void connect(String serverIp, String username, String password) throws IOException { L2tpProfile p = getProfile(); - MtpdHelper.sendCommand(this, L2TP_DAEMON, serverIp, L2TP_PORT, + getDaemons().startL2tp(serverIp, (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 deleted file mode 100644 index 9078d9b..0000000 --- a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * A helper class for sending commands to the MTP daemon (mtpd). - */ -class MtpdHelper { - 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(args, serverIp, username, password, encryption); - - DaemonProxy mtpd = vpnService.startDaemon(MTPD); - mtpd.sendCommand(args.toArray(new String[args.size()])); - } - - 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, - "password", password, - "refuse-eap", "nodefaultroute", "usepeerdns", - "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 d903d1b..de12710 100644 --- a/packages/VpnServices/src/com/android/server/vpn/PptpService.java +++ b/packages/VpnServices/src/com/android/server/vpn/PptpService.java @@ -24,19 +24,11 @@ import java.io.IOException; * The service that manages the PPTP VPN connection. */ 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, p.isEncryptionEnabled()); - } - - @Override - protected void stopPreviouslyRunDaemons() { - stopDaemon(MtpdHelper.MTPD); + getDaemons().startPptp(serverIp, username, password, + p.isEncryptionEnabled()); } } diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java b/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java new file mode 100644 index 0000000..499195f --- /dev/null +++ b/packages/VpnServices/src/com/android/server/vpn/VpnDaemons.java @@ -0,0 +1,147 @@ +/* + * 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 android.util.Log; + +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A helper class for managing native VPN daemons. + */ +class VpnDaemons implements Serializable { + static final long serialVersionUID = 1L; + private final String TAG = VpnDaemons.class.getSimpleName(); + + private static final String MTPD = "mtpd"; + private static final String IPSEC = "racoon"; + + private static final String L2TP = "l2tp"; + private static final String L2TP_PORT = "1701"; + + private static final String PPTP = "pptp"; + private static final String PPTP_PORT = "1723"; + + private static final String VPN_LINKNAME = "vpn"; + private static final String PPP_ARGS_SEPARATOR = ""; + + private List<DaemonProxy> mDaemonList = new ArrayList<DaemonProxy>(); + + public DaemonProxy startL2tp(String serverIp, String secret, + String username, String password) throws IOException { + return startMtpd(L2TP, serverIp, L2TP_PORT, secret, username, password, + false); + } + + public DaemonProxy startPptp(String serverIp, String username, + String password, boolean encryption) throws IOException { + return startMtpd(PPTP, serverIp, PPTP_PORT, null, username, password, + encryption); + } + + public DaemonProxy startIpsecForL2tp(String serverIp, String pskKey) + throws IOException { + DaemonProxy ipsec = startDaemon(IPSEC); + ipsec.sendCommand(serverIp, L2TP_PORT, pskKey); + return ipsec; + } + + public DaemonProxy startIpsecForL2tp(String serverIp, String userKeyKey, + String userCertKey, String caCertKey) throws IOException { + DaemonProxy ipsec = startDaemon(IPSEC); + ipsec.sendCommand(serverIp, L2TP_PORT, userKeyKey, userCertKey, + caCertKey); + return ipsec; + } + + public synchronized void stopAll() { + new DaemonProxy(MTPD).stop(); + new DaemonProxy(IPSEC).stop(); + } + + public synchronized void closeSockets() { + for (DaemonProxy s : mDaemonList) s.closeControlSocket(); + } + + public synchronized boolean anyDaemonStopped() { + for (DaemonProxy s : mDaemonList) { + if (s.isStopped()) { + Log.w(TAG, " VPN daemon gone: " + s.getName()); + return true; + } + } + return false; + } + + public synchronized int getSocketError() { + for (DaemonProxy s : mDaemonList) { + int errCode = getResultFromSocket(s); + if (errCode != 0) return errCode; + } + return 0; + } + + private synchronized DaemonProxy startDaemon(String daemonName) + throws IOException { + DaemonProxy daemon = new DaemonProxy(daemonName); + mDaemonList.add(daemon); + daemon.start(); + return daemon; + } + + private int getResultFromSocket(DaemonProxy s) { + try { + return s.getResultFromSocket(); + } catch (IOException e) { + return -1; + } + } + + private DaemonProxy startMtpd(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(args, serverIp, username, password, encryption); + + DaemonProxy mtpd = startDaemon(MTPD); + mtpd.sendCommand(args.toArray(new String[args.size()])); + return mtpd; + } + + 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, + "password", password, + "refuse-eap", "nodefaultroute", "usepeerdns", + "idle", "1800", + "mtu", "1400", + "mru", "1400")); + if (encryption) { + args.add("+mppe"); + } + } +} diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java index 53167f6..63b87b1 100644 --- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java +++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java @@ -30,18 +30,15 @@ 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; /** * The service base class for managing a type of VPN connection. */ abstract class VpnService<E extends VpnProfile> implements Serializable { - protected static final long serialVersionUID = 1L; + static final long serialVersionUID = 1L; private static final boolean DBG = true; private static final int NOTIFICATION_ID = 1; @@ -75,8 +72,8 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { private long mStartTime; // VPN connection start time - // for helping managing multiple daemons - private DaemonHelper mDaemonHelper = new DaemonHelper(); + // for helping managing daemons + private VpnDaemons mDaemons = new VpnDaemons(); // for helping showing, updating notification private transient NotificationHelper mNotification; @@ -87,21 +84,11 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { protected abstract void connect(String serverIp, String username, String password) throws IOException; - protected abstract void stopPreviouslyRunDaemons(); - /** - * Starts a VPN daemon. + * Returns the daemons management class for this service object. */ - protected DaemonProxy startDaemon(String daemonName) - throws IOException { - return mDaemonHelper.startDaemon(daemonName); - } - - /** - * Stops a VPN daemon. - */ - protected void stopDaemon(String daemonName) { - new DaemonProxy(daemonName).stop(); + protected VpnDaemons getDaemons() { + return mDaemons; } /** @@ -141,7 +128,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { try { setState(VpnState.CONNECTING); - stopPreviouslyRunDaemons(); + mDaemons.stopAll(); String serverIp = getIp(getProfile().getServerName()); saveLocalIpAndInterface(serverIp); onBeforeConnect(); @@ -160,7 +147,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { setState(VpnState.DISCONNECTING); mNotification.showDisconnect(); - mDaemonHelper.stopAll(); + mDaemons.stopAll(); } catch (Throwable e) { Log.e(TAG, "onDisconnect()", e); } finally { @@ -206,7 +193,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { onConnected(); return; } else { - int err = mDaemonHelper.getSocketError(); + int err = mDaemons.getSocketError(); if (err != 0) { onError(err); return; @@ -223,7 +210,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { private synchronized void onConnected() throws IOException { if (DBG) Log.d(TAG, "onConnected()"); - mDaemonHelper.closeSockets(); + mDaemons.closeSockets(); saveOriginalDns(); saveAndSetDomainSuffices(); @@ -341,15 +328,20 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { public void run() { Log.i(TAG, "VPN connectivity monitor running"); try { - for (;;) { + for (int i = 10; ; i--) { + long now = System.currentTimeMillis(); + + boolean heavyCheck = i == 0; synchronized (VpnService.this) { - if ((mState != VpnState.CONNECTED) - || !checkConnectivity()) { - break; + if (mState != VpnState.CONNECTED) break; + mNotification.update(now); + + if (heavyCheck) { + i = 10; + if (checkConnectivity()) checkDns(); } - mNotification.update(); - checkDns(); - VpnService.this.wait(1000); // 1 second + long t = 1000L - System.currentTimeMillis() + now; + if (t > 100L) VpnService.this.wait(t); } } } catch (InterruptedException e) { @@ -378,7 +370,7 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { // returns false if vpn connectivity is broken private boolean checkConnectivity() { - if (mDaemonHelper.anyDaemonStopped() || isLocalIpChanged()) { + if (mDaemons.anyDaemonStopped() || isLocalIpChanged()) { onError(new IOException("Connectivity lost")); return false; } else { @@ -421,60 +413,17 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { } private class DaemonHelper implements Serializable { - private List<DaemonProxy> mDaemonList = - new ArrayList<DaemonProxy>(); - - synchronized DaemonProxy startDaemon(String daemonName) - throws IOException { - DaemonProxy daemon = new DaemonProxy(daemonName); - mDaemonList.add(daemon); - daemon.start(); - return daemon; - } - - synchronized void stopAll() { - for (DaemonProxy s : mDaemonList) s.stop(); - } - - synchronized void closeSockets() { - for (DaemonProxy s : mDaemonList) s.closeControlSocket(); - } - - synchronized boolean anyDaemonStopped() { - for (DaemonProxy s : mDaemonList) { - if (s.isStopped()) { - Log.w(TAG, " VPN daemon gone: " + s.getName()); - return true; - } - } - return false; - } - - private int getResultFromSocket(DaemonProxy s) { - try { - return s.getResultFromSocket(); - } catch (IOException e) { - return -1; - } - } - - synchronized int getSocketError() { - for (DaemonProxy s : mDaemonList) { - int errCode = getResultFromSocket(s); - if (errCode != 0) return errCode; - } - return 0; - } } // Helper class for showing, updating notification. private class NotificationHelper { - void update() { + void update(long now) { String title = getNotificationTitle(true); Notification n = new Notification(R.drawable.vpn_connected, title, mStartTime); n.setLatestEventInfo(mContext, title, - getNotificationMessage(true), prepareNotificationIntent()); + getConnectedNotificationMessage(now), + prepareNotificationIntent()); n.flags |= Notification.FLAG_NO_CLEAR; n.flags |= Notification.FLAG_ONGOING_EVENT; enableNotification(n); @@ -485,7 +434,8 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { Notification n = new Notification(R.drawable.vpn_disconnected, title, System.currentTimeMillis()); n.setLatestEventInfo(mContext, title, - getNotificationMessage(false), prepareNotificationIntent()); + getDisconnectedNotificationMessage(), + prepareNotificationIntent()); n.flags |= Notification.FLAG_AUTO_CANCEL; disableNotification(); enableNotification(n); @@ -515,8 +465,8 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { return String.format(formatString, mProfile.getName()); } - private String getFormattedTime(long duration) { - long hours = duration / 3600; + private String getFormattedTime(int duration) { + int hours = duration / 3600; StringBuilder sb = new StringBuilder(); if (hours > 0) sb.append(hours).append(':'); sb.append(String.format("%02d:%02d", (duration % 3600 / 60), @@ -524,14 +474,13 @@ abstract class VpnService<E extends VpnProfile> implements Serializable { return sb.toString(); } - private String getNotificationMessage(boolean connected) { - if (connected) { - long time = (System.currentTimeMillis() - mStartTime) / 1000; - return getFormattedTime(time); - } else { - return mContext.getString( - R.string.vpn_notification_hint_disconnected); - } + private String getConnectedNotificationMessage(long now) { + return getFormattedTime((int) (now - mStartTime) / 1000); + } + + private String getDisconnectedNotificationMessage() { + return mContext.getString( + R.string.vpn_notification_hint_disconnected); } } } |