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 <audio_utils/roundup.h>
25
26namespace android {
27
28class String8;
29
30class NBLog {
31
32public:
33
34class Writer;
35class Reader;
36
37private:
38
39enum Event {
40    EVENT_RESERVED,
41    EVENT_STRING,               // ASCII string, not NUL-terminated
42    EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
43};
44
45// ---------------------------------------------------------------------------
46
47// representation of a single log entry in private memory
48struct Entry {
49    Entry(Event event, const void *data, size_t length)
50        : mEvent(event), mLength(length), mData(data) { }
51    /*virtual*/ ~Entry() { }
52
53    int     readAt(size_t offset) const;
54
55private:
56    friend class Writer;
57    Event       mEvent;     // event type
58    size_t      mLength;    // length of additional data, 0 <= mLength <= 255
59    const void *mData;      // event type-specific data
60};
61
62// representation of a single log entry in shared memory
63//  byte[0]             mEvent
64//  byte[1]             mLength
65//  byte[2]             mData[0]
66//  ...
67//  byte[2+i]           mData[i]
68//  ...
69//  byte[2+mLength-1]   mData[mLength-1]
70//  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
71//  byte[3+mLength]     start of next log entry
72
73// located in shared memory
74struct Shared {
75    Shared() : mRear(0) { }
76    /*virtual*/ ~Shared() { }
77
78    volatile int32_t mRear;     // index one byte past the end of most recent Entry
79    char    mBuffer[0];         // circular buffer for entries
80};
81
82public:
83
84// ---------------------------------------------------------------------------
85
86// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
87// For now it is just a namespace for sharedSize().
88class Timeline : public RefBase {
89public:
90#if 0
91    Timeline(size_t size, void *shared = NULL);
92    virtual ~Timeline();
93#endif
94
95    // Input parameter 'size' is the desired size of the timeline in byte units.
96    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
97    static size_t sharedSize(size_t size);
98
99#if 0
100private:
101    friend class    Writer;
102    friend class    Reader;
103
104    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
105    bool            mOwn;       // whether I own the memory at mShared
106    Shared* const   mShared;    // pointer to shared memory
107#endif
108};
109
110// ---------------------------------------------------------------------------
111
112// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
113// calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
114class Writer : public RefBase {
115public:
116    Writer();                   // dummy nop implementation without shared memory
117
118    // Input parameter 'size' is the desired size of the timeline in byte units.
119    // The size of the shared memory must be at least Timeline::sharedSize(size).
120    Writer(size_t size, void *shared);
121    Writer(size_t size, const sp<IMemory>& iMemory);
122
123    virtual ~Writer() { }
124
125    virtual void    log(const char *string);
126    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
127    virtual void    logvf(const char *fmt, va_list ap);
128    virtual void    logTimestamp();
129    virtual void    logTimestamp(const struct timespec& ts);
130
131    virtual bool    isEnabled() const;
132
133    // return value for all of these is the previous isEnabled()
134    virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
135            bool    enable()    { return setEnabled(true); }
136            bool    disable()   { return setEnabled(false); }
137
138    sp<IMemory>     getIMemory() const  { return mIMemory; }
139
140private:
141    void    log(Event event, const void *data, size_t length);
142    void    log(const Entry *entry, bool trusted = false);
143
144    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
145    Shared* const   mShared;    // raw pointer to shared memory
146    const sp<IMemory> mIMemory; // ref-counted version
147    int32_t         mRear;      // my private copy of mShared->mRear
148    bool            mEnabled;   // whether to actually log
149};
150
151// ---------------------------------------------------------------------------
152
153// Similar to Writer, but safe for multiple threads to call concurrently
154class LockedWriter : public Writer {
155public:
156    LockedWriter();
157    LockedWriter(size_t size, void *shared);
158
159    virtual void    log(const char *string);
160    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
161    virtual void    logvf(const char *fmt, va_list ap);
162    virtual void    logTimestamp();
163    virtual void    logTimestamp(const struct timespec& ts);
164
165    virtual bool    isEnabled() const;
166    virtual bool    setEnabled(bool enabled);
167
168private:
169    mutable Mutex   mLock;
170};
171
172// ---------------------------------------------------------------------------
173
174class Reader : public RefBase {
175public:
176
177    // Input parameter 'size' is the desired size of the timeline in byte units.
178    // The size of the shared memory must be at least Timeline::sharedSize(size).
179    Reader(size_t size, const void *shared);
180    Reader(size_t size, const sp<IMemory>& iMemory);
181
182    virtual ~Reader() { }
183
184    void    dump(int fd, size_t indent = 0);
185    bool    isIMemory(const sp<IMemory>& iMemory) const;
186
187private:
188    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
189    const Shared* const mShared; // raw pointer to shared memory
190    const sp<IMemory> mIMemory; // ref-counted version
191    int32_t     mFront;         // index of oldest acknowledged Entry
192    int     mFd;                // file descriptor
193    int     mIndent;            // indentation level
194
195    void    dumpLine(const String8& timestamp, String8& body);
196
197    static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
198};
199
200};  // class NBLog
201
202}   // namespace android
203
204#endif  // ANDROID_MEDIA_NBLOG_H
205