Yi Jin | 99c248f | 2017-08-25 18:11:58 -0700 | [diff] [blame^] | 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 | |
| 17 | #include "EncodedBuffer.h" |
| 18 | #include "io_util.h" |
| 19 | #include "protobuf.h" |
| 20 | |
| 21 | #include <deque> |
| 22 | |
| 23 | const size_t BUFFER_SIZE = 4 * 1024; // 4 KB |
| 24 | |
| 25 | /** |
| 26 | * Read varint from iterator, the iterator will point to next available byte. |
| 27 | * Return the number of bytes of the varint. |
| 28 | */ |
| 29 | static uint32_t |
| 30 | read_raw_varint(FdBuffer::iterator& it) |
| 31 | { |
| 32 | uint32_t val = 0; |
| 33 | int i = 0; |
| 34 | bool hasNext = true; |
| 35 | while (hasNext) { |
| 36 | hasNext = ((*it & 0x80) != 0); |
| 37 | val += (*it & 0x7F) << (7*i); |
| 38 | it++; |
| 39 | i++; |
| 40 | } |
| 41 | return val; |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * Write the field to buf based on the wire type, iterator will point to next field. |
| 46 | * If skip is set to true, no data will be written to buf. Return number of bytes written. |
| 47 | */ |
| 48 | static size_t |
| 49 | write_field_or_skip(FdBuffer::iterator &iterator, vector<uint8_t> &buf, uint8_t wireType, bool skip) |
| 50 | { |
| 51 | FdBuffer::iterator snapshot = iterator.snapshot(); |
| 52 | size_t bytesToWrite = 0; |
| 53 | uint32_t varint = 0; |
| 54 | switch (wireType) { |
| 55 | case WIRE_TYPE_VARINT: |
| 56 | varint = read_raw_varint(iterator); |
| 57 | if(!skip) return write_raw_varint(buf, varint); |
| 58 | break; |
| 59 | case WIRE_TYPE_FIXED64: |
| 60 | bytesToWrite = 8; |
| 61 | break; |
| 62 | case WIRE_TYPE_LENGTH_DELIMITED: |
| 63 | bytesToWrite = read_raw_varint(iterator); |
| 64 | if(!skip) write_raw_varint(buf, bytesToWrite); |
| 65 | break; |
| 66 | case WIRE_TYPE_FIXED32: |
| 67 | bytesToWrite = 4; |
| 68 | break; |
| 69 | } |
| 70 | if (skip) { |
| 71 | iterator += bytesToWrite; |
| 72 | } else { |
| 73 | buf.reserve(bytesToWrite); |
| 74 | for (size_t i=0; i<bytesToWrite; i++) { |
| 75 | buf.push_back(*iterator); |
| 76 | iterator++; |
| 77 | } |
| 78 | } |
| 79 | return skip ? 0 : iterator - snapshot; |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * Strip next field based on its private policy and request spec, then stores data in buf. |
| 84 | * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in FdBuffer. |
| 85 | * |
| 86 | * The iterator must point to the head of a protobuf formatted field for successful operation. |
| 87 | * After exit with NO_ERROR, iterator points to the next protobuf field's head. |
| 88 | */ |
| 89 | static status_t |
| 90 | stripField(FdBuffer::iterator &iterator, vector<uint8_t> &buf, const Privacy* parentPolicy, const PrivacySpec& spec) |
| 91 | { |
| 92 | if (iterator.outOfBound() || parentPolicy == NULL) return BAD_VALUE; |
| 93 | |
| 94 | uint32_t varint = read_raw_varint(iterator); |
| 95 | uint8_t wireType = read_wire_type(varint); |
| 96 | uint32_t fieldId = read_field_id(varint); |
| 97 | const Privacy* policy = parentPolicy->lookup(fieldId); |
| 98 | |
| 99 | if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) { |
| 100 | bool skip = !spec.CheckPremission(policy); |
| 101 | size_t amt = buf.size(); |
| 102 | if (!skip) amt += write_header(buf, fieldId, wireType); |
| 103 | amt += write_field_or_skip(iterator, buf, wireType, skip); // point to head of next field |
| 104 | return buf.size() != amt ? BAD_VALUE : NO_ERROR; |
| 105 | } |
| 106 | // current field is message type and its sub-fields have extra privacy policies |
| 107 | deque<vector<uint8_t>> q; |
| 108 | uint32_t msgSize = read_raw_varint(iterator); |
| 109 | size_t finalSize = 0; |
| 110 | FdBuffer::iterator start = iterator.snapshot(); |
| 111 | while ((iterator - start) != (int)msgSize) { |
| 112 | vector<uint8_t> v; |
| 113 | status_t err = stripField(iterator, v, policy, spec); |
| 114 | if (err != NO_ERROR) return err; |
| 115 | if (v.empty()) continue; |
| 116 | q.push_back(v); |
| 117 | finalSize += v.size(); |
| 118 | } |
| 119 | |
| 120 | write_header(buf, fieldId, wireType); |
| 121 | write_raw_varint(buf, finalSize); |
| 122 | buf.reserve(finalSize); |
| 123 | while (!q.empty()) { |
| 124 | vector<uint8_t> subField = q.front(); |
| 125 | for (vector<uint8_t>::iterator it = subField.begin(); it != subField.end(); it++) { |
| 126 | buf.push_back(*it); |
| 127 | } |
| 128 | q.pop_front(); |
| 129 | } |
| 130 | return NO_ERROR; |
| 131 | } |
| 132 | |
| 133 | // ================================================================================ |
| 134 | EncodedBuffer::EncodedBuffer(const FdBuffer& buffer, const Privacy* policy) |
| 135 | : mFdBuffer(buffer), |
| 136 | mPolicy(policy), |
| 137 | mBuffers(), |
| 138 | mSize(0) |
| 139 | { |
| 140 | } |
| 141 | |
| 142 | EncodedBuffer::~EncodedBuffer() |
| 143 | { |
| 144 | } |
| 145 | |
| 146 | status_t |
| 147 | EncodedBuffer::strip(const PrivacySpec& spec) |
| 148 | { |
| 149 | // optimization when no strip happens |
| 150 | if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) { |
| 151 | if (spec.CheckPremission(mPolicy)) mSize = mFdBuffer.size(); |
| 152 | return NO_ERROR; |
| 153 | } |
| 154 | |
| 155 | FdBuffer::iterator it = mFdBuffer.begin(); |
| 156 | vector<uint8_t> field; |
| 157 | field.reserve(BUFFER_SIZE); |
| 158 | |
| 159 | while (it != mFdBuffer.end()) { |
| 160 | status_t err = stripField(it, field, mPolicy, spec); |
| 161 | if (err != NO_ERROR) return err; |
| 162 | if (field.size() > BUFFER_SIZE) { // rotate to another chunk if buffer size exceeds |
| 163 | mBuffers.push_back(field); |
| 164 | mSize += field.size(); |
| 165 | field.clear(); |
| 166 | } |
| 167 | } |
| 168 | if (!field.empty()) { |
| 169 | mBuffers.push_back(field); |
| 170 | mSize += field.size(); |
| 171 | } |
| 172 | return NO_ERROR; |
| 173 | } |
| 174 | |
| 175 | void |
| 176 | EncodedBuffer::clear() |
| 177 | { |
| 178 | mSize = 0; |
| 179 | mBuffers.clear(); |
| 180 | } |
| 181 | |
| 182 | size_t |
| 183 | EncodedBuffer::size() const { return mSize; } |
| 184 | |
| 185 | status_t |
| 186 | EncodedBuffer::flush(int fd) |
| 187 | { |
| 188 | if (size() == mFdBuffer.size()) return mFdBuffer.flush(fd); |
| 189 | |
| 190 | for (vector<vector<uint8_t>>::iterator it = mBuffers.begin(); it != mBuffers.end(); it++) { |
| 191 | status_t err = write_all(fd, it->data(), it->size()); |
| 192 | if (err != NO_ERROR) return err; |
| 193 | } |
| 194 | return NO_ERROR; |
| 195 | } |