aboutsummaryrefslogtreecommitdiff
path: root/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java
diff options
context:
space:
mode:
Diffstat (limited to 'apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java')
-rw-r--r--apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java795
1 files changed, 0 insertions, 795 deletions
diff --git a/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java b/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java
deleted file mode 100644
index 639f4cfd4..000000000
--- a/apps/SdkController/src/com/android/tools/sdkcontroller/lib/Channel.java
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * 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.os.Message;
-import android.util.Log;
-
-import com.android.tools.sdkcontroller.service.ControllerService;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Encapsulates basics of a connection with the emulator.
- * This class must be used as a base class for all the channelss that provide
- * particular type of emulation (such as sensors, multi-touch, etc.)
- * <p/>
- * Essentially, Channel is an implementation of a particular emulated functionality,
- * that defines logical format of the data transferred between the emulator and
- * SDK controller. For instance, "sensors" is a channel that emulates sensors,
- * and transfers sensor value changes from the device to the emulator. "Multi-touch"
- * is a channel that supports multi-touch emulation, and transfers multi-touch
- * events to the emulator, while receiving frame buffer updates from the emulator.
- * <p/>
- * Besides connection with the emulator, each channel may contain one or more UI
- * components associated with it. This class provides some basics for UI support,
- * including:
- * <p/>
- * - Providing a way to register / unregister a UI component with the channel.
- * <p/>
- * - Implementing posting of messages to emulator in opposite to direct message
- * sent. This is due to requirement that UI threads are prohibited from doing
- * network I/O.
- */
-public abstract class Channel {
-
- /**
- * Encapsulates a message posted to be sent to the emulator from a worker
- * thread. This class is used to describe a message that is posted in UI
- * thread, and then picked up in the worker thread.
- */
- private class SdkControllerMessage {
- /** Message type. */
- private int mMessageType;
- /** Message data (can be null). */
- private byte[] mMessage;
- /** Message data size */
- private int mMessageSize;
-
- /**
- * Construct message from an array.
- *
- * @param type Message type.
- * @param message Message data. Message data size is defined by size of
- * the array.
- */
- public SdkControllerMessage(int type, byte[] message) {
- mMessageType = type;
- mMessage = message;
- mMessageSize = (message != null) ? message.length : 0;
- }
-
- /**
- * Construct message from a ByteBuffer.
- *
- * @param type Message type.
- * @param message Message data. Message data size is defined by
- * position() property of the ByteBuffer.
- */
- public SdkControllerMessage(int type, ByteBuffer message) {
- mMessageType = type;
- if (message != null) {
- mMessage = message.array();
- mMessageSize = message.position();
- } else {
- mMessage = null;
- mMessageSize = 0;
- }
- }
-
- /**
- * Gets message type.
-
- *
- * @return Message type.
- */
- public int getMessageType() {
- return mMessageType;
- }
-
- /**
- * Gets message buffer.
- *
- * @return Message buffer.
- */
- public byte[] getMessage() {
- return mMessage;
- }
-
- /**
- * Gets message buffer size.
- *
- * @return Message buffer size.
- */
- public int getMessageSize() {
- return mMessageSize;
- }
- } // SdkControllerMessage
-
- /*
- * Names for currently implemented SDK controller channels.
- */
-
- /** Name for a channel that handles sensors emulation */
- public static final String SENSOR_CHANNEL = "sensors";
- /** Name for a channel that handles multi-touch emulation */
- public static final String MULTITOUCH_CHANNEL = "multi-touch";
-
- /*
- * Types of messages internally used by Channel class.
- */
-
- /** Service-side emulator is connected. */
- private static final int MSG_CONNECTED = -1;
- /** Service-side emulator is disconnected. */
- private static final int MSG_DISCONNECTED = -2;
- /** Service-side emulator is enabled. */
- private static final int MSG_ENABLED = -3;
- /** Service-side emulator is disabled. */
- private static final int MSG_DISABLED = -4;
-
- /** Tag for logging messages. */
- private static final String TAG = "SdkControllerChannel";
- /** Controls debug log. */
- private static final boolean DEBUG = false;
-
- /** Service that has created this object. */
- protected ControllerService mService;
-
- /*
- * Socket stuff.
- */
-
- /** Socket to use to to communicate with the emulator. */
- private Socket mSocket = null;
- /** Channel name ("sensors", "multi-touch", etc.) */
- private String mChannelName;
- /** Endianness of data transferred in this channel. */
- private ByteOrder mEndian;
-
- /*
- * Message posting support.
- */
-
- /** Total number of messages posted in this channel */
- private final AtomicInteger mMsgCount = new AtomicInteger(0);
- /** Flags whether or not message thread is running. */
- private volatile boolean mRunMsgQueue = true;
- /** Queue of messages pending transmission. */
- private final BlockingQueue<SdkControllerMessage>
- mMsgQueue = new LinkedBlockingQueue<SdkControllerMessage>();
- /** Message thread */
- private final Thread mMsgThread;
-
- /*
- * UI support.
- */
-
- /** Lists UI handlers attached to this channel. */
- private final List<android.os.Handler> mUiHandlers = new ArrayList<android.os.Handler>();
-
- /*
- * Abstract methods.
- */
-
- /**
- * This method is invoked when this channel is fully connected with its
- * counterpart in the emulator.
- */
- public abstract void onEmulatorConnected();
-
- /**
- * This method is invoked when this channel loses connection with its
- * counterpart in the emulator.
- */
- public abstract void onEmulatorDisconnected();
-
- /**
- * A message has been received from the emulator.
- *
- * @param msg_type Message type.
- * @param msg_data Message data. Message data size is defined by the length
- * of the array wrapped by the ByteBuffer.
- */
- public abstract void onEmulatorMessage(int msg_type, ByteBuffer msg_data);
-
- /**
- * A query has been received from the emulator.
- *
- * @param query_id Identifies the query. This ID must be used when replying
- * to the query.
- * @param query_type Query type.
- * @param query_data Query data. Query data size is defined by the length of
- * the array wrapped by the ByteBuffer.
- */
- public abstract void onEmulatorQuery(int query_id, int query_type, ByteBuffer query_data);
-
- /*
- * Channel implementation.
- */
-
- /**
- * Constructs Channel instance.
- *
- * @param name Channel name.
- */
- public Channel(ControllerService service, String name) {
- mService = service;
- mChannelName = name;
- // Start the worker thread for posted messages.
- mMsgThread = new Thread(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) Log.d(TAG, "MsgThread.started-" + mChannelName);
- while (mRunMsgQueue) {
- try {
- SdkControllerMessage msg = mMsgQueue.take();
- if (msg != null) {
- sendMessage(
- msg.getMessageType(), msg.getMessage(), msg.getMessageSize());
- mMsgCount.incrementAndGet();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "MsgThread-" + mChannelName, e);
- }
- }
- if (DEBUG) Log.d(TAG, "MsgThread.terminate-" + mChannelName);
- }
- }, "MsgThread-" + name);
- mMsgThread.start();
- if (DEBUG) Log.d(TAG, "Channel is constructed for " + mChannelName);
- }
-
- /**
- * Gets name for this channel.
- *
- * @return Emulator name.
- */
- public String getChannelName() {
- return mChannelName;
- }
-
- /**
- * Gets endianness for this channel.
- *
- * @return Channel endianness.
- */
- public ByteOrder getEndian() {
- return mEndian;
- }
-
- /**
- * Gets number of messages sent via postMessage method.
- *
- * @return Number of messages sent via postMessage method.
- */
- public int getMsgSentCount() {
- return mMsgCount.get();
- }
-
- /**
- * Checks if this channel is connected with the emulator.
- *
- * @return true if this channel is connected with the emulator, or false if it is
- * not connected.
- */
- public boolean isConnected() {
- // 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.
- Socket socket = mSocket;
- return socket != null && socket.isConnected();
- }
-
- /**
- * Establishes connection with the emulator. This method is called by Connection
- * object when emulator successfully connects to this channel, or this channel
- * gets registered, and there is a pending socket connection for it.
- *
- * @param socket Channel connection socket.
- */
- public void connect(Socket socket) {
- mSocket = socket;
- mEndian = socket.getEndian();
- Logv("Channel " + mChannelName + " is now connected with the emulator.");
- // Notify the emulator that connection is established.
- sendMessage(MSG_CONNECTED, (byte[]) null);
-
- // Let the derived class know that emulator is connected, and start the
- // I/O loop in which we will receive data from the emulator. Note that
- // we start the loop after onEmulatorConnected call, since we don't want
- // to start dispatching messages before the derived class could set
- // itself up for receiving them.
- onEmulatorConnected();
- new Thread(new Runnable() {
- @Override
- public void run() {
- runIOLooper();
- }
- }, "ChannelIoLoop").start();
- mService.notifyStatusChanged();
- }
-
- /**
- * Disconnects this channel from the emulator.
- *
- * @return true if this channel has been disconnected in this call, or false if
- * channel has been already disconnected when this method has been called.
- */
- public boolean disconnect() {
- // 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.
- Socket socket;
- synchronized (this) {
- socket = mSocket;
- mSocket = null;
- }
- if (socket != null) {
- // Notify the emulator about channel disconnection before we close
- // the communication socket.
- try {
- sendMessage(socket, MSG_DISCONNECTED, null, 0);
- } catch (IOException e) {
- // Ignore I/O exception at this point. We don't care about
- // it, since the socket is being closed anyways.
- }
- // This will eventually stop I/O looper thread.
- socket.close();
- mService.notifyStatusChanged();
- }
- return socket != null;
- }
-
- /**
- * Enables the emulation. Typically, this method is called for channels that are
- * dependent on UI to handle the emulation. For instance, multi-touch emulation is
- * disabled until at least one UI component is attached to the channel. So, for
- * multi-touch emulation this method is called when UI gets attached to the channel.
- */
- public void enable() {
- postMessage(MSG_ENABLED, (byte[]) null);
- mService.notifyStatusChanged();
- }
-
- /**
- * Disables the emulation. Just the opposite to enable(). For multi-touch this
- * method is called when UI detaches from the channel.
- */
- public void disable() {
- postMessage(MSG_DISABLED, (byte[]) null);
- mService.notifyStatusChanged();
- }
-
- /**
- * Sends message to the emulator.
- *
- * @param socket Socket to send the message to.
- * @param msg_type Message type.
- * @param msg Message data to send.
- * @param len Byte size of message data.
- * @throws IOException
- */
- private void sendMessage(Socket socket, int msg_type, byte[] msg, int len)
- throws IOException {
- // In async environment we must have message header and message data in
- // one block to prevent messages from other threads getting between the
- // header and the data. So, we can't sent header, and then the data. We
- // must combine them in one data block instead.
- ByteBuffer bb = ByteBuffer.allocate(ProtocolConstants.MESSAGE_HEADER_SIZE + len);
- bb.order(mEndian);
-
- // Initialize message header.
- bb.putInt(ProtocolConstants.PACKET_SIGNATURE);
- bb.putInt(ProtocolConstants.MESSAGE_HEADER_SIZE + len);
- bb.putInt(ProtocolConstants.PACKET_TYPE_MESSAGE);
- bb.putInt(msg_type);
-
- // Save message data (if there is any).
- if (len != 0) {
- bb.put(msg, 0, len);
- }
-
- socket.send(bb.array());
- }
-
- /**
- * Sends message to the emulator.
- *
- * @param msg_type Message type.
- * @param msg Message data to send. Message size is defined by the size of
- * the array.
- * @return true on success, or false if data transmission has failed.
- */
- public boolean sendMessage(int msg_type, byte[] msg, int msg_len) {
- try {
- Socket socket = mSocket;
- if (socket != null) {
- sendMessage(socket, msg_type, msg, msg_len);
- return true;
- } else {
- Logw("sendMessage is called on disconnected Channel " + mChannelName);
- }
- } catch (IOException e) {
- Loge("Exception " + e + " in sendMessage for Channel " + mChannelName);
- onIoFailure();
- }
- return false;
- }
-
- /**
- * Sends message to the emulator.
- *
- * @param msg_type Message type.
- * @param msg Message data to send. Message size is defined by the size of
- * the array.
- * @return true on success, or false if data transmission has failed.
- */
- public boolean sendMessage(int msg_type, byte[] msg) {
- try {
- Socket socket = mSocket;
- if (socket != null) {
- if (msg != null) {
- sendMessage(socket, msg_type, msg, msg.length);
- } else {
- sendMessage(socket, msg_type, null, 0);
- }
- return true;
- } else {
- Logw("sendMessage is called on disconnected Channel " + mChannelName);
- }
- } catch (IOException e) {
- Loge("Exception " + e + " in sendMessage for Channel " + mChannelName);
- onIoFailure();
- }
- return false;
- }
-
- /**
- * Sends message to the emulator.
- *
- * @param msg_type Message type.
- * @param msg Message data to send. Message size is defined by the
- * position() property of the ByteBuffer.
- * @return true on success, or false if data transmission has failed.
- */
- public boolean sendMessage(int msg_type, ByteBuffer msg) {
- try {
- Socket socket = mSocket;
- if (socket != null) {
- if (msg != null) {
- sendMessage(socket, msg_type, msg.array(), msg.position());
- } else {
- sendMessage(socket, msg_type, null, 0);
- }
- return true;
- } else {
- Logw("sendMessage is called on disconnected Channel " + mChannelName);
- }
- } catch (IOException e) {
- Loge("Exception " + e + " in sendMessage for Channel " + mChannelName);
- onIoFailure();
- }
- return false;
- }
-
- /**
- * Posts message to the emulator.
- *
- * @param msg_type Message type.
- * @param msg Message data to post. Message size is defined by the size of
- * the array.
- */
- public void postMessage(int msg_type, byte[] msg) {
- try {
- mMsgQueue.put(new SdkControllerMessage(msg_type, msg));
- } catch (InterruptedException e) {
- Log.e(TAG, "mMessageQueue.put", e);
- }
- }
-
- /**
- * Posts message to the emulator.
- *
- * @param msg_type Message type.
- * @param msg Message data to post. Message size is defined by the
- * position() property of the ByteBuffer.
- */
- public void postMessage(int msg_type, ByteBuffer msg) {
- try {
- mMsgQueue.put(new SdkControllerMessage(msg_type, msg));
- } catch (InterruptedException e) {
- Log.e(TAG, "mMessageQueue.put", e);
- }
- }
-
- /**
- * Sends query response to the emulator.
- *
- * @param query_id Query identifier.
- * @param qresp Response to the query.
- * @param len Byte size of query response data.
- * @return true on success, or false if data transmission has failed.
- */
- public boolean sendQueryResponse(int query_id, byte[] qresp, int len) {
- // Just like with messages, we must combine header and data in a single
- // transmitting block.
- ByteBuffer bb = ByteBuffer.allocate(ProtocolConstants.QUERY_RESP_HEADER_SIZE + len);
- bb.order(mEndian);
-
- // Initialize response header.
- bb.putInt(ProtocolConstants.PACKET_SIGNATURE);
- bb.putInt(ProtocolConstants.QUERY_RESP_HEADER_SIZE + len);
- bb.putInt(ProtocolConstants.PACKET_TYPE_QUERY_RESPONSE);
- bb.putInt(query_id);
-
- // Save response data (if there is any).
- if (qresp != null && len != 0) {
- bb.put(qresp, 0, len);
- }
-
- // Send the response.
- try {
- Socket socket = mSocket;
- if (socket != null) {
- socket.send(bb.array());
- return true;
- } else {
- Logw("sendQueryResponse is called on disconnected Channel "
- + mChannelName);
- }
- } catch (IOException e) {
- Loge("Exception " + e + " in sendQueryResponse for Channel " + mChannelName);
- onIoFailure();
- }
- return false;
- }
-
- /**
- * Sends query response to the emulator.
- *
- * @param query_id Query identifier.
- * @param qresp Response to the query. Query response size is defined by the
- * size of the array.
- * @return true on success, or false if data transmission has failed.
- */
- public boolean sendQueryResponse(int query_id, byte[] qresp) {
- return (qresp != null) ? sendQueryResponse(query_id, qresp, qresp.length) :
- sendQueryResponse(query_id, null, 0);
- }
-
- /**
- * Sends query response to the emulator.
- *
- * @param query_id Query identifier.
- * @param qresp Response to the query. Query response size is defined by the
- * position() property of the ByteBuffer.
- * @return true on success, or false if data transmission has failed.
- */
- public boolean sendQueryResponse(int query_id, ByteBuffer qresp) {
- return (qresp != null) ? sendQueryResponse(query_id, qresp.array(), qresp.position()) :
- sendQueryResponse(query_id, null, 0);
- }
-
- /**
- * Handles an I/O failure occurred in the channel.
- */
- private void onIoFailure() {
- // All I/O failures cause disconnection.
- if (disconnect()) {
- // Success of disconnect() indicates that I/O failure is not the
- // result of a disconnection request, but is in deed an I/O
- // failure. Report lost connection to the derived class.
- Loge("Connection with the emulator has been lost in Channel " + mChannelName);
- onEmulatorDisconnected();
- }
- }
-
- /**
- * Loops on the local socket, handling connection attempts.
- */
- private void runIOLooper() {
- if (DEBUG) Log.d(TAG, "In I/O looper for Channel " + mChannelName);
- // Initialize byte buffer large enough to receive packet header.
- ByteBuffer header = ByteBuffer.allocate(ProtocolConstants.PACKET_HEADER_SIZE);
- header.order(mEndian);
- try {
- // Since disconnection (which will null the mSocket) can be
- // requested from outside of this thread, it's simpler just to make
- // a copy of mSocket here, and work with that copy. Otherwise we
- // will have to go through a complex synchronization algorithm that
- // would decrease performance on normal runs. If socket gets closed
- // while we're in the middle of transfer, an exception will occur,
- // which we will catch and handle properly.
- Socket socket = mSocket;
- while (socket != null) {
- // Reset header position.
- header.position(0);
- // This will receive total packet size + packet type.
- socket.receive(header.array());
- // First - signature.
- final int signature = header.getInt();
- assert signature == ProtocolConstants.PACKET_SIGNATURE;
- // Next - packet size (including header).
- int remains = header.getInt() - ProtocolConstants.PACKET_HEADER_SIZE;
- // After the size comes packet type.
- final int packet_type = header.getInt();
-
- // Get the remainder of the data, and dispatch the packet to
- // an appropriate handler.
- switch (packet_type) {
- case ProtocolConstants.PACKET_TYPE_MESSAGE:
- // Read message header (one int: message type).
- final int ext = ProtocolConstants.MESSAGE_HEADER_SIZE - ProtocolConstants.PACKET_HEADER_SIZE;
- header.position(0);
- socket.receive(header.array(), ext);
- final int msg_type = header.getInt();
-
- // Read message data.
- remains -= ext;
- final ByteBuffer msg_data = ByteBuffer.allocate(remains);
- msg_data.order(mEndian);
- socket.receive(msg_data.array());
-
- // Dispatch message for handling.
- onEmulatorMessage(msg_type, msg_data);
- break;
-
- case ProtocolConstants.PACKET_TYPE_QUERY:
- // Read query ID and query type.
- final int extq = ProtocolConstants.QUERY_HEADER_SIZE - ProtocolConstants.PACKET_HEADER_SIZE;
- header.position(0);
- socket.receive(header.array(), extq);
- final int query_id = header.getInt();
- final int query_type = header.getInt();
-
- // Read query data.
- remains -= extq;
- final ByteBuffer query_data = ByteBuffer.allocate(remains);
- query_data.order(mEndian);
- socket.receive(query_data.array());
-
- // Dispatch query for handling.
- onEmulatorQuery(query_id, query_type, query_data);
- break;
-
- default:
- // Unknown packet type. Just discard the remainder
- // of the packet
- Loge("Unknown packet type " + packet_type + " in Channel "
- + mChannelName);
- final byte[] discard_data = new byte[remains];
- socket.receive(discard_data);
- break;
- }
- socket = mSocket;
- }
- } catch (IOException e) {
- Loge("Exception " + e + " in I/O looper for Channel " + mChannelName);
- onIoFailure();
- }
- if (DEBUG) Log.d(TAG, "Exiting I/O looper for Channel " + mChannelName);
- }
-
- /**
- * Indicates any UI handler is currently registered with the channel. If no UI
- * is displaying the channel's state, maybe the channel can skip UI related tasks.
- *
- * @return True if there's at least one UI handler registered.
- */
- public boolean hasUiHandler() {
- return !mUiHandlers.isEmpty();
- }
-
- /**
- * Registers a new UI handler.
- *
- * @param uiHandler A non-null UI handler to register. Ignored if the UI
- * handler is null or already registered.
- */
- public void addUiHandler(android.os.Handler uiHandler) {
- assert uiHandler != null;
- if (uiHandler != null) {
- if (!mUiHandlers.contains(uiHandler)) {
- mUiHandlers.add(uiHandler);
- }
- }
- }
-
- /**
- * Unregisters an UI handler.
- *
- * @param uiHandler A non-null UI listener to unregister. Ignored if the
- * listener is null or already registered.
- */
- public void removeUiHandler(android.os.Handler uiHandler) {
- assert uiHandler != null;
- mUiHandlers.remove(uiHandler);
- }
-
- /**
- * Protected method to be used by handlers to send an event to all UI
- * handlers.
- *
- * @param event An integer event code with no specific parameters. To be
- * defined by the handler itself.
- */
- protected void notifyUiHandlers(int event) {
- for (android.os.Handler uiHandler : mUiHandlers) {
- uiHandler.sendEmptyMessage(event);
- }
- }
-
- /**
- * Protected method to be used by handlers to send an event to all UI
- * handlers.
- *
- * @param msg An event with parameters. To be defined by the handler itself.
- */
- protected void notifyUiHandlers(Message msg) {
- for (android.os.Handler uiHandler : mUiHandlers) {
- uiHandler.sendMessage(msg);
- }
- }
-
- /**
- * A helper routine that expands ByteBuffer to contain given number of extra
- * bytes.
- *
- * @param buff Buffer to expand.
- * @param extra Number of bytes that are required to be available in the
- * buffer after current position()
- * @return ByteBuffer, containing required number of available bytes.
- */
- public ByteBuffer ExpandIf(ByteBuffer buff, int extra) {
- if (extra <= buff.remaining()) {
- return buff;
- }
- ByteBuffer ret = ByteBuffer.allocate(buff.position() + extra);
- ret.order(buff.order());
- ret.put(buff.array(), 0, buff.position());
- return ret;
- }
-
- /***************************************************************************
- * Logging wrappers
- **************************************************************************/
-
- private void Loge(String log) {
- mService.addError(log);
- Log.e(TAG, log);
- }
-
- private void Logw(String log) {
- Log.w(TAG, log);
- }
-
- private void Logv(String log) {
- Log.v(TAG, log);
- }
-}