1*77b80299SAndroid Build Coastguard Worker /*
2*77b80299SAndroid Build Coastguard Worker * Copyright (C) 2006 The Android Open Source Project
3*77b80299SAndroid Build Coastguard Worker *
4*77b80299SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*77b80299SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*77b80299SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*77b80299SAndroid Build Coastguard Worker *
8*77b80299SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*77b80299SAndroid Build Coastguard Worker *
10*77b80299SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*77b80299SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*77b80299SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*77b80299SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*77b80299SAndroid Build Coastguard Worker * limitations under the License.
15*77b80299SAndroid Build Coastguard Worker */
16*77b80299SAndroid Build Coastguard Worker
17*77b80299SAndroid Build Coastguard Worker #define LOG_TAG "hw-BufferedTextOutput"
18*77b80299SAndroid Build Coastguard Worker
19*77b80299SAndroid Build Coastguard Worker #include <hwbinder/Debug.h>
20*77b80299SAndroid Build Coastguard Worker
21*77b80299SAndroid Build Coastguard Worker #include <cutils/atomic.h>
22*77b80299SAndroid Build Coastguard Worker #include <utils/Log.h>
23*77b80299SAndroid Build Coastguard Worker #include <utils/RefBase.h>
24*77b80299SAndroid Build Coastguard Worker #include <utils/Vector.h>
25*77b80299SAndroid Build Coastguard Worker
26*77b80299SAndroid Build Coastguard Worker #include "BufferedTextOutput.h"
27*77b80299SAndroid Build Coastguard Worker #include <hwbinder/Static.h>
28*77b80299SAndroid Build Coastguard Worker
29*77b80299SAndroid Build Coastguard Worker #include <pthread.h>
30*77b80299SAndroid Build Coastguard Worker #include <stdio.h>
31*77b80299SAndroid Build Coastguard Worker #include <stdlib.h>
32*77b80299SAndroid Build Coastguard Worker
33*77b80299SAndroid Build Coastguard Worker // ---------------------------------------------------------------------------
34*77b80299SAndroid Build Coastguard Worker
35*77b80299SAndroid Build Coastguard Worker namespace android {
36*77b80299SAndroid Build Coastguard Worker namespace hardware {
37*77b80299SAndroid Build Coastguard Worker
38*77b80299SAndroid Build Coastguard Worker struct BufferedTextOutput::BufferState : public RefBase
39*77b80299SAndroid Build Coastguard Worker {
BufferStateandroid::hardware::BufferedTextOutput::BufferState40*77b80299SAndroid Build Coastguard Worker explicit BufferState(int32_t _seq)
41*77b80299SAndroid Build Coastguard Worker : seq(_seq)
42*77b80299SAndroid Build Coastguard Worker , buffer(nullptr)
43*77b80299SAndroid Build Coastguard Worker , bufferPos(0)
44*77b80299SAndroid Build Coastguard Worker , bufferSize(0)
45*77b80299SAndroid Build Coastguard Worker , atFront(true)
46*77b80299SAndroid Build Coastguard Worker , indent(0)
47*77b80299SAndroid Build Coastguard Worker , bundle(0) {
48*77b80299SAndroid Build Coastguard Worker }
~BufferStateandroid::hardware::BufferedTextOutput::BufferState49*77b80299SAndroid Build Coastguard Worker ~BufferState() {
50*77b80299SAndroid Build Coastguard Worker free(buffer);
51*77b80299SAndroid Build Coastguard Worker }
52*77b80299SAndroid Build Coastguard Worker
appendandroid::hardware::BufferedTextOutput::BufferState53*77b80299SAndroid Build Coastguard Worker status_t append(const char* txt, size_t len) {
54*77b80299SAndroid Build Coastguard Worker if (len > SIZE_MAX - bufferPos) return NO_MEMORY; // overflow
55*77b80299SAndroid Build Coastguard Worker if ((len+bufferPos) > bufferSize) {
56*77b80299SAndroid Build Coastguard Worker if ((len + bufferPos) > SIZE_MAX / 3) return NO_MEMORY; // overflow
57*77b80299SAndroid Build Coastguard Worker size_t newSize = ((len+bufferPos)*3)/2;
58*77b80299SAndroid Build Coastguard Worker void* b = realloc(buffer, newSize);
59*77b80299SAndroid Build Coastguard Worker if (!b) return NO_MEMORY;
60*77b80299SAndroid Build Coastguard Worker buffer = (char*)b;
61*77b80299SAndroid Build Coastguard Worker bufferSize = newSize;
62*77b80299SAndroid Build Coastguard Worker }
63*77b80299SAndroid Build Coastguard Worker memcpy(buffer+bufferPos, txt, len);
64*77b80299SAndroid Build Coastguard Worker bufferPos += len;
65*77b80299SAndroid Build Coastguard Worker return NO_ERROR;
66*77b80299SAndroid Build Coastguard Worker }
67*77b80299SAndroid Build Coastguard Worker
restartandroid::hardware::BufferedTextOutput::BufferState68*77b80299SAndroid Build Coastguard Worker void restart() {
69*77b80299SAndroid Build Coastguard Worker bufferPos = 0;
70*77b80299SAndroid Build Coastguard Worker atFront = true;
71*77b80299SAndroid Build Coastguard Worker if (bufferSize > 256) {
72*77b80299SAndroid Build Coastguard Worker void* b = realloc(buffer, 256);
73*77b80299SAndroid Build Coastguard Worker if (b) {
74*77b80299SAndroid Build Coastguard Worker buffer = (char*)b;
75*77b80299SAndroid Build Coastguard Worker bufferSize = 256;
76*77b80299SAndroid Build Coastguard Worker }
77*77b80299SAndroid Build Coastguard Worker }
78*77b80299SAndroid Build Coastguard Worker }
79*77b80299SAndroid Build Coastguard Worker
80*77b80299SAndroid Build Coastguard Worker const int32_t seq;
81*77b80299SAndroid Build Coastguard Worker char* buffer;
82*77b80299SAndroid Build Coastguard Worker size_t bufferPos;
83*77b80299SAndroid Build Coastguard Worker size_t bufferSize;
84*77b80299SAndroid Build Coastguard Worker bool atFront;
85*77b80299SAndroid Build Coastguard Worker int32_t indent;
86*77b80299SAndroid Build Coastguard Worker int32_t bundle;
87*77b80299SAndroid Build Coastguard Worker };
88*77b80299SAndroid Build Coastguard Worker
89*77b80299SAndroid Build Coastguard Worker struct BufferedTextOutput::ThreadState
90*77b80299SAndroid Build Coastguard Worker {
91*77b80299SAndroid Build Coastguard Worker Vector<sp<BufferedTextOutput::BufferState> > states;
92*77b80299SAndroid Build Coastguard Worker };
93*77b80299SAndroid Build Coastguard Worker
94*77b80299SAndroid Build Coastguard Worker static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
95*77b80299SAndroid Build Coastguard Worker
96*77b80299SAndroid Build Coastguard Worker static volatile int32_t gSequence = 0;
97*77b80299SAndroid Build Coastguard Worker
98*77b80299SAndroid Build Coastguard Worker static volatile int32_t gFreeBufferIndex = -1;
99*77b80299SAndroid Build Coastguard Worker
allocBufferIndex()100*77b80299SAndroid Build Coastguard Worker static int32_t allocBufferIndex()
101*77b80299SAndroid Build Coastguard Worker {
102*77b80299SAndroid Build Coastguard Worker int32_t res = -1;
103*77b80299SAndroid Build Coastguard Worker
104*77b80299SAndroid Build Coastguard Worker pthread_mutex_lock(&gMutex);
105*77b80299SAndroid Build Coastguard Worker
106*77b80299SAndroid Build Coastguard Worker if (gFreeBufferIndex >= 0) {
107*77b80299SAndroid Build Coastguard Worker res = gFreeBufferIndex;
108*77b80299SAndroid Build Coastguard Worker gFreeBufferIndex = gTextBuffers[res];
109*77b80299SAndroid Build Coastguard Worker gTextBuffers.editItemAt(res) = -1;
110*77b80299SAndroid Build Coastguard Worker
111*77b80299SAndroid Build Coastguard Worker } else {
112*77b80299SAndroid Build Coastguard Worker res = gTextBuffers.size();
113*77b80299SAndroid Build Coastguard Worker gTextBuffers.add(-1);
114*77b80299SAndroid Build Coastguard Worker }
115*77b80299SAndroid Build Coastguard Worker
116*77b80299SAndroid Build Coastguard Worker pthread_mutex_unlock(&gMutex);
117*77b80299SAndroid Build Coastguard Worker
118*77b80299SAndroid Build Coastguard Worker return res;
119*77b80299SAndroid Build Coastguard Worker }
120*77b80299SAndroid Build Coastguard Worker
freeBufferIndex(int32_t idx)121*77b80299SAndroid Build Coastguard Worker static void freeBufferIndex(int32_t idx)
122*77b80299SAndroid Build Coastguard Worker {
123*77b80299SAndroid Build Coastguard Worker pthread_mutex_lock(&gMutex);
124*77b80299SAndroid Build Coastguard Worker gTextBuffers.editItemAt(idx) = gFreeBufferIndex;
125*77b80299SAndroid Build Coastguard Worker gFreeBufferIndex = idx;
126*77b80299SAndroid Build Coastguard Worker pthread_mutex_unlock(&gMutex);
127*77b80299SAndroid Build Coastguard Worker }
128*77b80299SAndroid Build Coastguard Worker
129*77b80299SAndroid Build Coastguard Worker // ---------------------------------------------------------------------------
130*77b80299SAndroid Build Coastguard Worker
BufferedTextOutput(uint32_t flags)131*77b80299SAndroid Build Coastguard Worker BufferedTextOutput::BufferedTextOutput(uint32_t flags)
132*77b80299SAndroid Build Coastguard Worker : mFlags(flags)
133*77b80299SAndroid Build Coastguard Worker , mSeq(android_atomic_inc(&gSequence))
134*77b80299SAndroid Build Coastguard Worker , mIndex(allocBufferIndex())
135*77b80299SAndroid Build Coastguard Worker {
136*77b80299SAndroid Build Coastguard Worker mGlobalState = new BufferState(mSeq);
137*77b80299SAndroid Build Coastguard Worker if (mGlobalState) mGlobalState->incStrong(this);
138*77b80299SAndroid Build Coastguard Worker }
139*77b80299SAndroid Build Coastguard Worker
~BufferedTextOutput()140*77b80299SAndroid Build Coastguard Worker BufferedTextOutput::~BufferedTextOutput()
141*77b80299SAndroid Build Coastguard Worker {
142*77b80299SAndroid Build Coastguard Worker if (mGlobalState) mGlobalState->decStrong(this);
143*77b80299SAndroid Build Coastguard Worker freeBufferIndex(mIndex);
144*77b80299SAndroid Build Coastguard Worker }
145*77b80299SAndroid Build Coastguard Worker
print(const char * txt,size_t len)146*77b80299SAndroid Build Coastguard Worker status_t BufferedTextOutput::print(const char* txt, size_t len)
147*77b80299SAndroid Build Coastguard Worker {
148*77b80299SAndroid Build Coastguard Worker AutoMutex _l(mLock);
149*77b80299SAndroid Build Coastguard Worker BufferState* b = getBuffer();
150*77b80299SAndroid Build Coastguard Worker const char* const end = txt+len;
151*77b80299SAndroid Build Coastguard Worker status_t err;
152*77b80299SAndroid Build Coastguard Worker
153*77b80299SAndroid Build Coastguard Worker while (txt < end) {
154*77b80299SAndroid Build Coastguard Worker // Find the next line.
155*77b80299SAndroid Build Coastguard Worker const char* first = txt;
156*77b80299SAndroid Build Coastguard Worker while (txt < end && *txt != '\n') txt++;
157*77b80299SAndroid Build Coastguard Worker
158*77b80299SAndroid Build Coastguard Worker // Include this and all following empty lines.
159*77b80299SAndroid Build Coastguard Worker while (txt < end && *txt == '\n') txt++;
160*77b80299SAndroid Build Coastguard Worker
161*77b80299SAndroid Build Coastguard Worker // Special cases for first data on a line.
162*77b80299SAndroid Build Coastguard Worker if (b->atFront) {
163*77b80299SAndroid Build Coastguard Worker if (b->indent > 0) {
164*77b80299SAndroid Build Coastguard Worker // If this is the start of a line, add the indent.
165*77b80299SAndroid Build Coastguard Worker const char* prefix = stringForIndent(b->indent);
166*77b80299SAndroid Build Coastguard Worker err = b->append(prefix, strlen(prefix));
167*77b80299SAndroid Build Coastguard Worker if (err != NO_ERROR) return err;
168*77b80299SAndroid Build Coastguard Worker } else if (*(txt-1) == '\n' && !b->bundle) {
169*77b80299SAndroid Build Coastguard Worker // Fast path: if we are not indenting or bundling, and
170*77b80299SAndroid Build Coastguard Worker // have been given one or more complete lines, just write
171*77b80299SAndroid Build Coastguard Worker // them out without going through the buffer.
172*77b80299SAndroid Build Coastguard Worker
173*77b80299SAndroid Build Coastguard Worker // Slurp up all of the lines.
174*77b80299SAndroid Build Coastguard Worker const char* lastLine = txt+1;
175*77b80299SAndroid Build Coastguard Worker while (txt < end) {
176*77b80299SAndroid Build Coastguard Worker if (*txt++ == '\n') lastLine = txt;
177*77b80299SAndroid Build Coastguard Worker }
178*77b80299SAndroid Build Coastguard Worker struct iovec vec;
179*77b80299SAndroid Build Coastguard Worker vec.iov_base = (void*)first;
180*77b80299SAndroid Build Coastguard Worker vec.iov_len = lastLine-first;
181*77b80299SAndroid Build Coastguard Worker //printf("Writing %d bytes of data!\n", vec.iov_len);
182*77b80299SAndroid Build Coastguard Worker writeLines(vec, 1);
183*77b80299SAndroid Build Coastguard Worker txt = lastLine;
184*77b80299SAndroid Build Coastguard Worker continue;
185*77b80299SAndroid Build Coastguard Worker }
186*77b80299SAndroid Build Coastguard Worker }
187*77b80299SAndroid Build Coastguard Worker
188*77b80299SAndroid Build Coastguard Worker // Append the new text to the buffer.
189*77b80299SAndroid Build Coastguard Worker err = b->append(first, txt-first);
190*77b80299SAndroid Build Coastguard Worker if (err != NO_ERROR) return err;
191*77b80299SAndroid Build Coastguard Worker b->atFront = *(txt-1) == '\n';
192*77b80299SAndroid Build Coastguard Worker
193*77b80299SAndroid Build Coastguard Worker // If we have finished a line and are not bundling, write
194*77b80299SAndroid Build Coastguard Worker // it out.
195*77b80299SAndroid Build Coastguard Worker //printf("Buffer is now %d bytes\n", b->bufferPos);
196*77b80299SAndroid Build Coastguard Worker if (b->atFront && !b->bundle) {
197*77b80299SAndroid Build Coastguard Worker struct iovec vec;
198*77b80299SAndroid Build Coastguard Worker vec.iov_base = b->buffer;
199*77b80299SAndroid Build Coastguard Worker vec.iov_len = b->bufferPos;
200*77b80299SAndroid Build Coastguard Worker //printf("Writing %d bytes of data!\n", vec.iov_len);
201*77b80299SAndroid Build Coastguard Worker writeLines(vec, 1);
202*77b80299SAndroid Build Coastguard Worker b->restart();
203*77b80299SAndroid Build Coastguard Worker }
204*77b80299SAndroid Build Coastguard Worker }
205*77b80299SAndroid Build Coastguard Worker
206*77b80299SAndroid Build Coastguard Worker return NO_ERROR;
207*77b80299SAndroid Build Coastguard Worker }
208*77b80299SAndroid Build Coastguard Worker
moveIndent(int delta)209*77b80299SAndroid Build Coastguard Worker void BufferedTextOutput::moveIndent(int delta)
210*77b80299SAndroid Build Coastguard Worker {
211*77b80299SAndroid Build Coastguard Worker AutoMutex _l(mLock);
212*77b80299SAndroid Build Coastguard Worker BufferState* b = getBuffer();
213*77b80299SAndroid Build Coastguard Worker b->indent += delta;
214*77b80299SAndroid Build Coastguard Worker if (b->indent < 0) b->indent = 0;
215*77b80299SAndroid Build Coastguard Worker }
216*77b80299SAndroid Build Coastguard Worker
pushBundle()217*77b80299SAndroid Build Coastguard Worker void BufferedTextOutput::pushBundle()
218*77b80299SAndroid Build Coastguard Worker {
219*77b80299SAndroid Build Coastguard Worker AutoMutex _l(mLock);
220*77b80299SAndroid Build Coastguard Worker BufferState* b = getBuffer();
221*77b80299SAndroid Build Coastguard Worker b->bundle++;
222*77b80299SAndroid Build Coastguard Worker }
223*77b80299SAndroid Build Coastguard Worker
popBundle()224*77b80299SAndroid Build Coastguard Worker void BufferedTextOutput::popBundle()
225*77b80299SAndroid Build Coastguard Worker {
226*77b80299SAndroid Build Coastguard Worker AutoMutex _l(mLock);
227*77b80299SAndroid Build Coastguard Worker BufferState* b = getBuffer();
228*77b80299SAndroid Build Coastguard Worker b->bundle--;
229*77b80299SAndroid Build Coastguard Worker LOG_FATAL_IF(b->bundle < 0,
230*77b80299SAndroid Build Coastguard Worker "TextOutput::popBundle() called more times than pushBundle()");
231*77b80299SAndroid Build Coastguard Worker if (b->bundle < 0) b->bundle = 0;
232*77b80299SAndroid Build Coastguard Worker
233*77b80299SAndroid Build Coastguard Worker if (b->bundle == 0) {
234*77b80299SAndroid Build Coastguard Worker // Last bundle, write out data if it is complete. If it is not
235*77b80299SAndroid Build Coastguard Worker // complete, don't write until the last line is done... this may
236*77b80299SAndroid Build Coastguard Worker // or may not be the write thing to do, but it's the easiest.
237*77b80299SAndroid Build Coastguard Worker if (b->bufferPos > 0 && b->atFront) {
238*77b80299SAndroid Build Coastguard Worker struct iovec vec;
239*77b80299SAndroid Build Coastguard Worker vec.iov_base = b->buffer;
240*77b80299SAndroid Build Coastguard Worker vec.iov_len = b->bufferPos;
241*77b80299SAndroid Build Coastguard Worker writeLines(vec, 1);
242*77b80299SAndroid Build Coastguard Worker b->restart();
243*77b80299SAndroid Build Coastguard Worker }
244*77b80299SAndroid Build Coastguard Worker }
245*77b80299SAndroid Build Coastguard Worker }
246*77b80299SAndroid Build Coastguard Worker
getBuffer() const247*77b80299SAndroid Build Coastguard Worker BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
248*77b80299SAndroid Build Coastguard Worker {
249*77b80299SAndroid Build Coastguard Worker if ((mFlags&MULTITHREADED) != 0) {
250*77b80299SAndroid Build Coastguard Worker thread_local ThreadState ts;
251*77b80299SAndroid Build Coastguard Worker while (ts.states.size() <= (size_t)mIndex) ts.states.add(nullptr);
252*77b80299SAndroid Build Coastguard Worker BufferState* bs = ts.states[mIndex].get();
253*77b80299SAndroid Build Coastguard Worker if (bs != nullptr && bs->seq == mSeq) return bs;
254*77b80299SAndroid Build Coastguard Worker
255*77b80299SAndroid Build Coastguard Worker ts.states.editItemAt(mIndex) = new BufferState(mIndex);
256*77b80299SAndroid Build Coastguard Worker bs = ts.states[mIndex].get();
257*77b80299SAndroid Build Coastguard Worker if (bs != nullptr) return bs;
258*77b80299SAndroid Build Coastguard Worker }
259*77b80299SAndroid Build Coastguard Worker
260*77b80299SAndroid Build Coastguard Worker return mGlobalState;
261*77b80299SAndroid Build Coastguard Worker }
262*77b80299SAndroid Build Coastguard Worker
263*77b80299SAndroid Build Coastguard Worker } // namespace hardware
264*77b80299SAndroid Build Coastguard Worker } // namespace android
265