Loading packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java→packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java +199 −0 Original line number Diff line number Diff line Loading @@ -27,18 +27,13 @@ import java.io.InputStream; import java.io.OutputStream; /** * Proxy to start, stop and interact with an Android service defined in init.rc. * The android service is expected to accept connection through Unix domain * socket. When the proxy successfully starts the service, it will establish a * socket connection with the service. The socket serves two purposes: (1) send * commands to the service; (2) for the proxy to know whether the service is * alive. * * After the service receives commands from the proxy, it should return either * 0 if the service will close the socket (and the proxy will re-establish * another connection immediately after), or 1 if the socket is remained alive. * Proxy to start, stop and interact with a VPN daemon. * The daemon is expected to accept connection through Unix domain socket. * When the proxy successfully starts the daemon, it will establish a socket * connection with the daemon, to both send commands to the daemon and receive * response and connecting error code from the daemon. */ public class AndroidServiceProxy extends ProcessProxy { class DaemonProxy { private static final int WAITING_TIME = 15; // sec private static final String SVC_STATE_CMD_PREFIX = "init.svc."; Loading @@ -49,65 +44,27 @@ 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; private boolean mControlSocketInUse; private Integer mSocketResult = null; private String mName; private LocalSocket mControlSocket; private String mTag; /** * Creates a proxy with the service name. * @param serviceName the service name * Creates a proxy of the specified daemon. * @param daemonName name of the daemon */ public AndroidServiceProxy(String serviceName) { mServiceName = serviceName; mSocketName = serviceName; mTag = "SProxy_" + serviceName; DaemonProxy(String daemonName) { mName = daemonName; mTag = "SProxy_" + daemonName; } @Override public String getName() { return "Service " + mServiceName; } @Override public synchronized void stop() { if (isRunning()) { try { setResultAndCloseControlSocket(STOP_SERVICE); } catch (IOException e) { // should not occur throw new RuntimeException(e); } } Log.d(mTag, "----- Stop: " + mServiceName); SystemProperties.set(SVC_STOP_CMD, mServiceName); String getName() { return mName; } /** * Sends a command with arguments to the service through the control socket. */ public synchronized void sendCommand(String ...args) throws IOException { OutputStream out = getControlSocketOutput(); for (String arg : args) outputString(out, arg); out.write(END_OF_ARGUMENTS); out.flush(); checkSocketResult(); } /** * {@inheritDoc} * The method returns when the service exits. */ @Override protected void performTask() throws IOException { String svc = mServiceName; Log.d(mTag, "----- Stop the daemon just in case: " + mServiceName); SystemProperties.set(SVC_STOP_CMD, mServiceName); 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"); Loading @@ -116,53 +73,70 @@ public class AndroidServiceProxy extends ProcessProxy { Log.d(mTag, "+++++ Start: " + svc); SystemProperties.set(SVC_START_CMD, svc); boolean success = blockUntil(SVC_STATE_RUNNING, WAITING_TIME); if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) { throw new IOException("cannot start service: " + svc); } else { mControlSocket = createServiceSocket(); } } if (success) { Log.d(mTag, "----- Running: " + svc + ", create keepalive socket"); LocalSocket s = mKeepaliveSocket = createServiceSocket(); setState(ProcessState.RUNNING); void sendCommand(String ...args) throws IOException { OutputStream out = getControlSocketOutput(); for (String arg : args) outputString(out, arg); out.write(END_OF_ARGUMENTS); out.flush(); if (s == null) { // no socket connection, stop hosting the service stop(); return; int result = getResultFromSocket(true); if (result != args.length) { throw new IOException("socket error, result from service: " + result); } try { for (;;) { InputStream in = s.getInputStream(); int data = in.read(); if (data >= 0) { Log.d(mTag, "got data from control socket: " + data); setSocketResult(data); } else { // service is gone if (mControlSocketInUse) setSocketResult(-1); break; } // returns 0 if nothing is in the receive buffer int getResultFromSocket() throws IOException { return getResultFromSocket(false); } Log.d(mTag, "control connection closed"); void closeControlSocket() { if (mControlSocket == null) return; try { mControlSocket.close(); } catch (IOException e) { if (e instanceof VpnConnectingError) { throw e; } else { Log.d(mTag, "control socket broken: " + e.getMessage()); Log.e(mTag, "close control socket", e); } finally { mControlSocket = null; } } // Wait 5 seconds for the service to exit success = blockUntil(SVC_STATE_STOPPED, 5); void stop() { String svc = mName; Log.d(mTag, "----- Stop: " + svc); SystemProperties.set(SVC_STOP_CMD, svc); boolean success = blockUntil(SVC_STATE_STOPPED, 5); Log.d(mTag, "stopping " + svc + ", success? " + success); } else { setState(ProcessState.STOPPED); throw new IOException("cannot start service: " + svc); } boolean isStopped() { String cmd = SVC_STATE_CMD_PREFIX + mName; return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd)); } private int getResultFromSocket(boolean blocking) throws IOException { LocalSocket s = mControlSocket; if (s == null) return 0; InputStream in = s.getInputStream(); if (!blocking && in.available() == 0) return 0; int data = in.read(); Log.d(mTag, "got data from control socket: " + data); return data; } private LocalSocket createServiceSocket() throws IOException { LocalSocket s = new LocalSocket(); LocalSocketAddress a = new LocalSocketAddress(mSocketName, LocalSocketAddress a = new LocalSocketAddress(mName, LocalSocketAddress.Namespace.RESERVED); // try a few times in case the service has not listen()ed Loading @@ -181,69 +155,25 @@ public class AndroidServiceProxy extends ProcessProxy { } private OutputStream getControlSocketOutput() throws IOException { if (mKeepaliveSocket != null) { mControlSocketInUse = true; mSocketResult = null; return mKeepaliveSocket.getOutputStream(); if (mControlSocket != null) { return mControlSocket.getOutputStream(); } else { throw new IOException("no control socket available"); } } private void checkSocketResult() throws IOException { try { // will be notified when the result comes back from service if (mSocketResult == null) wait(); } catch (InterruptedException e) { Log.d(mTag, "checkSocketResult(): " + e); } finally { mControlSocketInUse = false; if ((mSocketResult == null) || (mSocketResult < 0)) { throw new IOException("socket error, result from service: " + mSocketResult); } } } 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) throws VpnConnectingError { setSocketResult(result); try { mKeepaliveSocket.shutdownInput(); mKeepaliveSocket.shutdownOutput(); mKeepaliveSocket.close(); } catch (IOException e) { Log.e(mTag, "close keepalive socket", e); } finally { mKeepaliveSocket = null; } } /** * Waits for the process to be in the expected state. The method returns * false if after the specified duration (in seconds), the process is still * not in the expected state. */ private boolean blockUntil(String expectedState, int waitTime) { String cmd = SVC_STATE_CMD_PREFIX + mServiceName; String cmd = SVC_STATE_CMD_PREFIX + mName; int sleepTime = 200; // ms int n = waitTime * 1000 / sleepTime; for (int i = 0; i < n; i++) { if (expectedState.equals(SystemProperties.get(cmd))) { Log.d(mTag, mServiceName + " is " + expectedState + " after " Log.d(mTag, mName + " is " + expectedState + " after " + (i * sleepTime) + " msec"); break; } Loading @@ -258,4 +188,12 @@ public class AndroidServiceProxy extends ProcessProxy { out.write(bytes); out.flush(); } private void sleep(int msec) { try { Thread.currentThread().sleep(msec); } catch (InterruptedException e) { throw new RuntimeException(e); } } } packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java +4 −4 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import java.io.IOException; * connection. */ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> { private static final String IPSEC_DAEMON = "racoon"; private static final String IPSEC = "racoon"; @Override protected void connect(String serverIp, String username, String password) Loading @@ -33,9 +33,9 @@ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> { L2tpIpsecPskProfile p = getProfile(); // IPSEC AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON); ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT, p.getPresharedKey()); DaemonProxy ipsec = startDaemon(IPSEC); ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, p.getPresharedKey()); ipsec.closeControlSocket(); sleep(2000); // 2 seconds Loading packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java +4 −3 Original line number Diff line number Diff line Loading @@ -25,15 +25,16 @@ import java.io.IOException; * The service that manages the certificate based L2TP-over-IPSec VPN connection. */ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> { private static final String IPSEC_DAEMON = "racoon"; private static final String IPSEC = "racoon"; @Override protected void connect(String serverIp, String username, String password) throws IOException { // IPSEC AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON); ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT, DaemonProxy ipsec = startDaemon(IPSEC); ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, getUserkeyPath(), getUserCertPath(), getCaCertPath()); ipsec.closeControlSocket(); sleep(2000); // 2 seconds Loading packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ import java.util.Arrays; * A helper class for sending commands to the MTP daemon (mtpd). */ class MtpdHelper { private static final String MTPD_SERVICE = "mtpd"; private static final String MTPD = "mtpd"; private static final String VPN_LINKNAME = "vpn"; private static final String PPP_ARGS_SEPARATOR = ""; Loading @@ -37,7 +37,7 @@ class MtpdHelper { args.add(PPP_ARGS_SEPARATOR); addPppArguments(vpnService, args, serverIp, username, password); AndroidServiceProxy mtpd = vpnService.startService(MTPD_SERVICE); DaemonProxy mtpd = vpnService.startDaemon(MTPD); mtpd.sendCommand(args.toArray(new String[args.size()])); } Loading packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.javadeleted 100644 → 0 +0 −85 Original line number Diff line number Diff line /* * 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.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; /** * Proxy to perform a command with arguments. */ public class NormalProcessProxy extends ProcessProxy { private Process mProcess; private String[] mArgs; private String mTag; /** * Creates a proxy with the arguments. * @param args the argument list with the first one being the command */ public NormalProcessProxy(String ...args) { if ((args == null) || (args.length == 0)) { throw new IllegalArgumentException(); } mArgs = args; mTag = "PProxy_" + getName(); } @Override public String getName() { return mArgs[0]; } @Override public synchronized void stop() { if (isStopped()) return; getHostThread().interrupt(); // TODO: not sure how to reliably kill a process mProcess.destroy(); setState(ProcessState.STOPPING); } @Override protected void performTask() throws IOException, InterruptedException { String[] args = mArgs; Log.d(mTag, "+++++ Execute: " + getEntireCommand()); ProcessBuilder pb = new ProcessBuilder(args); setState(ProcessState.RUNNING); Process p = mProcess = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader( p.getInputStream())); while (true) { String line = reader.readLine(); if ((line == null) || isStopping()) break; Log.d(mTag, line); } Log.d(mTag, "----- p.waitFor(): " + getName()); p.waitFor(); Log.d(mTag, "----- Done: " + getName()); } private CharSequence getEntireCommand() { String[] args = mArgs; StringBuilder sb = new StringBuilder(args[0]); for (int i = 1; i < args.length; i++) sb.append(' ').append(args[i]); return sb; } } Loading
packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java→packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java +199 −0 Original line number Diff line number Diff line Loading @@ -27,18 +27,13 @@ import java.io.InputStream; import java.io.OutputStream; /** * Proxy to start, stop and interact with an Android service defined in init.rc. * The android service is expected to accept connection through Unix domain * socket. When the proxy successfully starts the service, it will establish a * socket connection with the service. The socket serves two purposes: (1) send * commands to the service; (2) for the proxy to know whether the service is * alive. * * After the service receives commands from the proxy, it should return either * 0 if the service will close the socket (and the proxy will re-establish * another connection immediately after), or 1 if the socket is remained alive. * Proxy to start, stop and interact with a VPN daemon. * The daemon is expected to accept connection through Unix domain socket. * When the proxy successfully starts the daemon, it will establish a socket * connection with the daemon, to both send commands to the daemon and receive * response and connecting error code from the daemon. */ public class AndroidServiceProxy extends ProcessProxy { class DaemonProxy { private static final int WAITING_TIME = 15; // sec private static final String SVC_STATE_CMD_PREFIX = "init.svc."; Loading @@ -49,65 +44,27 @@ 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; private boolean mControlSocketInUse; private Integer mSocketResult = null; private String mName; private LocalSocket mControlSocket; private String mTag; /** * Creates a proxy with the service name. * @param serviceName the service name * Creates a proxy of the specified daemon. * @param daemonName name of the daemon */ public AndroidServiceProxy(String serviceName) { mServiceName = serviceName; mSocketName = serviceName; mTag = "SProxy_" + serviceName; DaemonProxy(String daemonName) { mName = daemonName; mTag = "SProxy_" + daemonName; } @Override public String getName() { return "Service " + mServiceName; } @Override public synchronized void stop() { if (isRunning()) { try { setResultAndCloseControlSocket(STOP_SERVICE); } catch (IOException e) { // should not occur throw new RuntimeException(e); } } Log.d(mTag, "----- Stop: " + mServiceName); SystemProperties.set(SVC_STOP_CMD, mServiceName); String getName() { return mName; } /** * Sends a command with arguments to the service through the control socket. */ public synchronized void sendCommand(String ...args) throws IOException { OutputStream out = getControlSocketOutput(); for (String arg : args) outputString(out, arg); out.write(END_OF_ARGUMENTS); out.flush(); checkSocketResult(); } /** * {@inheritDoc} * The method returns when the service exits. */ @Override protected void performTask() throws IOException { String svc = mServiceName; Log.d(mTag, "----- Stop the daemon just in case: " + mServiceName); SystemProperties.set(SVC_STOP_CMD, mServiceName); 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"); Loading @@ -116,53 +73,70 @@ public class AndroidServiceProxy extends ProcessProxy { Log.d(mTag, "+++++ Start: " + svc); SystemProperties.set(SVC_START_CMD, svc); boolean success = blockUntil(SVC_STATE_RUNNING, WAITING_TIME); if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) { throw new IOException("cannot start service: " + svc); } else { mControlSocket = createServiceSocket(); } } if (success) { Log.d(mTag, "----- Running: " + svc + ", create keepalive socket"); LocalSocket s = mKeepaliveSocket = createServiceSocket(); setState(ProcessState.RUNNING); void sendCommand(String ...args) throws IOException { OutputStream out = getControlSocketOutput(); for (String arg : args) outputString(out, arg); out.write(END_OF_ARGUMENTS); out.flush(); if (s == null) { // no socket connection, stop hosting the service stop(); return; int result = getResultFromSocket(true); if (result != args.length) { throw new IOException("socket error, result from service: " + result); } try { for (;;) { InputStream in = s.getInputStream(); int data = in.read(); if (data >= 0) { Log.d(mTag, "got data from control socket: " + data); setSocketResult(data); } else { // service is gone if (mControlSocketInUse) setSocketResult(-1); break; } // returns 0 if nothing is in the receive buffer int getResultFromSocket() throws IOException { return getResultFromSocket(false); } Log.d(mTag, "control connection closed"); void closeControlSocket() { if (mControlSocket == null) return; try { mControlSocket.close(); } catch (IOException e) { if (e instanceof VpnConnectingError) { throw e; } else { Log.d(mTag, "control socket broken: " + e.getMessage()); Log.e(mTag, "close control socket", e); } finally { mControlSocket = null; } } // Wait 5 seconds for the service to exit success = blockUntil(SVC_STATE_STOPPED, 5); void stop() { String svc = mName; Log.d(mTag, "----- Stop: " + svc); SystemProperties.set(SVC_STOP_CMD, svc); boolean success = blockUntil(SVC_STATE_STOPPED, 5); Log.d(mTag, "stopping " + svc + ", success? " + success); } else { setState(ProcessState.STOPPED); throw new IOException("cannot start service: " + svc); } boolean isStopped() { String cmd = SVC_STATE_CMD_PREFIX + mName; return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd)); } private int getResultFromSocket(boolean blocking) throws IOException { LocalSocket s = mControlSocket; if (s == null) return 0; InputStream in = s.getInputStream(); if (!blocking && in.available() == 0) return 0; int data = in.read(); Log.d(mTag, "got data from control socket: " + data); return data; } private LocalSocket createServiceSocket() throws IOException { LocalSocket s = new LocalSocket(); LocalSocketAddress a = new LocalSocketAddress(mSocketName, LocalSocketAddress a = new LocalSocketAddress(mName, LocalSocketAddress.Namespace.RESERVED); // try a few times in case the service has not listen()ed Loading @@ -181,69 +155,25 @@ public class AndroidServiceProxy extends ProcessProxy { } private OutputStream getControlSocketOutput() throws IOException { if (mKeepaliveSocket != null) { mControlSocketInUse = true; mSocketResult = null; return mKeepaliveSocket.getOutputStream(); if (mControlSocket != null) { return mControlSocket.getOutputStream(); } else { throw new IOException("no control socket available"); } } private void checkSocketResult() throws IOException { try { // will be notified when the result comes back from service if (mSocketResult == null) wait(); } catch (InterruptedException e) { Log.d(mTag, "checkSocketResult(): " + e); } finally { mControlSocketInUse = false; if ((mSocketResult == null) || (mSocketResult < 0)) { throw new IOException("socket error, result from service: " + mSocketResult); } } } 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) throws VpnConnectingError { setSocketResult(result); try { mKeepaliveSocket.shutdownInput(); mKeepaliveSocket.shutdownOutput(); mKeepaliveSocket.close(); } catch (IOException e) { Log.e(mTag, "close keepalive socket", e); } finally { mKeepaliveSocket = null; } } /** * Waits for the process to be in the expected state. The method returns * false if after the specified duration (in seconds), the process is still * not in the expected state. */ private boolean blockUntil(String expectedState, int waitTime) { String cmd = SVC_STATE_CMD_PREFIX + mServiceName; String cmd = SVC_STATE_CMD_PREFIX + mName; int sleepTime = 200; // ms int n = waitTime * 1000 / sleepTime; for (int i = 0; i < n; i++) { if (expectedState.equals(SystemProperties.get(cmd))) { Log.d(mTag, mServiceName + " is " + expectedState + " after " Log.d(mTag, mName + " is " + expectedState + " after " + (i * sleepTime) + " msec"); break; } Loading @@ -258,4 +188,12 @@ public class AndroidServiceProxy extends ProcessProxy { out.write(bytes); out.flush(); } private void sleep(int msec) { try { Thread.currentThread().sleep(msec); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java +4 −4 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import java.io.IOException; * connection. */ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> { private static final String IPSEC_DAEMON = "racoon"; private static final String IPSEC = "racoon"; @Override protected void connect(String serverIp, String username, String password) Loading @@ -33,9 +33,9 @@ class L2tpIpsecPskService extends VpnService<L2tpIpsecPskProfile> { L2tpIpsecPskProfile p = getProfile(); // IPSEC AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON); ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT, p.getPresharedKey()); DaemonProxy ipsec = startDaemon(IPSEC); ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, p.getPresharedKey()); ipsec.closeControlSocket(); sleep(2000); // 2 seconds Loading
packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java +4 −3 Original line number Diff line number Diff line Loading @@ -25,15 +25,16 @@ import java.io.IOException; * The service that manages the certificate based L2TP-over-IPSec VPN connection. */ class L2tpIpsecService extends VpnService<L2tpIpsecProfile> { private static final String IPSEC_DAEMON = "racoon"; private static final String IPSEC = "racoon"; @Override protected void connect(String serverIp, String username, String password) throws IOException { // IPSEC AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON); ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT, DaemonProxy ipsec = startDaemon(IPSEC); ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, getUserkeyPath(), getUserCertPath(), getCaCertPath()); ipsec.closeControlSocket(); sleep(2000); // 2 seconds Loading
packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ import java.util.Arrays; * A helper class for sending commands to the MTP daemon (mtpd). */ class MtpdHelper { private static final String MTPD_SERVICE = "mtpd"; private static final String MTPD = "mtpd"; private static final String VPN_LINKNAME = "vpn"; private static final String PPP_ARGS_SEPARATOR = ""; Loading @@ -37,7 +37,7 @@ class MtpdHelper { args.add(PPP_ARGS_SEPARATOR); addPppArguments(vpnService, args, serverIp, username, password); AndroidServiceProxy mtpd = vpnService.startService(MTPD_SERVICE); DaemonProxy mtpd = vpnService.startDaemon(MTPD); mtpd.sendCommand(args.toArray(new String[args.size()])); } Loading
packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.javadeleted 100644 → 0 +0 −85 Original line number Diff line number Diff line /* * 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.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; /** * Proxy to perform a command with arguments. */ public class NormalProcessProxy extends ProcessProxy { private Process mProcess; private String[] mArgs; private String mTag; /** * Creates a proxy with the arguments. * @param args the argument list with the first one being the command */ public NormalProcessProxy(String ...args) { if ((args == null) || (args.length == 0)) { throw new IllegalArgumentException(); } mArgs = args; mTag = "PProxy_" + getName(); } @Override public String getName() { return mArgs[0]; } @Override public synchronized void stop() { if (isStopped()) return; getHostThread().interrupt(); // TODO: not sure how to reliably kill a process mProcess.destroy(); setState(ProcessState.STOPPING); } @Override protected void performTask() throws IOException, InterruptedException { String[] args = mArgs; Log.d(mTag, "+++++ Execute: " + getEntireCommand()); ProcessBuilder pb = new ProcessBuilder(args); setState(ProcessState.RUNNING); Process p = mProcess = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader( p.getInputStream())); while (true) { String line = reader.readLine(); if ((line == null) || isStopping()) break; Log.d(mTag, line); } Log.d(mTag, "----- p.waitFor(): " + getName()); p.waitFor(); Log.d(mTag, "----- Done: " + getName()); } private CharSequence getEntireCommand() { String[] args = mArgs; StringBuilder sb = new StringBuilder(args[0]); for (int i = 1; i < args.length; i++) sb.append(' ').append(args[i]); return sb; } }