// // Copyright 2005 The Android Open Source Project // // High-level message stream that sits on top of a pair of Pipes. Useful // for inter-process communication, e.g. between "simulator" and "runtime". // // All messages are sent in packets: // +00 16-bit length (of everything that follows), little-endian // +02 8-bit message type // +03 (reserved, must be zero) // +04 message body // #ifndef _LIBS_UTILS_MESSAGE_STREAM_H #define _LIBS_UTILS_MESSAGE_STREAM_H #ifdef HAVE_ANDROID_OS #error DO NOT USE THIS FILE IN THE DEVICE BUILD #endif #include <utils/Pipe.h> #include <stdlib.h> #include <cutils/uio.h> // Defined in LogBundle.h. struct android_LogBundle; namespace android { /* * A single message, which can be filled out and sent, or filled with * received data. * * Message objects are reusable. */ class Message { public: Message(void) : mCleanup(kCleanupUnknown) { reset(); } ~Message(void) { reset(); } /* values for message type byte */ typedef enum MessageType { kTypeUnknown = 0, kTypeRaw, // chunk of raw data kTypeConfig, // send a name=value pair to peer kTypeCommand, // simple command w/arg kTypeCommandExt, // slightly more complicated command kTypeLogBundle, // multi-part log message } MessageType; /* what to do with data when we're done */ typedef enum Cleanup { kCleanupUnknown = 0, kCleanupNoDelete, // do not delete data when object destroyed kCleanupDelete, // delete with "delete[]" } Cleanup; /* * Stuff raw data into the object. The caller can use the "cleanup" * parameter to decide whether or not the Message object owns the data. */ void setRaw(const unsigned char* data, int len, Cleanup cleanup); /* * Send a "name=value" pair. */ void setConfig(const char* name, const char* value); /* * Send a command/arg pair. */ void setCommand(int cmd, int arg); void setCommandExt(int cmd, int arg0, int arg1, int arg2); /* * Send a multi-part log message. */ void setLogBundle(const android_LogBundle* pBundle); /* * Simple accessors. */ MessageType getType(void) const { return mType; } const unsigned char* getData(void) const { return mData; } int getLength(void) const { return mLength; } /* * Not-so-simple accessors. These coerce the raw data into an object. * * The data returned by these may not outlive the Message, so make * copies if you plan to use them long-term. */ bool getConfig(const char** pName, const char** pValue); bool getCommand(int* pCmd, int* pArg); bool getLogBundle(android_LogBundle* pBundle); /* * Read or write this message on the specified pipe. * * If "wait" is true, read() blocks until a message arrives. Only * one thread should be reading at a time. */ bool read(Pipe* pPipe, bool wait); bool write(Pipe* pPipe) const; private: Message& operator=(const Message&); // not defined Message(const Message&); // not defined void reset(void) { if (mCleanup == kCleanupDelete) delete[] mData; mType = kTypeUnknown; mCleanup = kCleanupNoDelete; mData = NULL; mLength = -1; } MessageType mType; Cleanup mCleanup; unsigned char* mData; int mLength; struct iovec mVec; }; /* * Abstraction of higher-level communication channel. * * This may be used from multiple threads simultaneously. Blocking on * the read pipe from multiple threads will have unpredictable behavior. * * Does not take ownership of the pipes passed in to init(). */ class MessageStream { public: MessageStream(void) : mReadPipe(NULL), mWritePipe(NULL) {} ~MessageStream(void) {} /* * Initialize object and exchange greetings. "initateHello" determines * whether we send "Hello" or block waiting for it to arrive. Usually * the "parent" initiates. */ bool init(Pipe* readPipe, Pipe* writePipe, bool initiateHello); bool isReady(void) const { return mReadPipe != NULL && mWritePipe != NULL; } /* * Send a message immediately. */ bool send(const Message* pMsg) { return pMsg->write(mWritePipe); } /* * Receive a message. */ bool recv(Message* pMsg, bool wait) { return pMsg->read(mReadPipe, wait); } /* * Close communication pipes. Further attempts to send or receive * will fail. Note this doesn't actually "close" the pipes, because * we don't own them. */ void close(void) { mReadPipe = mWritePipe = NULL; } /* * Get our incoming traffic pipe. This is useful on Linux systems * because it allows access to the file descriptor which can be used * in a select() call. */ Pipe* getReadPipe(void) { return mReadPipe; } private: enum { kHelloMsg = 0x4e303047, // 'N00G' kHelloAckMsg = 0x31455221, // '1ER!' }; /* communication pipes; note we don't own these */ Pipe* mReadPipe; Pipe* mWritePipe; }; }; // namespace android #endif // _LIBS_UTILS_MESSAGE_STREAM_H