summaryrefslogtreecommitdiffstats
path: root/simulator/app/MessageStream.h
blob: 82a9b4c485648f9225a1cafcc85ea69f1715b0a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//
// 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