blob: a0152b1261a15f952dc914a5999b1384f4f481ce [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/Debug.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070020
Steven Moreland5e677882018-02-23 14:59:21 -080021#include <cutils/atomic.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070022#include <utils/Log.h>
23#include <utils/RefBase.h>
24#include <utils/Vector.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070025
Steven Moreland507238e2020-07-14 22:12:20 +000026#include "BufferedTextOutput.h"
Martijn Coenene01f4f22016-05-12 12:33:28 +020027#include <hwbinder/Static.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070028
Elliott Hughesf729b642018-07-13 11:10:22 -070029#include <pthread.h>
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070030#include <stdio.h>
31#include <stdlib.h>
32
33// ---------------------------------------------------------------------------
34
35namespace android {
Martijn Coenenf75a23d2016-08-01 11:55:17 +020036namespace hardware {
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070037
38struct BufferedTextOutput::BufferState : public RefBase
39{
Chih-Hung Hsieh1f555e92016-04-25 15:41:05 -070040 explicit BufferState(int32_t _seq)
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070041 : seq(_seq)
Yi Kong55d41072018-07-23 14:55:39 -070042 , buffer(nullptr)
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070043 , bufferPos(0)
44 , bufferSize(0)
45 , atFront(true)
46 , indent(0)
47 , bundle(0) {
48 }
49 ~BufferState() {
50 free(buffer);
51 }
Keun Soo Yime5855722017-01-07 17:18:17 -080052
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070053 status_t append(const char* txt, size_t len) {
Martijn Coenenb0221962020-01-22 10:41:03 +010054 if (len > SIZE_MAX - bufferPos) return NO_MEMORY; // overflow
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070055 if ((len+bufferPos) > bufferSize) {
Martijn Coenenb0221962020-01-22 10:41:03 +010056 if ((len + bufferPos) > SIZE_MAX / 3) return NO_MEMORY; // overflow
Christopher Tateabaa7622015-06-08 14:45:14 -070057 size_t newSize = ((len+bufferPos)*3)/2;
Christopher Tateabaa7622015-06-08 14:45:14 -070058 void* b = realloc(buffer, newSize);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070059 if (!b) return NO_MEMORY;
60 buffer = (char*)b;
Christopher Tateabaa7622015-06-08 14:45:14 -070061 bufferSize = newSize;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070062 }
63 memcpy(buffer+bufferPos, txt, len);
64 bufferPos += len;
65 return NO_ERROR;
66 }
Keun Soo Yime5855722017-01-07 17:18:17 -080067
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070068 void restart() {
69 bufferPos = 0;
70 atFront = true;
71 if (bufferSize > 256) {
72 void* b = realloc(buffer, 256);
73 if (b) {
74 buffer = (char*)b;
75 bufferSize = 256;
76 }
77 }
78 }
Keun Soo Yime5855722017-01-07 17:18:17 -080079
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070080 const int32_t seq;
81 char* buffer;
82 size_t bufferPos;
83 size_t bufferSize;
84 bool atFront;
85 int32_t indent;
86 int32_t bundle;
87};
88
89struct BufferedTextOutput::ThreadState
90{
91 Vector<sp<BufferedTextOutput::BufferState> > states;
92};
93
Elliott Hughesf729b642018-07-13 11:10:22 -070094static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070095
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070096static volatile int32_t gSequence = 0;
97
98static volatile int32_t gFreeBufferIndex = -1;
99
100static int32_t allocBufferIndex()
101{
102 int32_t res = -1;
Keun Soo Yime5855722017-01-07 17:18:17 -0800103
Elliott Hughesf729b642018-07-13 11:10:22 -0700104 pthread_mutex_lock(&gMutex);
Keun Soo Yime5855722017-01-07 17:18:17 -0800105
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700106 if (gFreeBufferIndex >= 0) {
107 res = gFreeBufferIndex;
108 gFreeBufferIndex = gTextBuffers[res];
109 gTextBuffers.editItemAt(res) = -1;
110
111 } else {
112 res = gTextBuffers.size();
113 gTextBuffers.add(-1);
114 }
115
Elliott Hughesf729b642018-07-13 11:10:22 -0700116 pthread_mutex_unlock(&gMutex);
Keun Soo Yime5855722017-01-07 17:18:17 -0800117
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700118 return res;
119}
120
121static void freeBufferIndex(int32_t idx)
122{
Elliott Hughesf729b642018-07-13 11:10:22 -0700123 pthread_mutex_lock(&gMutex);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700124 gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
125 gFreeBufferIndex = idx;
Elliott Hughesf729b642018-07-13 11:10:22 -0700126 pthread_mutex_unlock(&gMutex);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700127}
128
129// ---------------------------------------------------------------------------
130
131BufferedTextOutput::BufferedTextOutput(uint32_t flags)
132 : mFlags(flags)
133 , mSeq(android_atomic_inc(&gSequence))
134 , mIndex(allocBufferIndex())
135{
136 mGlobalState = new BufferState(mSeq);
137 if (mGlobalState) mGlobalState->incStrong(this);
138}
Keun Soo Yime5855722017-01-07 17:18:17 -0800139
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700140BufferedTextOutput::~BufferedTextOutput()
141{
142 if (mGlobalState) mGlobalState->decStrong(this);
143 freeBufferIndex(mIndex);
144}
145
146status_t BufferedTextOutput::print(const char* txt, size_t len)
147{
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700148 AutoMutex _l(mLock);
149 BufferState* b = getBuffer();
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700150 const char* const end = txt+len;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700151 status_t err;
152
153 while (txt < end) {
154 // Find the next line.
155 const char* first = txt;
156 while (txt < end && *txt != '\n') txt++;
Keun Soo Yime5855722017-01-07 17:18:17 -0800157
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700158 // Include this and all following empty lines.
159 while (txt < end && *txt == '\n') txt++;
Keun Soo Yime5855722017-01-07 17:18:17 -0800160
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700161 // Special cases for first data on a line.
162 if (b->atFront) {
163 if (b->indent > 0) {
164 // If this is the start of a line, add the indent.
165 const char* prefix = stringForIndent(b->indent);
166 err = b->append(prefix, strlen(prefix));
167 if (err != NO_ERROR) return err;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700168 } else if (*(txt-1) == '\n' && !b->bundle) {
169 // Fast path: if we are not indenting or bundling, and
170 // have been given one or more complete lines, just write
171 // them out without going through the buffer.
Keun Soo Yime5855722017-01-07 17:18:17 -0800172
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700173 // Slurp up all of the lines.
174 const char* lastLine = txt+1;
175 while (txt < end) {
176 if (*txt++ == '\n') lastLine = txt;
177 }
178 struct iovec vec;
179 vec.iov_base = (void*)first;
180 vec.iov_len = lastLine-first;
181 //printf("Writing %d bytes of data!\n", vec.iov_len);
182 writeLines(vec, 1);
183 txt = lastLine;
184 continue;
185 }
186 }
Keun Soo Yime5855722017-01-07 17:18:17 -0800187
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700188 // Append the new text to the buffer.
189 err = b->append(first, txt-first);
190 if (err != NO_ERROR) return err;
191 b->atFront = *(txt-1) == '\n';
Keun Soo Yime5855722017-01-07 17:18:17 -0800192
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700193 // If we have finished a line and are not bundling, write
194 // it out.
195 //printf("Buffer is now %d bytes\n", b->bufferPos);
196 if (b->atFront && !b->bundle) {
197 struct iovec vec;
198 vec.iov_base = b->buffer;
199 vec.iov_len = b->bufferPos;
200 //printf("Writing %d bytes of data!\n", vec.iov_len);
201 writeLines(vec, 1);
202 b->restart();
203 }
204 }
Keun Soo Yime5855722017-01-07 17:18:17 -0800205
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700206 return NO_ERROR;
207}
208
209void BufferedTextOutput::moveIndent(int delta)
210{
211 AutoMutex _l(mLock);
212 BufferState* b = getBuffer();
213 b->indent += delta;
214 if (b->indent < 0) b->indent = 0;
215}
216
217void BufferedTextOutput::pushBundle()
218{
219 AutoMutex _l(mLock);
220 BufferState* b = getBuffer();
221 b->bundle++;
222}
223
224void BufferedTextOutput::popBundle()
225{
226 AutoMutex _l(mLock);
227 BufferState* b = getBuffer();
228 b->bundle--;
229 LOG_FATAL_IF(b->bundle < 0,
230 "TextOutput::popBundle() called more times than pushBundle()");
231 if (b->bundle < 0) b->bundle = 0;
Keun Soo Yime5855722017-01-07 17:18:17 -0800232
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700233 if (b->bundle == 0) {
234 // Last bundle, write out data if it is complete. If it is not
235 // complete, don't write until the last line is done... this may
236 // or may not be the write thing to do, but it's the easiest.
237 if (b->bufferPos > 0 && b->atFront) {
238 struct iovec vec;
239 vec.iov_base = b->buffer;
240 vec.iov_len = b->bufferPos;
241 writeLines(vec, 1);
242 b->restart();
243 }
244 }
245}
246
247BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
248{
249 if ((mFlags&MULTITHREADED) != 0) {
Elliott Hughes187cc9f2020-12-02 11:08:12 -0800250 thread_local ThreadState ts;
251 while (ts.states.size() <= (size_t)mIndex) ts.states.add(nullptr);
252 BufferState* bs = ts.states[mIndex].get();
253 if (bs != nullptr && bs->seq == mSeq) return bs;
Keun Soo Yime5855722017-01-07 17:18:17 -0800254
Elliott Hughes187cc9f2020-12-02 11:08:12 -0800255 ts.states.editItemAt(mIndex) = new BufferState(mIndex);
256 bs = ts.states[mIndex].get();
257 if (bs != nullptr) return bs;
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700258 }
Keun Soo Yime5855722017-01-07 17:18:17 -0800259
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700260 return mGlobalState;
261}
262
Steven Moreland7173a4c2019-09-26 15:55:02 -0700263} // namespace hardware
264} // namespace android