aboutsummaryrefslogtreecommitdiff
path: root/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java
diff options
context:
space:
mode:
Diffstat (limited to 'apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java')
-rw-r--r--apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java213
1 files changed, 213 insertions, 0 deletions
diff --git a/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java b/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java
new file mode 100644
index 000000000..08e6b2813
--- /dev/null
+++ b/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Socket.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 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.tools.sdkcontroller.lib;
+
+import android.net.LocalSocket;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
+import java.nio.channels.ClosedChannelException;
+
+/**
+ * Encapsulates a connection with the emulator over a UNIX-domain socket.
+ */
+public class Socket {
+ /** UNIX-domain socket connected with the emulator. */
+ private LocalSocket mSocket = null;
+ /** Channel name for the connection established via this socket. */
+ private String mChannelName;
+ /** Endianness of data transferred in this connection. */
+ private ByteOrder mEndian;
+
+ /** Tag for message logging. */
+ private static final String TAG = "SdkControllerSocket";
+ /** Controls debug log. */
+ private static boolean DEBUG = false;
+
+ /**
+ * Constructs Socket instance.
+ *
+ * @param socket Socket connection with the emulator.
+ * @param name Channel port name for this connection.
+ * @param endian Endianness of data transferred in this connection.
+ */
+ public Socket(LocalSocket socket, String name, ByteOrder endian) {
+ mSocket = socket;
+ mChannelName = name;
+ mEndian = endian;
+ if (DEBUG) Log.d(TAG, "Socket is constructed for " + mChannelName);
+ }
+
+ /**
+ * Gets connection status of this socket.
+ *
+ * @return true if socket is connected, or false if socket is not connected.
+ */
+ public boolean isConnected() {
+ return mSocket != null;
+ }
+
+ /**
+ * Gets channel name for this socket.
+ *
+ * @return Channel name for this socket.
+ */
+ public String getChannelName() {
+ return mChannelName;
+ }
+
+ /**
+ * Gets endianness of data transferred via this socket.
+ *
+ * @return Endianness of data transferred via this socket.
+ */
+ public ByteOrder getEndian() {
+ return mEndian;
+ }
+
+ /**
+ * Sends data to the socket.
+ *
+ * @param data Data to send. Data size is defined by the length of the
+ * array.
+ * @throws IOException
+ */
+ public void send(byte[] data) throws IOException {
+ // Use local copy of the socket, ensuring it's not going to NULL while
+ // we're working with it. If it gets closed, while we're in the middle
+ // of data transfer - it's OK, since it will produce an exception, and
+ // the caller will gracefully handle it.
+ //
+ // Same technique is used everywhere in this class where mSocket member
+ // is touched.
+ LocalSocket socket = mSocket;
+ if (socket == null) {
+ Logw("'send' request on closed Socket " + mChannelName);
+ throw new ClosedChannelException();
+ }
+ socket.getOutputStream().write(data);
+ }
+
+ /**
+ * Sends data to the socket.
+ *
+ * @param data Data to send.
+ * @param offset The start position in data from where to get bytes.
+ * @param len The number of bytes from data to write to this socket.
+ * @throws IOException
+ */
+ public void send(byte[] data, int offset, int len) throws IOException {
+ LocalSocket socket = mSocket;
+ if (socket == null) {
+ Logw("'send' request on closed Socket " + mChannelName);
+ throw new ClosedChannelException();
+ }
+ socket.getOutputStream().write(data, offset, len);
+ }
+
+ /**
+ * Receives data from the socket.
+ *
+ * @param socket Socket from where to receive data.
+ * @param data Array where to save received data.
+ * @param len Number of bytes to receive.
+ * @throws IOException
+ */
+ public static void receive(LocalSocket socket, byte[] data, int len) throws IOException {
+ final InputStream is = socket.getInputStream();
+ int received = 0;
+ while (received != len) {
+ final int chunk = is.read(data, received, len - received);
+ if (chunk < 0) {
+ throw new IOException(
+ "I/O failure while receiving SDK controller data from socket.");
+ }
+ received += chunk;
+ }
+ }
+
+ /**
+ * Receives data from the socket.
+ *
+ * @param data Array where to save received data.
+ * @param len Number of bytes to receive.
+ * @throws IOException
+ */
+ public void receive(byte[] data, int len) throws IOException {
+ LocalSocket socket = mSocket;
+ if (socket == null) {
+ Logw("'receive' request on closed Socket " + mChannelName);
+ throw new ClosedChannelException();
+ }
+ receive(socket, data, len);
+ }
+
+ /**
+ * Receives data from the socket.
+ *
+ * @param data Array where to save received data. Data size is defined by
+ * the size of the array.
+ * @throws IOException
+ */
+ public void receive(byte[] data) throws IOException {
+ receive(data, data.length);
+ }
+
+ /**
+ * Closes the socket.
+ *
+ * @return true if socket has been closed in this call, or false if it had
+ * been already closed when this method has been called.
+ */
+ public boolean close() {
+ // This is the only place in this class where we will null the socket
+ // object. Since this method can be called concurrently from different
+ // threads, lets do this under the lock.
+ LocalSocket socket;
+ synchronized (this) {
+ socket = mSocket;
+ mSocket = null;
+ }
+ if (socket != null) {
+ try {
+ // Force all I/O to stop before closing the socket.
+ socket.shutdownInput();
+ socket.shutdownOutput();
+ socket.close();
+ if (DEBUG) Log.d(TAG, "Socket is closed for " + mChannelName);
+ return true;
+ } catch (IOException e) {
+ Loge("Exception " + e + " while closing Socket for " + mChannelName);
+ }
+ }
+ return false;
+ }
+
+ /***************************************************************************
+ * Logging wrappers
+ **************************************************************************/
+
+ private void Loge(String log) {
+ Log.e(TAG, log);
+ }
+
+ private void Logw(String log) {
+ Log.w(TAG, log);
+ }
+}