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