Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.tools.sdkcontroller.lib;
     18 
     19 import android.net.LocalSocket;
     20 import android.util.Log;
     21 
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.nio.ByteOrder;
     25 import java.nio.channels.ClosedChannelException;
     26 
     27 /**
     28  * Encapsulates a connection with the emulator over a UNIX-domain socket.
     29  */
     30 public class Socket {
     31     /** UNIX-domain socket connected with the emulator. */
     32     private LocalSocket mSocket = null;
     33     /** Channel name for the connection established via this socket. */
     34     private String mChannelName;
     35     /** Endianness of data transferred in this connection. */
     36     private ByteOrder mEndian;
     37 
     38     /** Tag for message logging. */
     39     private static final String TAG = "SdkControllerSocket";
     40     /** Controls debug log. */
     41     private static boolean DEBUG = false;
     42 
     43     /**
     44      * Constructs Socket instance.
     45      *
     46      * @param socket Socket connection with the emulator.
     47      * @param name Channel port name for this connection.
     48      * @param endian Endianness of data transferred in this connection.
     49      */
     50     public Socket(LocalSocket socket, String name, ByteOrder endian) {
     51         mSocket = socket;
     52         mChannelName = name;
     53         mEndian = endian;
     54         if (DEBUG) Log.d(TAG, "Socket is constructed for " + mChannelName);
     55     }
     56 
     57     /**
     58      * Gets connection status of this socket.
     59      *
     60      * @return true if socket is connected, or false if socket is not connected.
     61      */
     62     public boolean isConnected() {
     63         return mSocket != null;
     64     }
     65 
     66     /**
     67      * Gets channel name for this socket.
     68      *
     69      * @return Channel name for this socket.
     70      */
     71     public String getChannelName() {
     72         return mChannelName;
     73     }
     74 
     75     /**
     76      * Gets endianness of data transferred via this socket.
     77      *
     78      * @return Endianness of data transferred via this socket.
     79      */
     80     public ByteOrder getEndian() {
     81         return mEndian;
     82     }
     83 
     84     /**
     85      * Sends data to the socket.
     86      *
     87      * @param data Data to send. Data size is defined by the length of the
     88      *            array.
     89      * @throws IOException
     90      */
     91     public void send(byte[] data) throws IOException {
     92         // Use local copy of the socket, ensuring it's not going to NULL while
     93         // we're working with it. If it gets closed, while we're in the middle
     94         // of data transfer - it's OK, since it will produce an exception, and
     95         // the caller will gracefully handle it.
     96         //
     97         // Same technique is used everywhere in this class where mSocket member
     98         // is touched.
     99         LocalSocket socket = mSocket;
    100         if (socket == null) {
    101             Logw("'send' request on closed Socket " + mChannelName);
    102             throw new ClosedChannelException();
    103         }
    104         socket.getOutputStream().write(data);
    105     }
    106 
    107     /**
    108      * Sends data to the socket.
    109      *
    110      * @param data Data to send.
    111      * @param offset The start position in data from where to get bytes.
    112      * @param len The number of bytes from data to write to this socket.
    113      * @throws IOException
    114      */
    115     public void send(byte[] data, int offset, int len) throws IOException {
    116         LocalSocket socket = mSocket;
    117         if (socket == null) {
    118             Logw("'send' request on closed Socket " + mChannelName);
    119             throw new ClosedChannelException();
    120         }
    121         socket.getOutputStream().write(data, offset, len);
    122     }
    123 
    124     /**
    125      * Receives data from the socket.
    126      *
    127      * @param socket Socket from where to receive data.
    128      * @param data Array where to save received data.
    129      * @param len Number of bytes to receive.
    130      * @throws IOException
    131      */
    132     public static void receive(LocalSocket socket, byte[] data, int len) throws IOException {
    133         final InputStream is = socket.getInputStream();
    134         int received = 0;
    135         while (received != len) {
    136             final int chunk = is.read(data, received, len - received);
    137             if (chunk < 0) {
    138                 throw new IOException(
    139                         "I/O failure while receiving SDK controller data from socket.");
    140             }
    141             received += chunk;
    142         }
    143     }
    144 
    145     /**
    146      * Receives data from the socket.
    147      *
    148      * @param data Array where to save received data.
    149      * @param len Number of bytes to receive.
    150      * @throws IOException
    151      */
    152     public void receive(byte[] data, int len) throws IOException {
    153         LocalSocket socket = mSocket;
    154         if (socket == null) {
    155             Logw("'receive' request on closed Socket " + mChannelName);
    156             throw new ClosedChannelException();
    157         }
    158         receive(socket, data, len);
    159     }
    160 
    161     /**
    162      * Receives data from the socket.
    163      *
    164      * @param data Array where to save received data. Data size is defined by
    165      *            the size of the array.
    166      * @throws IOException
    167      */
    168     public void receive(byte[] data) throws IOException {
    169         receive(data, data.length);
    170     }
    171 
    172     /**
    173      * Closes the socket.
    174      *
    175      * @return true if socket has been closed in this call, or false if it had
    176      *         been already closed when this method has been called.
    177      */
    178     public boolean close() {
    179         // This is the only place in this class where we will null the socket
    180         // object. Since this method can be called concurrently from different
    181         // threads, lets do this under the lock.
    182         LocalSocket socket;
    183         synchronized (this) {
    184             socket = mSocket;
    185             mSocket = null;
    186         }
    187         if (socket != null) {
    188             try {
    189                 // Force all I/O to stop before closing the socket.
    190                 socket.shutdownInput();
    191                 socket.shutdownOutput();
    192                 socket.close();
    193                 if (DEBUG) Log.d(TAG, "Socket is closed for " + mChannelName);
    194                 return true;
    195             } catch (IOException e) {
    196                 Loge("Exception " + e + " while closing Socket for " + mChannelName);
    197             }
    198         }
    199         return false;
    200     }
    201 
    202     /***************************************************************************
    203      * Logging wrappers
    204      **************************************************************************/
    205 
    206     private void Loge(String log) {
    207         Log.e(TAG, log);
    208     }
    209 
    210     private void Logw(String log) {
    211         Log.w(TAG, log);
    212     }
    213 }
    214