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 
26 namespace android {
27 
28 class String8;
29 
30 class NBLog {
31 
32 public:
33 
34 class Writer;
35 class Reader;
36 
37 private:
38 
39 enum 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
48 struct Entry {
EntryEntry49     Entry(Event event, const void *data, size_t length)
50         : mEvent(event), mLength(length), mData(data) { }
~EntryEntry51     /*virtual*/ ~Entry() { }
52 
53     int     readAt(size_t offset) const;
54 
55 private:
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
74 struct Shared {
SharedShared75     Shared() : mRear(0) { }
~SharedShared76     /*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 
82 public:
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().
88 class Timeline : public RefBase {
89 public:
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
100 private:
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.
114 class Writer : public RefBase {
115 public:
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 
~Writer()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
enable()135             bool    enable()    { return setEnabled(true); }
disable()136             bool    disable()   { return setEnabled(false); }
137 
getIMemory()138     sp<IMemory>     getIMemory() const  { return mIMemory; }
139 
140 private:
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
154 class LockedWriter : public Writer {
155 public:
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 
168 private:
169     mutable Mutex   mLock;
170 };
171 
172 // ---------------------------------------------------------------------------
173 
174 class Reader : public RefBase {
175 public:
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 
~Reader()182     virtual ~Reader() { }
183 
184     void    dump(int fd, size_t indent = 0);
185     bool    isIMemory(const sp<IMemory>& iMemory) const;
186 
187 private:
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