NBLog.h revision fb1fdc9d6603aa228362e7349451f6455c9849c2
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Non-blocking event logger intended for safe communication between processes via shared memory
18
19#ifndef ANDROID_MEDIA_NBLOG_H
20#define ANDROID_MEDIA_NBLOG_H
21
22#include <binder/IMemory.h>
23#include <utils/Mutex.h>
24#include <media/nbaio/roundup.h>
25
26namespace android {
27
28class NBLog {
29
30public:
31
32class Writer;
33class Reader;
34
35private:
36
37enum Event {
38    EVENT_RESERVED,
39    EVENT_STRING,               // ASCII string, not NUL-terminated
40    EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
41};
42
43// ---------------------------------------------------------------------------
44
45// representation of a single log entry in private memory
46struct Entry {
47    Entry(Event event, const void *data, size_t length)
48        : mEvent(event), mLength(length), mData(data) { }
49    /*virtual*/ ~Entry() { }
50
51    int     readAt(size_t offset) const;
52
53private:
54    friend class Writer;
55    Event       mEvent;     // event type
56    size_t      mLength;    // length of additional data, 0 <= mLength <= 255
57    const void *mData;      // event type-specific data
58};
59
60// representation of a single log entry in shared memory
61//  byte[0]             mEvent
62//  byte[1]             mLength
63//  byte[2]             mData[0]
64//  ...
65//  byte[2+i]           mData[i]
66//  ...
67//  byte[2+mLength-1]   mData[mLength-1]
68//  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
69//  byte[3+mLength]     start of next log entry
70
71// located in shared memory
72struct Shared {
73    Shared() : mRear(0) { }
74    /*virtual*/ ~Shared() { }
75
76    volatile int32_t mRear;     // index one byte past the end of most recent Entry
77    char    mBuffer[0];         // circular buffer for entries
78};
79
80public:
81
82// ---------------------------------------------------------------------------
83
84// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
85// For now it is just a namespace for sharedSize().
86class Timeline : public RefBase {
87public:
88#if 0
89    Timeline(size_t size, void *shared = NULL);
90    virtual ~Timeline();
91#endif
92
93    // Input parameter 'size' is the desired size of the timeline in byte units.
94    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
95    static size_t sharedSize(size_t size);
96
97#if 0
98private:
99    friend class    Writer;
100    friend class    Reader;
101
102    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
103    bool            mOwn;       // whether I own the memory at mShared
104    Shared* const   mShared;    // pointer to shared memory
105#endif
106};
107
108// ---------------------------------------------------------------------------
109
110// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
111// calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
112class Writer : public RefBase {
113public:
114    Writer();                   // dummy nop implementation without shared memory
115
116    // Input parameter 'size' is the desired size of the timeline in byte units.
117    // The size of the shared memory must be at least Timeline::sharedSize(size).
118    Writer(size_t size, void *shared);
119    Writer(size_t size, const sp<IMemory>& iMemory);
120
121    virtual ~Writer() { }
122
123    virtual void    log(const char *string);
124    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
125    virtual void    logvf(const char *fmt, va_list ap);
126    virtual void    logTimestamp();
127    virtual void    logTimestamp(const struct timespec& ts);
128
129    virtual bool    isEnabled() const;
130
131    // return value for all of these is the previous isEnabled()
132    virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
133            bool    enable()    { return setEnabled(true); }
134            bool    disable()   { return setEnabled(false); }
135
136    sp<IMemory>     getIMemory() const  { return mIMemory; }
137
138private:
139    void    log(Event event, const void *data, size_t length);
140    void    log(const Entry *entry, bool trusted = false);
141
142    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
143    Shared* const   mShared;    // raw pointer to shared memory
144    const sp<IMemory> mIMemory; // ref-counted version
145    int32_t         mRear;      // my private copy of mShared->mRear
146    bool            mEnabled;   // whether to actually log
147};
148
149// ---------------------------------------------------------------------------
150
151// Similar to Writer, but safe for multiple threads to call concurrently
152class LockedWriter : public Writer {
153public:
154    LockedWriter();
155    LockedWriter(size_t size, void *shared);
156
157    virtual void    log(const char *string);
158    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
159    virtual void    logvf(const char *fmt, va_list ap);
160    virtual void    logTimestamp();
161    virtual void    logTimestamp(const struct timespec& ts);
162
163    virtual bool    isEnabled() const;
164    virtual bool    setEnabled(bool enabled);
165
166private:
167    mutable Mutex   mLock;
168};
169
170// ---------------------------------------------------------------------------
171
172class Reader : public RefBase {
173public:
174
175    // Input parameter 'size' is the desired size of the timeline in byte units.
176    // The size of the shared memory must be at least Timeline::sharedSize(size).
177    Reader(size_t size, const void *shared);
178    Reader(size_t size, const sp<IMemory>& iMemory);
179
180    virtual ~Reader() { }
181
182    void    dump(int fd, size_t indent = 0);
183    bool    isIMemory(const sp<IMemory>& iMemory) const;
184
185private:
186    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
187    const Shared* const mShared; // raw pointer to shared memory
188    const sp<IMemory> mIMemory; // ref-counted version
189    int32_t     mFront;         // index of oldest acknowledged Entry
190
191    static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
192};
193
194};  // class NBLog
195
196}   // namespace android
197
198#endif  // ANDROID_MEDIA_NBLOG_H
199