diff options
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.java | 213 |
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); + } +} |