18f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown/* 28f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Copyright (C) 2013 The Android Open Source Project 38f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 48f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 58f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * you may not use this file except in compliance with the License. 68f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * You may obtain a copy of the License at 78f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 88f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 98f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Unless required by applicable law or agreed to in writing, software 118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * See the License for the specific language governing permissions and 148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * limitations under the License. 158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpackage com.android.accessorydisplay.common; 188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.os.Handler; 208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.os.Looper; 218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.os.Message; 228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport android.util.SparseArray; 238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.io.IOException; 258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownimport java.nio.ByteBuffer; 268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown/** 288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * A simple message transport. 298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * <p> 308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * This object's interface is thread-safe, however incoming messages 318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * are always delivered on the {@link Looper} thread on which the transport 328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * was created. 338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * </p> 348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brownpublic abstract class Transport { 368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static final int MAX_INPUT_BUFFERS = 8; 378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final Logger mLogger; 398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The transport thread looper and handler. 418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final TransportHandler mHandler; 428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Lock to guard all mutable state. 448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final Object mLock = new Object(); 458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The output buffer. Set to null when the transport is closed. 478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private ByteBuffer mOutputBuffer; 488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The input buffer pool. 508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private BufferPool mInputBufferPool; 518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The reader thread. Initialized when reading starts. 538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private ReaderThread mThread; 548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The list of callbacks indexed by service id. 568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private final SparseArray<Callback> mServices = new SparseArray<Callback>(); 578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public Transport(Logger logger, int maxPacketSize) { 598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger = logger; 608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHandler = new TransportHandler(); 618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer = ByteBuffer.allocate(maxPacketSize); 628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mInputBufferPool = new BufferPool( 638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown maxPacketSize, Protocol.MAX_ENVELOPE_SIZE, MAX_INPUT_BUFFERS); 648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Gets the logger for debugging. 688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public Logger getLogger() { 708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return mLogger; 718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Gets the handler on the transport's thread. 758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public Handler getHandler() { 778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return mHandler; 788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Closes the transport. 828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void close() { 848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown synchronized (mLock) { 858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mOutputBuffer != null) { 868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mThread == null) { 878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ioClose(); 888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // If the thread was started then it will be responsible for 908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // closing the stream when it quits because it may currently 918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // be in the process of reading from the stream so we can't simply 928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // shut it down right now. 938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mThread.quit(); 948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer = null; 968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 1018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Sends a message. 1028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 1038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param service The service to whom the message is addressed. 1048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param what The message type. 1058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param content The content, or null if there is none. 1068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @return True if the message was sent successfully, false if an error occurred. 1078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 1088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public boolean sendMessage(int service, int what, ByteBuffer content) { 1098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown checkServiceId(service); 1108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown checkMessageId(what); 1118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown try { 1138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown synchronized (mLock) { 1148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mOutputBuffer == null) { 1158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Send message failed because transport was closed."); 1168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return false; 1178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final byte[] outputArray = mOutputBuffer.array(); 1208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int capacity = mOutputBuffer.capacity(); 1218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.clear(); 1228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.putShort((short)service); 1238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.putShort((short)what); 1248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (content == null) { 1258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.putInt(0); 1268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 1278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int contentLimit = content.limit(); 1288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int contentPosition = content.position(); 1298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int contentRemaining = contentLimit - contentPosition; 1308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (contentRemaining > Protocol.MAX_CONTENT_SIZE) { 1318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throw new IllegalArgumentException("Message content too large: " 1328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown + contentRemaining + " > " + Protocol.MAX_CONTENT_SIZE); 1338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.putInt(contentRemaining); 1358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown while (contentRemaining != 0) { 1368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int outputAvailable = capacity - mOutputBuffer.position(); 1378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (contentRemaining <= outputAvailable) { 1388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.put(content); 1398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; 1408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown content.limit(contentPosition + outputAvailable); 1428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.put(content); 1438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown content.limit(contentLimit); 1448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ioWrite(outputArray, 0, capacity); 1458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown contentPosition += outputAvailable; 1468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown contentRemaining -= outputAvailable; 1478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mOutputBuffer.clear(); 1488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ioWrite(outputArray, 0, mOutputBuffer.position()); 1518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return true; 1528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } catch (IOException ex) { 1548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Send message failed: " + ex); 1558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown return false; 1568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 1608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Starts reading messages on a separate thread. 1618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 1628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void startReading() { 1638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown synchronized (mLock) { 1648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (mOutputBuffer == null) { 1658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throw new IllegalStateException("Transport has been closed"); 1668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mThread = new ReaderThread(); 1698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mThread.start(); 1708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 1748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Registers a service and provides a callback to receive messages. 1758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 1768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param service The service id. 1778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param callback The callback to use. 1788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 1798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void registerService(int service, Callback callback) { 1808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown checkServiceId(service); 1818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (callback == null) { 1828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throw new IllegalArgumentException("callback must not be null"); 1838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown synchronized (mLock) { 1868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mServices.put(service, callback); 1878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 1898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 1918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Unregisters a service. 1928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 1938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param service The service to unregister. 1948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 1958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void unregisterService(int service) { 1968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown checkServiceId(service); 1978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 1988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown synchronized (mLock) { 1998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mServices.remove(service); 2008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void dispatchMessageReceived(int service, int what, ByteBuffer content) { 2048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final Callback callback; 2058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown synchronized (mLock) { 2068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown callback = mServices.get(service); 2078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (callback != null) { 2098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown callback.onMessageReceived(service, what, content); 2108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 2118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.log("Discarding message " + what 2128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown + " for unregistered service " + service); 2138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static void checkServiceId(int service) { 2178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (service < 0 || service > 0xffff) { 2188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throw new IllegalArgumentException("service id out of range: " + service); 2198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private static void checkMessageId(int what) { 2238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (what < 0 || what > 0xffff) { 2248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throw new IllegalArgumentException("message id out of range: " + what); 2258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // The IO methods must be safe to call on any thread. 2298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // They may be called concurrently. 2308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown protected abstract void ioClose(); 2318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown protected abstract int ioRead(byte[] buffer, int offset, int count) 2328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throws IOException; 2338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown protected abstract void ioWrite(byte[] buffer, int offset, int count) 2348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown throws IOException; 2358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 2378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Callback for services that handle received messages. 2388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 2398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public interface Callback { 2408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown /** 2418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * Indicates that a message was received. 2428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * 2438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param service The service to whom the message is addressed. 2448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param what The message type. 2458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown * @param content The content, or null if there is none. 2468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown */ 2478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void onMessageReceived(int service, int what, ByteBuffer content); 2488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final class TransportHandler extends Handler { 2518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 2528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void handleMessage(Message msg) { 2538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final ByteBuffer buffer = (ByteBuffer)msg.obj; 2548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown try { 2558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int limit = buffer.limit(); 2568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown while (buffer.position() < limit) { 2578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int service = buffer.getShort() & 0xffff; 2588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int what = buffer.getShort() & 0xffff; 2598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int contentSize = buffer.getInt(); 2608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (contentSize == 0) { 2618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown dispatchMessageReceived(service, what, null); 2628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 2638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final int end = buffer.position() + contentSize; 2648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.limit(end); 2658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown dispatchMessageReceived(service, what, buffer); 2668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.limit(limit); 2678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.position(end); 2688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } finally { 2718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mInputBufferPool.release(buffer); 2728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final class ReaderThread extends Thread { 2778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Set to true when quitting. 2788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private volatile boolean mQuitting; 2798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public ReaderThread() { 2818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown super("Accessory Display Transport"); 2828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2838f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2848f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown @Override 2858f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void run() { 2868f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown loop(); 2878f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ioClose(); 2888f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 2898f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 2908f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown private void loop() { 2918f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown ByteBuffer buffer = null; 2928f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int length = Protocol.HEADER_SIZE; 2938f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int contentSize = -1; 2948f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown outer: while (!mQuitting) { 2958f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Get a buffer. 2968f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (buffer == null) { 2978f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer = mInputBufferPool.acquire(length); 2988f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 2998f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer = mInputBufferPool.grow(buffer, length); 3008f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3018f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3028f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Read more data until needed number of bytes obtained. 3038f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int position = buffer.position(); 3048f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int count; 3058f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown try { 3068f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown count = ioRead(buffer.array(), position, buffer.capacity() - position); 3078f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (count < 0) { 3088f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; // end of stream 3098f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3108f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } catch (IOException ex) { 3118f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Read failed: " + ex); 3128f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; // error 3138f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3148f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown position += count; 3158f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.position(position); 3168f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (contentSize < 0 && position >= Protocol.HEADER_SIZE) { 3178f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown contentSize = buffer.getInt(4); 3188f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (contentSize < 0 || contentSize > Protocol.MAX_CONTENT_SIZE) { 3198f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Encountered invalid content size: " + contentSize); 3208f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; // malformed stream 3218f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3228f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown length += contentSize; 3238f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3248f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (position < length) { 3258f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown continue; // need more data 3268f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3278f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3288f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // There is at least one complete message in the buffer. 3298f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Find the end of a contiguous chunk of complete messages. 3308f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int next = length; 3318f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown int remaining; 3328f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown for (;;) { 3338f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown length = Protocol.HEADER_SIZE; 3348f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown remaining = position - next; 3358f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (remaining < length) { 3368f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown contentSize = -1; 3378f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; // incomplete header, need more data 3388f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3398f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown contentSize = buffer.getInt(next + 4); 3408f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (contentSize < 0 || contentSize > Protocol.MAX_CONTENT_SIZE) { 3418f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mLogger.logError("Encountered invalid content size: " + contentSize); 3428f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break outer; // malformed stream 3438f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3448f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown length += contentSize; 3458f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (remaining < length) { 3468f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown break; // incomplete content, need more data 3478f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3488f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown next += length; 3498f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3508f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3518f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Post the buffer then don't modify it anymore. 3528f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // Now this is kind of sneaky. We know that no other threads will 3538f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // be acquiring buffers from the buffer pool so we can keep on 3548f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // referring to this buffer as long as we don't modify its contents. 3558f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // This allows us to operate in a single-buffered mode if desired. 3568f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.limit(next); 3578f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.rewind(); 3588f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mHandler.obtainMessage(0, buffer).sendToTarget(); 3598f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3608f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // If there is an incomplete message at the end, then we will need 3618f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // to copy it to a fresh buffer before continuing. In the single-buffered 3628f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown // case, we may acquire the same buffer as before which is fine. 3638f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (remaining == 0) { 3648f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer = null; 3658f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } else { 3668f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown final ByteBuffer oldBuffer = buffer; 3678f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer = mInputBufferPool.acquire(length); 3688f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown System.arraycopy(oldBuffer.array(), next, buffer.array(), 0, remaining); 3698f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown buffer.position(remaining); 3708f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3718f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3728f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3738f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown if (buffer != null) { 3748f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mInputBufferPool.release(buffer); 3758f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3768f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3778f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown 3788f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown public void quit() { 3798f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown mQuitting = true; 3808f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3818f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown } 3828f3b1307678fcd1896c7fb8ba4cc20553dc032e8Jeff Brown} 383