blob: 5addba471d302804ac1eac72fb1922155cdcc142 [file] [log] [blame]
Mathias Agopian4ea13dc2013-05-06 20:20:50 -07001/*
2 * Copyright (C) 2006 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
Steven Morelandc4dd2102017-02-23 13:57:21 -080017#define LOG_TAG "hw-BufferedTextOutput"
18
Martijn Coenen4080edc2016-05-04 14:17:02 +020019#include <hwbinder/BufferedTextOutput.h>
20#include <hwbinder/Debug.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070021
Steven Moreland5e677882018-02-23 14:59:21 -080022#include <cutils/atomic.h>
23#include <cutils/threads.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070024#include <utils/Log.h>
25#include <utils/RefBase.h>
26#include <utils/Vector.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070027
Martijn Coenene01f4f22016-05-12 12:33:28 +020028#include <hwbinder/Static.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070029
Elliott Hughesf729b642018-07-13 11:10:22 -070030#include <pthread.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070031#include <stdio.h>
32#include <stdlib.h>
33
34// ---------------------------------------------------------------------------
35
36namespace android {
Martijn Coenenf75a23d2016-08-01 11:55:17 +020037namespace hardware {
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070038
39struct BufferedTextOutput::BufferState : public RefBase
40{
Chih-Hung Hsieh1f555e92016-04-25 15:41:05 -070041 explicit BufferState(int32_t _seq)
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070042 : seq(_seq)
Yi Kong55d41072018-07-23 14:55:39 -070043 , buffer(nullptr)
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070044 , bufferPos(0)
45 , bufferSize(0)
46 , atFront(true)
47 , indent(0)
48 , bundle(0) {
49 }
50 ~BufferState() {
51 free(buffer);
52 }
Keun Soo Yime5855722017-01-07 17:18:17 -080053
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070054 status_t append(const char* txt, size_t len) {
Martijn Coenend79ac372020-01-22 10:41:03 +010055 if (len > SIZE_MAX - bufferPos) return NO_MEMORY; // overflow
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070056 if ((len+bufferPos) > bufferSize) {
Martijn Coenend79ac372020-01-22 10:41:03 +010057 if ((len + bufferPos) > SIZE_MAX / 3) return NO_MEMORY; // overflow
Christopher Tateabaa7622015-06-08 14:45:14 -070058 size_t newSize = ((len+bufferPos)*3)/2;
Christopher Tateabaa7622015-06-08 14:45:14 -070059 void* b = realloc(buffer, newSize);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070060 if (!b) return NO_MEMORY;
61 buffer = (char*)b;
Christopher Tateabaa7622015-06-08 14:45:14 -070062 bufferSize = newSize;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070063 }
64 memcpy(buffer+bufferPos, txt, len);
65 bufferPos += len;
66 return NO_ERROR;
67 }
Keun Soo Yime5855722017-01-07 17:18:17 -080068
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070069 void restart() {
70 bufferPos = 0;
71 atFront = true;
72 if (bufferSize > 256) {
73 void* b = realloc(buffer, 256);
74 if (b) {
75 buffer = (char*)b;
76 bufferSize = 256;
77 }
78 }
79 }
Keun Soo Yime5855722017-01-07 17:18:17 -080080
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070081 const int32_t seq;
82 char* buffer;
83 size_t bufferPos;
84 size_t bufferSize;
85 bool atFront;
86 int32_t indent;
87 int32_t bundle;
88};
89
90struct BufferedTextOutput::ThreadState
91{
92 Vector<sp<BufferedTextOutput::BufferState> > states;
93};
94
Elliott Hughesf729b642018-07-13 11:10:22 -070095static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070096
97static thread_store_t tls;
98
99BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
100{
101 ThreadState* ts = (ThreadState*) thread_store_get( &tls );
102 if (ts) return ts;
103 ts = new ThreadState;
104 thread_store_set( &tls, ts, threadDestructor );
105 return ts;
106}
107
108void BufferedTextOutput::threadDestructor(void *st)
109{
110 delete ((ThreadState*)st);
111}
112
113static volatile int32_t gSequence = 0;
114
115static volatile int32_t gFreeBufferIndex = -1;
116
117static int32_t allocBufferIndex()
118{
119 int32_t res = -1;
Keun Soo Yime5855722017-01-07 17:18:17 -0800120
Elliott Hughesf729b642018-07-13 11:10:22 -0700121 pthread_mutex_lock(&gMutex);
Keun Soo Yime5855722017-01-07 17:18:17 -0800122
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700123 if (gFreeBufferIndex >= 0) {
124 res = gFreeBufferIndex;
125 gFreeBufferIndex = gTextBuffers[res];
126 gTextBuffers.editItemAt(res) = -1;
127
128 } else {
129 res = gTextBuffers.size();
130 gTextBuffers.add(-1);
131 }
132
Elliott Hughesf729b642018-07-13 11:10:22 -0700133 pthread_mutex_unlock(&gMutex);
Keun Soo Yime5855722017-01-07 17:18:17 -0800134
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700135 return res;
136}
137
138static void freeBufferIndex(int32_t idx)
139{
Elliott Hughesf729b642018-07-13 11:10:22 -0700140 pthread_mutex_lock(&gMutex);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700141 gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
142 gFreeBufferIndex = idx;
Elliott Hughesf729b642018-07-13 11:10:22 -0700143 pthread_mutex_unlock(&gMutex);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700144}
145
146// ---------------------------------------------------------------------------
147
148BufferedTextOutput::BufferedTextOutput(uint32_t flags)
149 : mFlags(flags)
150 , mSeq(android_atomic_inc(&gSequence))
151 , mIndex(allocBufferIndex())
152{
153 mGlobalState = new BufferState(mSeq);
154 if (mGlobalState) mGlobalState->incStrong(this);
155}
Keun Soo Yime5855722017-01-07 17:18:17 -0800156
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700157BufferedTextOutput::~BufferedTextOutput()
158{
159 if (mGlobalState) mGlobalState->decStrong(this);
160 freeBufferIndex(mIndex);
161}
162
163status_t BufferedTextOutput::print(const char* txt, size_t len)
164{
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700165 AutoMutex _l(mLock);
166 BufferState* b = getBuffer();
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700167 const char* const end = txt+len;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700168 status_t err;
169
170 while (txt < end) {
171 // Find the next line.
172 const char* first = txt;
173 while (txt < end && *txt != '\n') txt++;
Keun Soo Yime5855722017-01-07 17:18:17 -0800174
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700175 // Include this and all following empty lines.
176 while (txt < end && *txt == '\n') txt++;
Keun Soo Yime5855722017-01-07 17:18:17 -0800177
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700178 // Special cases for first data on a line.
179 if (b->atFront) {
180 if (b->indent > 0) {
181 // If this is the start of a line, add the indent.
182 const char* prefix = stringForIndent(b->indent);
183 err = b->append(prefix, strlen(prefix));
184 if (err != NO_ERROR) return err;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700185 } else if (*(txt-1) == '\n' && !b->bundle) {
186 // Fast path: if we are not indenting or bundling, and
187 // have been given one or more complete lines, just write
188 // them out without going through the buffer.
Keun Soo Yime5855722017-01-07 17:18:17 -0800189
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700190 // Slurp up all of the lines.
191 const char* lastLine = txt+1;
192 while (txt < end) {
193 if (*txt++ == '\n') lastLine = txt;
194 }
195 struct iovec vec;
196 vec.iov_base = (void*)first;
197 vec.iov_len = lastLine-first;
198 //printf("Writing %d bytes of data!\n", vec.iov_len);
199 writeLines(vec, 1);
200 txt = lastLine;
201 continue;
202 }
203 }
Keun Soo Yime5855722017-01-07 17:18:17 -0800204
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700205 // Append the new text to the buffer.
206 err = b->append(first, txt-first);
207 if (err != NO_ERROR) return err;
208 b->atFront = *(txt-1) == '\n';
Keun Soo Yime5855722017-01-07 17:18:17 -0800209
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700210 // If we have finished a line and are not bundling, write
211 // it out.
212 //printf("Buffer is now %d bytes\n", b->bufferPos);
213 if (b->atFront && !b->bundle) {
214 struct iovec vec;
215 vec.iov_base = b->buffer;
216 vec.iov_len = b->bufferPos;
217 //printf("Writing %d bytes of data!\n", vec.iov_len);
218 writeLines(vec, 1);
219 b->restart();
220 }
221 }
Keun Soo Yime5855722017-01-07 17:18:17 -0800222
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700223 return NO_ERROR;
224}
225
226void BufferedTextOutput::moveIndent(int delta)
227{
228 AutoMutex _l(mLock);
229 BufferState* b = getBuffer();
230 b->indent += delta;
231 if (b->indent < 0) b->indent = 0;
232}
233
234void BufferedTextOutput::pushBundle()
235{
236 AutoMutex _l(mLock);
237 BufferState* b = getBuffer();
238 b->bundle++;
239}
240
241void BufferedTextOutput::popBundle()
242{
243 AutoMutex _l(mLock);
244 BufferState* b = getBuffer();
245 b->bundle--;
246 LOG_FATAL_IF(b->bundle < 0,
247 "TextOutput::popBundle() called more times than pushBundle()");
248 if (b->bundle < 0) b->bundle = 0;
Keun Soo Yime5855722017-01-07 17:18:17 -0800249
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700250 if (b->bundle == 0) {
251 // Last bundle, write out data if it is complete. If it is not
252 // complete, don't write until the last line is done... this may
253 // or may not be the write thing to do, but it's the easiest.
254 if (b->bufferPos > 0 && b->atFront) {
255 struct iovec vec;
256 vec.iov_base = b->buffer;
257 vec.iov_len = b->bufferPos;
258 writeLines(vec, 1);
259 b->restart();
260 }
261 }
262}
263
264BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
265{
266 if ((mFlags&MULTITHREADED) != 0) {
267 ThreadState* ts = getThreadState();
268 if (ts) {
Yi Kong55d41072018-07-23 14:55:39 -0700269 while (ts->states.size() <= (size_t)mIndex) ts->states.add(nullptr);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700270 BufferState* bs = ts->states[mIndex].get();
Yi Kong55d41072018-07-23 14:55:39 -0700271 if (bs != nullptr && bs->seq == mSeq) return bs;
Keun Soo Yime5855722017-01-07 17:18:17 -0800272
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700273 ts->states.editItemAt(mIndex) = new BufferState(mIndex);
274 bs = ts->states[mIndex].get();
Yi Kong55d41072018-07-23 14:55:39 -0700275 if (bs != nullptr) return bs;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700276 }
277 }
Keun Soo Yime5855722017-01-07 17:18:17 -0800278
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700279 return mGlobalState;
280}
281
Steven Moreland7173a4c2019-09-26 15:55:02 -0700282} // namespace hardware
283} // namespace android