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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Non-blocking event logger intended for safe communication between processes via shared memory
#ifndef ANDROID_MEDIA_NBLOG_H
#define ANDROID_MEDIA_NBLOG_H
#include <binder/IMemory.h>
#include <utils/Mutex.h>
#include <audio_utils/roundup.h>
namespace android {
class String8;
class NBLog {
public:
class Writer;
class Reader;
private:
enum Event {
EVENT_RESERVED,
EVENT_STRING, // ASCII string, not NUL-terminated
EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
};
// ---------------------------------------------------------------------------
// representation of a single log entry in private memory
struct Entry {
Entry(Event event, const void *data, size_t length)
: mEvent(event), mLength(length), mData(data) { }
/*virtual*/ ~Entry() { }
int readAt(size_t offset) const;
private:
friend class Writer;
Event mEvent; // event type
size_t mLength; // length of additional data, 0 <= mLength <= 255
const void *mData; // event type-specific data
};
// representation of a single log entry in shared memory
// byte[0] mEvent
// byte[1] mLength
// byte[2] mData[0]
// ...
// byte[2+i] mData[i]
// ...
// byte[2+mLength-1] mData[mLength-1]
// byte[2+mLength] duplicate copy of mLength to permit reverse scan
// byte[3+mLength] start of next log entry
// located in shared memory
struct Shared {
Shared() : mRear(0) { }
/*virtual*/ ~Shared() { }
volatile int32_t mRear; // index one byte past the end of most recent Entry
char mBuffer[0]; // circular buffer for entries
};
public:
// ---------------------------------------------------------------------------
// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
// For now it is just a namespace for sharedSize().
class Timeline : public RefBase {
public:
#if 0
Timeline(size_t size, void *shared = NULL);
virtual ~Timeline();
#endif
// Input parameter 'size' is the desired size of the timeline in byte units.
// Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
static size_t sharedSize(size_t size);
#if 0
private:
friend class Writer;
friend class Reader;
const size_t mSize; // circular buffer size in bytes, must be a power of 2
bool mOwn; // whether I own the memory at mShared
Shared* const mShared; // pointer to shared memory
#endif
};
// ---------------------------------------------------------------------------
// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
class Writer : public RefBase {
public:
Writer(); // dummy nop implementation without shared memory
// Input parameter 'size' is the desired size of the timeline in byte units.
// The size of the shared memory must be at least Timeline::sharedSize(size).
Writer(size_t size, void *shared);
Writer(size_t size, const sp<IMemory>& iMemory);
virtual ~Writer() { }
virtual void log(const char *string);
virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
virtual void logvf(const char *fmt, va_list ap);
virtual void logTimestamp();
virtual void logTimestamp(const struct timespec& ts);
virtual bool isEnabled() const;
// return value for all of these is the previous isEnabled()
virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
bool enable() { return setEnabled(true); }
bool disable() { return setEnabled(false); }
sp<IMemory> getIMemory() const { return mIMemory; }
private:
void log(Event event, const void *data, size_t length);
void log(const Entry *entry, bool trusted = false);
const size_t mSize; // circular buffer size in bytes, must be a power of 2
Shared* const mShared; // raw pointer to shared memory
const sp<IMemory> mIMemory; // ref-counted version
int32_t mRear; // my private copy of mShared->mRear
bool mEnabled; // whether to actually log
};
// ---------------------------------------------------------------------------
// Similar to Writer, but safe for multiple threads to call concurrently
class LockedWriter : public Writer {
public:
LockedWriter();
LockedWriter(size_t size, void *shared);
virtual void log(const char *string);
virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
virtual void logvf(const char *fmt, va_list ap);
virtual void logTimestamp();
virtual void logTimestamp(const struct timespec& ts);
virtual bool isEnabled() const;
virtual bool setEnabled(bool enabled);
private:
mutable Mutex mLock;
};
// ---------------------------------------------------------------------------
class Reader : public RefBase {
public:
// Input parameter 'size' is the desired size of the timeline in byte units.
// The size of the shared memory must be at least Timeline::sharedSize(size).
Reader(size_t size, const void *shared);
Reader(size_t size, const sp<IMemory>& iMemory);
virtual ~Reader() { }
void dump(int fd, size_t indent = 0);
bool isIMemory(const sp<IMemory>& iMemory) const;
private:
const size_t mSize; // circular buffer size in bytes, must be a power of 2
const Shared* const mShared; // raw pointer to shared memory
const sp<IMemory> mIMemory; // ref-counted version
int32_t mFront; // index of oldest acknowledged Entry
int mFd; // file descriptor
int mIndent; // indentation level
void dumpLine(const String8& timestamp, String8& body);
static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
};
}; // class NBLog
} // namespace android
#endif // ANDROID_MEDIA_NBLOG_H
|