1 /*
2 * Copyright (C) 2017 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 #define LOG_TAG "libprotoutil"
17
18 #include <stdlib.h>
19 #include <sys/mman.h>
20
21 #include <android/util/EncodedBuffer.h>
22 #include <android/util/protobuf.h>
23 #include <cutils/log.h>
24
25 namespace android {
26 namespace util {
27
28 const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
29
Pointer()30 EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
31 {
32 }
33
Pointer(size_t chunkSize)34 EncodedBuffer::Pointer::Pointer(size_t chunkSize)
35 :mIndex(0),
36 mOffset(0)
37 {
38 mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
39 }
40
41 size_t
pos() const42 EncodedBuffer::Pointer::pos() const
43 {
44 return mIndex * mChunkSize + mOffset;
45 }
46
47 size_t
index() const48 EncodedBuffer::Pointer::index() const
49 {
50 return mIndex;
51 }
52
53 size_t
offset() const54 EncodedBuffer::Pointer::offset() const
55 {
56 return mOffset;
57 }
58
59 EncodedBuffer::Pointer*
move(size_t amt)60 EncodedBuffer::Pointer::move(size_t amt)
61 {
62 size_t newOffset = mOffset + amt;
63 mIndex += newOffset / mChunkSize;
64 mOffset = newOffset % mChunkSize;
65 return this;
66 }
67
68 EncodedBuffer::Pointer*
rewind()69 EncodedBuffer::Pointer::rewind()
70 {
71 mIndex = 0;
72 mOffset = 0;
73 return this;
74 }
75
76 EncodedBuffer::Pointer
copy() const77 EncodedBuffer::Pointer::copy() const
78 {
79 Pointer p = Pointer(mChunkSize);
80 p.mIndex = mIndex;
81 p.mOffset = mOffset;
82 return p;
83 }
84
85 // ===========================================================
EncodedBuffer()86 EncodedBuffer::EncodedBuffer() : EncodedBuffer(BUFFER_SIZE)
87 {
88 }
89
EncodedBuffer(size_t chunkSize)90 EncodedBuffer::EncodedBuffer(size_t chunkSize)
91 :mBuffers()
92 {
93 // Align chunkSize to memory page size
94 chunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
95 mChunkSize = (chunkSize / PAGE_SIZE + ((chunkSize % PAGE_SIZE == 0) ? 0 : 1)) * PAGE_SIZE;
96 mWp = Pointer(mChunkSize);
97 mEp = Pointer(mChunkSize);
98 }
99
~EncodedBuffer()100 EncodedBuffer::~EncodedBuffer()
101 {
102 for (size_t i=0; i<mBuffers.size(); i++) {
103 uint8_t* buf = mBuffers[i];
104 munmap(buf, mChunkSize);
105 }
106 }
107
108 inline uint8_t*
at(const Pointer & p) const109 EncodedBuffer::at(const Pointer& p) const
110 {
111 return mBuffers[p.index()] + p.offset();
112 }
113
114 void
clear()115 EncodedBuffer::clear()
116 {
117 mWp.rewind();
118 mEp.rewind();
119 }
120
121 /******************************** Write APIs ************************************************/
122 size_t
size() const123 EncodedBuffer::size() const
124 {
125 return mWp.pos();
126 }
127
128 EncodedBuffer::Pointer*
wp()129 EncodedBuffer::wp()
130 {
131 return &mWp;
132 }
133
134 uint8_t*
writeBuffer()135 EncodedBuffer::writeBuffer()
136 {
137 // This prevents write pointer move too fast than allocating the buffer.
138 if (mWp.index() > mBuffers.size()) return NULL;
139 uint8_t* buf = NULL;
140 if (mWp.index() == mBuffers.size()) {
141 // Use mmap instead of malloc to ensure memory alignment i.e. no fragmentation so that
142 // the mem region can be immediately reused by the allocator after calling munmap()
143 buf = (uint8_t*)mmap(NULL, mChunkSize, PROT_READ | PROT_WRITE,
144 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
145
146 if (buf == NULL) return NULL; // This indicates NO_MEMORY
147
148 mBuffers.push_back(buf);
149 }
150 return at(mWp);
151 }
152
153 size_t
currentToWrite()154 EncodedBuffer::currentToWrite()
155 {
156 return mChunkSize - mWp.offset();
157 }
158
159 void
writeRawByte(uint8_t val)160 EncodedBuffer::writeRawByte(uint8_t val)
161 {
162 *writeBuffer() = val;
163 mWp.move();
164 }
165
166 size_t
writeRawVarint64(uint64_t val)167 EncodedBuffer::writeRawVarint64(uint64_t val)
168 {
169 size_t size = 0;
170 while (true) {
171 size++;
172 if ((val & ~0x7F) == 0) {
173 writeRawByte((uint8_t) val);
174 return size;
175 } else {
176 writeRawByte((uint8_t)((val & 0x7F) | 0x80));
177 val >>= 7;
178 }
179 }
180 }
181
182 size_t
writeRawVarint32(uint32_t val)183 EncodedBuffer::writeRawVarint32(uint32_t val)
184 {
185 uint64_t v =(uint64_t)val;
186 return writeRawVarint64(v);
187 }
188
189 void
writeRawFixed32(uint32_t val)190 EncodedBuffer::writeRawFixed32(uint32_t val)
191 {
192 writeRawByte((uint8_t) val);
193 writeRawByte((uint8_t) (val>>8));
194 writeRawByte((uint8_t) (val>>16));
195 writeRawByte((uint8_t) (val>>24));
196 }
197
198 void
writeRawFixed64(uint64_t val)199 EncodedBuffer::writeRawFixed64(uint64_t val)
200 {
201 writeRawByte((uint8_t) val);
202 writeRawByte((uint8_t) (val>>8));
203 writeRawByte((uint8_t) (val>>16));
204 writeRawByte((uint8_t) (val>>24));
205 writeRawByte((uint8_t) (val>>32));
206 writeRawByte((uint8_t) (val>>40));
207 writeRawByte((uint8_t) (val>>48));
208 writeRawByte((uint8_t) (val>>56));
209 }
210
211 size_t
writeHeader(uint32_t fieldId,uint8_t wireType)212 EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
213 {
214 return writeRawVarint32((fieldId << FIELD_ID_SHIFT) | wireType);
215 }
216
217 status_t
writeRaw(uint8_t const * buf,size_t size)218 EncodedBuffer::writeRaw(uint8_t const* buf, size_t size)
219 {
220 while (size > 0) {
221 uint8_t* target = writeBuffer();
222 if (target == NULL) {
223 return -ENOMEM;
224 }
225 size_t chunk = currentToWrite();
226 if (chunk > size) {
227 chunk = size;
228 }
229 memcpy(target, buf, chunk);
230 size -= chunk;
231 buf += chunk;
232 mWp.move(chunk);
233 }
234 return NO_ERROR;
235 }
236
237 status_t
writeRaw(const sp<ProtoReader> & reader)238 EncodedBuffer::writeRaw(const sp<ProtoReader>& reader)
239 {
240 status_t err;
241 uint8_t const* buf;
242 while ((buf = reader->readBuffer()) != nullptr) {
243 size_t amt = reader->currentToRead();
244 err = writeRaw(buf, amt);
245 reader->move(amt);
246 if (err != NO_ERROR) {
247 return err;
248 }
249 }
250 return NO_ERROR;
251 }
252
253 status_t
writeRaw(const sp<ProtoReader> & reader,size_t size)254 EncodedBuffer::writeRaw(const sp<ProtoReader>& reader, size_t size)
255 {
256 status_t err;
257 uint8_t const* buf;
258 while (size > 0 && (buf = reader->readBuffer()) != nullptr) {
259 size_t amt = reader->currentToRead();
260 if (size < amt) {
261 amt = size;
262 }
263 err = writeRaw(buf, amt);
264 reader->move(amt);
265 size -= amt;
266 if (err != NO_ERROR) {
267 return err;
268 }
269 }
270 return size == 0 ? NO_ERROR : NOT_ENOUGH_DATA;
271 }
272
273
274 /******************************** Edit APIs ************************************************/
275 EncodedBuffer::Pointer*
ep()276 EncodedBuffer::ep()
277 {
278 return &mEp;
279 }
280
281 uint8_t
readRawByte()282 EncodedBuffer::readRawByte()
283 {
284 uint8_t val = *at(mEp);
285 mEp.move();
286 return val;
287 }
288
289 uint64_t
readRawVarint()290 EncodedBuffer::readRawVarint()
291 {
292 uint64_t val = 0, shift = 0;
293 size_t start = mEp.pos();
294 while (true) {
295 uint8_t byte = readRawByte();
296 val |= (UINT64_C(0x7F) & byte) << shift;
297 if ((byte & 0x80) == 0) break;
298 shift += 7;
299 }
300 return val;
301 }
302
303 uint32_t
readRawFixed32()304 EncodedBuffer::readRawFixed32()
305 {
306 uint32_t val = 0;
307 for (auto i=0; i<32; i+=8) {
308 val += (uint32_t)readRawByte() << i;
309 }
310 return val;
311 }
312
313 uint64_t
readRawFixed64()314 EncodedBuffer::readRawFixed64()
315 {
316 uint64_t val = 0;
317 for (auto i=0; i<64; i+=8) {
318 val += (uint64_t)readRawByte() << i;
319 }
320 return val;
321 }
322
323 void
editRawFixed32(size_t pos,uint32_t val)324 EncodedBuffer::editRawFixed32(size_t pos, uint32_t val)
325 {
326 size_t oldPos = mEp.pos();
327 mEp.rewind()->move(pos);
328 for (auto i=0; i<32; i+=8) {
329 *at(mEp) = (uint8_t) (val >> i);
330 mEp.move();
331 }
332 mEp.rewind()->move(oldPos);
333 }
334
335 void
copy(size_t srcPos,size_t size)336 EncodedBuffer::copy(size_t srcPos, size_t size)
337 {
338 if (size == 0) return;
339 Pointer cp(mChunkSize);
340 cp.move(srcPos);
341
342 while (cp.pos() < srcPos + size) {
343 writeRawByte(*at(cp));
344 cp.move();
345 }
346 }
347
348 /********************************* Read APIs ************************************************/
349 sp<ProtoReader>
read()350 EncodedBuffer::read()
351 {
352 return new EncodedBuffer::Reader(this);
353 }
354
Reader(const sp<EncodedBuffer> & buffer)355 EncodedBuffer::Reader::Reader(const sp<EncodedBuffer>& buffer)
356 :mData(buffer),
357 mRp(buffer->mChunkSize)
358 {
359 }
360
~Reader()361 EncodedBuffer::Reader::~Reader() {
362 }
363
364 ssize_t
size() const365 EncodedBuffer::Reader::size() const
366 {
367 return (ssize_t)mData->size();
368 }
369
370 size_t
bytesRead() const371 EncodedBuffer::Reader::bytesRead() const
372 {
373 return mRp.pos();
374 }
375
376 uint8_t const*
readBuffer()377 EncodedBuffer::Reader::readBuffer()
378 {
379 return hasNext() ? const_cast<uint8_t const*>(mData->at(mRp)) : NULL;
380 }
381
382 size_t
currentToRead()383 EncodedBuffer::Reader::currentToRead()
384 {
385 return (mData->mWp.index() > mRp.index()) ?
386 mData->mChunkSize - mRp.offset() :
387 mData->mWp.offset() - mRp.offset();
388 }
389
390 bool
hasNext()391 EncodedBuffer::Reader::hasNext()
392 {
393 return mRp.pos() < mData->mWp.pos();
394 }
395
396 uint8_t
next()397 EncodedBuffer::Reader::next()
398 {
399 uint8_t res = *(mData->at(mRp));
400 mRp.move();
401 return res;
402 }
403
404 uint64_t
readRawVarint()405 EncodedBuffer::Reader::readRawVarint()
406 {
407 uint64_t val = 0, shift = 0;
408 while (true) {
409 uint8_t byte = next();
410 val |= (INT64_C(0x7F) & byte) << shift;
411 if ((byte & 0x80) == 0) break;
412 shift += 7;
413 }
414 return val;
415 }
416
417 void
move(size_t amt)418 EncodedBuffer::Reader::move(size_t amt)
419 {
420 mRp.move(amt);
421 }
422
423 } // util
424 } // android
425