summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaksymilian Osowski <maxosowski@google.com>2010-08-26 06:21:58 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-08-26 06:21:58 -0700
commit7f335371dd23580fc748c1fe7b5578df9e75174e (patch)
treec08b3eac5e9680d350d8e0bd594fd6ee3aaaf211
parente9ddcba348ee45fe000d84efaad98484db032926 (diff)
parent56d7e400ece64591685c8a21dbb82a94a7bd8010 (diff)
downloadframeworks_base-7f335371dd23580fc748c1fe7b5578df9e75174e.zip
frameworks_base-7f335371dd23580fc748c1fe7b5578df9e75174e.tar.gz
frameworks_base-7f335371dd23580fc748c1fe7b5578df9e75174e.tar.bz2
Merge "Added forwarding service."
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java87
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java116
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java131
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java73
4 files changed, 407 insertions, 0 deletions
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java
new file mode 100644
index 0000000..d165a1a
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/AdbUtils.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 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.dumprendertree2.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * The utility class that can setup a socket allowing the device to communicate with remote
+ * machines through the machine that the device is connected to via adb.
+ */
+public class AdbUtils {
+ private static final String LOG_TAG = "AdbUtils";
+
+ private static final String ADB_OK = "OKAY";
+ private static final int ADB_PORT = 5037;
+ private static final String ADB_HOST = "127.0.0.1";
+ private static final int ADB_RESPONSE_SIZE = 4;
+
+ /**
+ * Send an ADB command using existing socket connection
+ *
+ * The streams provided must be from a socket connected to adb already
+ *
+ * @param is input stream of the socket connection
+ * @param os output stream of the socket
+ * @param cmd the adb command to send
+ * @return if adb gave a success response
+ * @throws IOException
+ */
+ private static boolean sendAdbCmd(InputStream is, OutputStream os, String cmd)
+ throws IOException {
+ byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+ cmd = String.format("%04X", cmd.length()) + cmd;
+ os.write(cmd.getBytes());
+ int read = is.read(buf);
+ if (read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+ Log.w(LOG_TAG, "adb cmd faild.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get a tcp socket connection to specified IP address and port proxied by adb
+ *
+ * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+ * read from as if it is directly connected to the target
+ *
+ * @param remoteAddress IP address of the host to connect to
+ * @param remotePort port of the host to connect to
+ * @return a valid Socket instance if successful, null otherwise
+ */
+ public static Socket getSocketToRemoteMachine(String remoteAddress, int remotePort) {
+ try {
+ Socket socket = new Socket(ADB_HOST, ADB_PORT);
+ String cmd = "tcp:" + remotePort + ":" + remoteAddress;
+ if (!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ } catch (IOException ioe) {
+ Log.w(LOG_TAG, "error creating adb socket", ioe);
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java
new file mode 100644
index 0000000..6a6cb7f
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ConnectionHandler.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 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.dumprendertree2.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * Worker class for {@link Forwarder}. A ConnectionHandler will be created once the Forwarder
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ */
+public class ConnectionHandler {
+
+ private static final String LOG_TAG = "ConnectionHandler";
+
+ private class SocketPipeThread extends Thread {
+
+ private Socket mInSocket, mOutSocket;
+
+ public SocketPipeThread(Socket inSocket, Socket outSocket) {
+ mInSocket = inSocket;
+ mOutSocket = outSocket;
+ }
+
+ @Override
+ public void run() {
+ InputStream is;
+ OutputStream os;
+ try {
+ synchronized (this) {
+ is = mInSocket.getInputStream();
+ os = mOutSocket.getOutputStream();
+ }
+ } catch (IOException e) {
+ Log.w(LOG_TAG, this.toString(), e);
+ return;
+ }
+
+ byte[] buffer = new byte[4096];
+ int length;
+ while (true) {
+ try {
+ synchronized (this) {
+ if ((length = is.read(buffer)) <= 0) {
+ break;
+ }
+ os.write(buffer, 0, length);
+ }
+ } catch (IOException e) {
+ /** This exception means one of the streams is closed */
+ Log.v(LOG_TAG, this.toString(), e);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SocketPipeThread:\n" + mInSocket + "\n=>\n" + mOutSocket;
+ }
+ }
+
+ private Socket mFromSocket, mToSocket;
+ private SocketPipeThread mFromToPipe, mToFromPipe;
+
+ public ConnectionHandler(Socket fromSocket, Socket toSocket) {
+ mFromSocket = fromSocket;
+ mToSocket = toSocket;
+ mFromToPipe = new SocketPipeThread(mFromSocket, mToSocket);
+ mToFromPipe = new SocketPipeThread(mToSocket, mFromSocket);
+ }
+
+ public void start() {
+ mFromToPipe.start();
+ mToFromPipe.start();
+ }
+
+ public void stop() {
+ shutdown(mFromSocket);
+ shutdown(mToSocket);
+ }
+
+ private void shutdown(Socket socket) {
+ try {
+ synchronized (mFromToPipe) {
+ synchronized (mToFromPipe) {
+ /** This will stop the while loop in the run method */
+ socket.shutdownInput();
+ socket.shutdownOutput();
+ socket.close();
+ }
+ }
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "mFromToPipe=" + mFromToPipe + " mToFromPipe=" + mToFromPipe, e);
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java
new file mode 100644
index 0000000..e5ef6da
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/Forwarder.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 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.dumprendertree2.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A port forwarding server. Listens on localhost on specified port and forwards the tcp
+ * communications to external socket via adb networking proxy.
+ */
+public class Forwarder extends Thread {
+ private static final String LOG_TAG = "Forwarder";
+
+ private int mPort;
+ private String mRemoteMachineIpAddress;
+
+ private Boolean mIsRunning = false;
+ private ServerSocket mServerSocket;
+
+ private Set<ConnectionHandler> mConnectionHandlers = new HashSet<ConnectionHandler>();
+
+ public Forwarder(int port, String remoteMachineIpAddress) {
+ mPort = port;
+ mRemoteMachineIpAddress = remoteMachineIpAddress;
+ }
+
+ @Override
+ public void start() {
+ Log.i(LOG_TAG, "start(): Starting fowarder on port: " + mPort);
+ synchronized (this) {
+ if (mIsRunning) {
+ Log.w(LOG_TAG, "start(): Forwarder on port: " + mPort + " already running! NOOP.");
+ return;
+ }
+ }
+
+ try {
+ mServerSocket = new ServerSocket(mPort);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "mPort=" + mPort, e);
+ return;
+ }
+
+ mIsRunning = true;
+ super.start();
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ synchronized (this) {
+ if (!mIsRunning) {
+ return;
+ }
+
+ /** These sockets will be closed when Forwarder.stop() is called */
+ Socket localSocket;
+ Socket remoteSocket;
+ try {
+ localSocket = mServerSocket.accept();
+ remoteSocket = AdbUtils.getSocketToRemoteMachine(mRemoteMachineIpAddress,
+ mPort);
+ } catch (IOException e) {
+ /** This most likely means that mServerSocket is already closed */
+ Log.w(LOG_TAG + "mPort=" + mPort, e);
+ return;
+ }
+
+ if (remoteSocket == null) {
+ try {
+ localSocket.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "mPort=" + mPort, e);
+ }
+
+ Log.e(LOG_TAG, "run(): mPort= " + mPort + " Failed to start forwarding from " +
+ localSocket);
+ continue;
+ }
+
+ ConnectionHandler forwarder = new ConnectionHandler(localSocket, remoteSocket);
+ mConnectionHandlers.add(forwarder);
+ forwarder.start();
+
+ }
+ }
+ }
+
+ public void finish() {
+ synchronized (this) {
+ if (!mIsRunning) {
+ return;
+ }
+ }
+
+ try {
+ mServerSocket.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "mPort=" + mPort, e);
+ }
+
+ synchronized (this) {
+ mIsRunning = false;
+ }
+
+ for (ConnectionHandler connectionHandler : mConnectionHandlers) {
+ connectionHandler.stop();
+ }
+ mConnectionHandlers.clear();
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java
new file mode 100644
index 0000000..10fee4b
--- /dev/null
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/forwarder/ForwarderManager.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 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.dumprendertree2.forwarder;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A simple class to start and stop Forwarders running on some ports.
+ *
+ * It uses a singleton pattern and is thread safe.
+ */
+public class ForwarderManager {
+ /**
+ * The IP address of the server serving the tests.
+ */
+ private static final String HOST_IP = "127.0.0.1";
+
+ /**
+ * We use these ports because other webkit platforms do. They are set up in
+ * external/webkit/LayoutTests/http/conf/apache2-debian-httpd.conf
+ */
+ public static final int HTTP_PORT = 8080;
+ public static final int HTTPS_PORT = 8443;
+
+ private static ForwarderManager forwarderManager;
+
+ private Set<Forwarder> mServers;
+
+ private ForwarderManager() {
+ mServers = new HashSet<Forwarder>(2);
+ mServers.add(new Forwarder(HTTP_PORT, HOST_IP));
+ mServers.add(new Forwarder(HTTPS_PORT, HOST_IP));
+ }
+
+ public static synchronized ForwarderManager getForwarderManager() {
+ if (forwarderManager == null) {
+ forwarderManager = new ForwarderManager();
+ }
+ return forwarderManager;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+ public synchronized void start() {
+ for (Forwarder server : mServers) {
+ server.start();
+ }
+ }
+
+ public synchronized void stop() {
+ for (Forwarder server : mServers) {
+ server.finish();
+ }
+ }
+} \ No newline at end of file