Initial Contribution
diff --git a/simulator/app/MessageStream.cpp b/simulator/app/MessageStream.cpp
new file mode 100644
index 0000000..2397c63
--- /dev/null
+++ b/simulator/app/MessageStream.cpp
@@ -0,0 +1,402 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Message stream abstraction.
+//
+#include "MessageStream.h"
+#include "LogBundle.h"
+
+#include "utils/Log.h"
+
+#include <string.h>
+#include <assert.h>
+
+using namespace android;
+
+/*
+ * ===========================================================================
+ * Message
+ * ===========================================================================
+ */
+
+/*
+ * Send a blob of raw data.
+ */
+void Message::setRaw(const unsigned char* data, int len, Cleanup cleanup)
+{
+ reset();
+
+ mData = const_cast<unsigned char*>(data);
+ mLength = len;
+ mCleanup = cleanup;
+ mType = kTypeRaw;
+}
+
+/*
+ * Send a "name=value" config pair.
+ */
+void Message::setConfig(const char* name, const char* value)
+{
+ reset();
+
+ assert(name != NULL && value != NULL);
+
+ int nlen = strlen(name) +1;
+ int vlen = strlen(value) +1;
+ mData = new unsigned char[nlen+vlen];
+ mCleanup = kCleanupDelete;
+ mLength = nlen + vlen;
+ mType = kTypeConfig;
+
+ memcpy(mData, name, nlen);
+ memcpy(mData + nlen, value, vlen);
+}
+
+/*
+ * Try to return the contents of the message as if it were a name/value pair.
+ */
+bool Message::getConfig(const char** pName, const char** pValue)
+{
+ if (mLength < 2)
+ return false;
+ assert(mData != NULL);
+
+ *pName = (const char*) mData;
+ *pValue = (const char*) (mData + strlen((char*)mData) +1);
+ return true;
+}
+
+/*
+ * Send a command/arg pair.
+ */
+void Message::setCommand(int cmd, int arg)
+{
+ reset();
+
+ mData = new unsigned char[sizeof(int) * 2];
+ mCleanup = kCleanupDelete;
+ mLength = sizeof(int) * 2;
+ mType = kTypeCommand;
+
+ int* pInt = (int*) mData;
+ pInt[0] = cmd;
+ pInt[1] = arg;
+}
+
+/*
+ * Send a command with 3 args instead of just one.
+ */
+void Message::setCommandExt(int cmd, int arg0, int arg1, int arg2)
+{
+ reset();
+
+ mData = new unsigned char[sizeof(int) * 4];
+ mCleanup = kCleanupDelete;
+ mLength = sizeof(int) * 4;
+ mType = kTypeCommandExt;
+
+ int* pInt = (int*) mData;
+ pInt[0] = cmd;
+ pInt[1] = arg0;
+ pInt[2] = arg1;
+ pInt[3] = arg2;
+}
+
+/*
+ * Try to return the contents of the message as if it were a "command".
+ */
+bool Message::getCommand(int* pCmd, int* pArg)
+{
+ if (mLength != sizeof(int) * 2) {
+ LOG(LOG_WARN, "", "type is %d, len is %d\n", mType, mLength);
+ return false;
+ }
+ assert(mData != NULL);
+
+ const int* pInt = (const int*) mData;
+ *pCmd = pInt[0];
+ *pArg = pInt[1];
+
+ return true;
+}
+
+/*
+ * Serialize a log message.
+ *
+ * DO NOT call LOG() from here.
+ */
+void Message::setLogBundle(const android_LogBundle* pBundle)
+{
+ reset();
+
+ /* get string lengths; we add one here to include the '\0' */
+ int tagLen, msgLen;
+ tagLen = strlen(pBundle->tag) + 1;
+ size_t i;
+ msgLen = 0;
+ for (i=0; i<pBundle->msgCount; i++) msgLen += pBundle->msgVec[i].iov_len;
+ msgLen += 1;
+
+ /* set up the structure */
+ mCleanup = kCleanupDelete;
+ mLength = sizeof(pBundle->when) +
+ sizeof(pBundle->priority) +
+ sizeof(pBundle->pid) +
+ tagLen +
+ msgLen;
+ mData = new unsigned char[mLength];
+ mType = kTypeLogBundle;
+
+ unsigned char* pCur = mData;
+
+ /* copy the stuff over */
+ *((time_t*)pCur) = pBundle->when;
+ pCur += sizeof(pBundle->when);
+ *((android_LogPriority*)pCur) = pBundle->priority;
+ pCur += sizeof(pBundle->priority);
+ *((pid_t*)pCur) = pBundle->pid;
+ pCur += sizeof(pBundle->pid);
+ memcpy(pCur, pBundle->tag, tagLen);
+ pCur += tagLen;
+ for (i=0; i<pBundle->msgCount; i++) {
+ memcpy(pCur, pBundle->msgVec[i].iov_base, pBundle->msgVec[i].iov_len);
+ pCur += pBundle->msgVec[i].iov_len;
+ }
+ *pCur++ = 0;
+
+ assert(pCur - mData == mLength);
+}
+
+/*
+ * Extract the components of a log bundle.
+ *
+ * We're just returning points inside the message buffer, so the caller
+ * will need to copy them out before the next reset().
+ */
+bool Message::getLogBundle(android_LogBundle* pBundle)
+{
+ if (mLength < (int)(sizeof(time_t) + sizeof(int)*2 + 4)) {
+ LOG(LOG_WARN, "", "type is %d, len is %d, too small\n",
+ mType, mLength);
+ return false;
+ }
+ assert(mData != NULL);
+
+ unsigned char* pCur = mData;
+
+ pBundle->when = *((time_t*) pCur);
+ pCur += sizeof(pBundle->when);
+ pBundle->priority = *((android_LogPriority*) pCur);
+ pCur += sizeof(pBundle->priority);
+ pBundle->pid = *((pid_t*) pCur);
+ pCur += sizeof(pBundle->pid);
+ pBundle->tag = (const char*) pCur;
+ pCur += strlen((const char*) pCur) +1;
+ mVec.iov_base = (char*) pCur;
+ mVec.iov_len = strlen((const char*) pCur);
+ pBundle->msgVec = &mVec;
+ pBundle->msgCount = 1;
+ pCur += mVec.iov_len +1;
+
+ if (pCur - mData != mLength) {
+ LOG(LOG_WARN, "", "log bundle rcvd %d, used %d\n", mLength,
+ (int) (pCur - mData));
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Read the next event from the pipe.
+ *
+ * This is not expected to work well when multiple threads are reading.
+ */
+bool Message::read(Pipe* pPipe, bool wait)
+{
+ if (pPipe == NULL)
+ return false;
+ assert(pPipe->isCreated());
+
+ if (!wait) {
+ if (!pPipe->readReady())
+ return false;
+ }
+
+ reset();
+
+ unsigned char header[4];
+ if (pPipe->read(header, 4) != 4)
+ return false;
+
+ mType = (MessageType) header[2];
+ mLength = header[0] | header[1] << 8;
+ mLength -= 2; // we already read two of them in the header
+
+ if (mLength > 0) {
+ int actual;
+
+ mData = new unsigned char[mLength];
+ if (mData == NULL) {
+ LOG(LOG_ERROR, "", "alloc failed\n");
+ return false;
+ }
+ mCleanup = kCleanupDelete;
+
+ actual = pPipe->read(mData, mLength);
+ if (actual != mLength) {
+ LOG(LOG_WARN, "", "failed reading message body (%d of %d bytes)\n",
+ actual, mLength);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*
+ * Write this event to a pipe.
+ *
+ * It would be easiest to write the header and message body with two
+ * separate calls, but that will occasionally fail on multithreaded
+ * systems when the writes are interleaved. We have to allocate a
+ * temporary buffer, copy the data, and write it all at once. This
+ * would be easier with writev(), but we can't rely on having that.
+ *
+ * DO NOT call LOG() from here, as we could be in the process of sending
+ * a log message.
+ */
+bool Message::write(Pipe* pPipe) const
+{
+ char tmpBuf[128];
+ char* writeBuf = tmpBuf;
+ bool result = false;
+ int kHeaderLen = 4;
+
+ if (pPipe == NULL)
+ return false;
+ assert(pPipe->isCreated());
+
+ if (mData == NULL || mLength < 0)
+ return false;
+
+ /* if it doesn't fit in stack buffer, allocate space */
+ if (mLength + kHeaderLen > (int) sizeof(tmpBuf)) {
+ writeBuf = new char[mLength + kHeaderLen];
+ if (writeBuf == NULL)
+ goto bail;
+ }
+
+ /*
+ * The current value of "mLength" does not include the 4-byte header.
+ * Two of the 4 header bytes are included in the length we output
+ * (the type byte and the pad byte), so we adjust mLength.
+ */
+ writeBuf[0] = (unsigned char) (mLength + kHeaderLen -2);
+ writeBuf[1] = (unsigned char) ((mLength + kHeaderLen -2) >> 8);
+ writeBuf[2] = (unsigned char) mType;
+ writeBuf[3] = 0;
+ if (mLength > 0)
+ memcpy(writeBuf + kHeaderLen, mData, mLength);
+
+ int actual;
+
+ actual = pPipe->write(writeBuf, mLength + kHeaderLen);
+ if (actual != mLength + kHeaderLen) {
+ fprintf(stderr,
+ "Message::write failed writing message body (%d of %d bytes)\n",
+ actual, mLength + kHeaderLen);
+ goto bail;
+ }
+
+ result = true;
+
+bail:
+ if (writeBuf != tmpBuf)
+ delete[] writeBuf;
+ return result;
+}
+
+
+/*
+ * ===========================================================================
+ * MessageStream
+ * ===========================================================================
+ */
+
+/*
+ * Get ready to go.
+ */
+bool MessageStream::init(Pipe* readPipe, Pipe* writePipe, bool initiateHello)
+{
+ assert(mReadPipe == NULL && mWritePipe == NULL); // only once
+
+ /*
+ * Swap "hello" messages.
+ *
+ * In a more robust implementation, this would include version numbers
+ * and capability flags.
+ */
+ if (initiateHello) {
+ long data = kHelloMsg;
+ Message msg;
+
+ /* send hello */
+ msg.setRaw((unsigned char*) &data, sizeof(data),
+ Message::kCleanupNoDelete);
+ if (!msg.write(writePipe)) {
+ LOG(LOG_WARN, "", "hello write failed in stream init\n");
+ return false;
+ }
+
+ LOG(LOG_DEBUG, "", "waiting for peer to ack my hello\n");
+
+ /* wait for the ack */
+ if (!msg.read(readPipe, true)) {
+ LOG(LOG_WARN, "", "hello ack read failed in stream init\n");
+ return false;
+ }
+
+ const long* pAck;
+ pAck = (const long*) msg.getData();
+ if (pAck == NULL || *pAck != kHelloAckMsg) {
+ LOG(LOG_WARN, "", "hello ack was bad\n");
+ return false;
+ }
+ } else {
+ long data = kHelloAckMsg;
+ Message msg;
+
+ LOG(LOG_DEBUG, "", "waiting for hello from peer\n");
+
+ /* wait for the hello */
+ if (!msg.read(readPipe, true)) {
+ LOG(LOG_WARN, "", "hello read failed in stream init\n");
+ return false;
+ }
+
+ const long* pAck;
+ pAck = (const long*) msg.getData();
+ if (pAck == NULL || *pAck != kHelloMsg) {
+ LOG(LOG_WARN, "", "hello was bad\n");
+ return false;
+ }
+
+ /* send hello ack */
+ msg.setRaw((unsigned char*) &data, sizeof(data),
+ Message::kCleanupNoDelete);
+ if (!msg.write(writePipe)) {
+ LOG(LOG_WARN, "", "hello ack write failed in stream init\n");
+ return false;
+ }
+ }
+
+ /* success, set up our local stuff */
+ mReadPipe = readPipe;
+ mWritePipe = writePipe;
+
+ //LOG(LOG_DEBUG, "", "init success\n");
+
+ return true;
+}
+