//
// 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 "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