blob: 1e6de67a40ba80474ee9d1cfa08b83333ad2890c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2007 The Android Open Source Project
3 *
Mark Salyzyn00adb862014-03-19 11:00:06 -07004 * 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007 *
Mark Salyzyn00adb862014-03-19 11:00:06 -07008 * http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009 *
Mark Salyzyn00adb862014-03-19 11:00:06 -070010 * 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014 * limitations under the License.
15 */
16
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017#define LOG_TAG "CursorWindow"
18
Mathias Agopian49d2b182012-02-27 18:11:20 -080019#include <androidfw/CursorWindow.h>
Jeff Brown0cde89f2011-10-10 14:50:10 -070020
Jeff Brown0cde89f2011-10-10 14:50:10 -070021#include <sys/mman.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060023#include "android-base/logging.h"
24#include "cutils/ashmem.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026namespace android {
27
Jeff Sharkey539fdff2020-09-23 21:43:23 -060028/**
29 * By default windows are lightweight inline allocations of this size;
30 * they're only inflated to ashmem regions when more space is needed.
31 */
32static constexpr const size_t kInlineSize = 16384;
33
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060034static constexpr const size_t kSlotShift = 4;
35static constexpr const size_t kSlotSizeBytes = 1 << kSlotShift;
36
37CursorWindow::CursorWindow() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038}
39
Jeff Brown0cde89f2011-10-10 14:50:10 -070040CursorWindow::~CursorWindow() {
Jeff Sharkey539fdff2020-09-23 21:43:23 -060041 if (mAshmemFd != -1) {
42 ::munmap(mData, mSize);
43 ::close(mAshmemFd);
44 } else {
45 free(mData);
46 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047}
48
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060049status_t CursorWindow::create(const String8 &name, size_t inflatedSize, CursorWindow **outWindow) {
50 *outWindow = nullptr;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060051
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060052 CursorWindow* window = new CursorWindow();
53 if (!window) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060054
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060055 window->mName = name;
56 window->mSize = std::min(kInlineSize, inflatedSize);
57 window->mInflatedSize = inflatedSize;
58 window->mData = malloc(window->mSize);
59 if (!window->mData) goto fail;
60 window->mReadOnly = false;
61
62 window->clear();
63 window->updateSlotsData();
64
65 LOG(DEBUG) << "Created: " << window->toString();
66 *outWindow = window;
67 return OK;
68
69fail:
70 LOG(ERROR) << "Failed create";
71fail_silent:
Jeff Sharkey539fdff2020-09-23 21:43:23 -060072 delete window;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060073 return UNKNOWN_ERROR;
Jeff Sharkey539fdff2020-09-23 21:43:23 -060074}
75
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060076status_t CursorWindow::maybeInflate() {
77 int ashmemFd = 0;
78 void* newData = nullptr;
79
80 // Bail early when we can't expand any further
81 if (mReadOnly || mSize == mInflatedSize) {
82 return INVALID_OPERATION;
83 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -060084
Jeff Brown0cde89f2011-10-10 14:50:10 -070085 String8 ashmemName("CursorWindow: ");
Jeff Sharkey539fdff2020-09-23 21:43:23 -060086 ashmemName.append(mName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060088 ashmemFd = ashmem_create_region(ashmemName.string(), mInflatedSize);
Jeff Brown0cde89f2011-10-10 14:50:10 -070089 if (ashmemFd < 0) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060090 PLOG(ERROR) << "Failed ashmem_create_region";
91 goto fail_silent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -060093
94 if (ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE) < 0) {
95 PLOG(ERROR) << "Failed ashmem_set_prot_region";
96 goto fail_silent;
97 }
98
99 newData = ::mmap(nullptr, mInflatedSize, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
100 if (newData == MAP_FAILED) {
101 PLOG(ERROR) << "Failed mmap";
102 goto fail_silent;
103 }
104
105 if (ashmem_set_prot_region(ashmemFd, PROT_READ) < 0) {
106 PLOG(ERROR) << "Failed ashmem_set_prot_region";
107 goto fail_silent;
108 }
109
110 {
111 // Migrate existing contents into new ashmem region
112 uint32_t slotsSize = mSize - mSlotsOffset;
113 uint32_t newSlotsOffset = mInflatedSize - slotsSize;
114 memcpy(static_cast<uint8_t*>(newData),
115 static_cast<uint8_t*>(mData), mAllocOffset);
116 memcpy(static_cast<uint8_t*>(newData) + newSlotsOffset,
117 static_cast<uint8_t*>(mData) + mSlotsOffset, slotsSize);
118
119 free(mData);
120 mAshmemFd = ashmemFd;
121 mData = newData;
122 mSize = mInflatedSize;
123 mSlotsOffset = newSlotsOffset;
124
125 updateSlotsData();
126 }
127
128 LOG(DEBUG) << "Inflated: " << this->toString();
129 return OK;
130
131fail:
132 LOG(ERROR) << "Failed maybeInflate";
133fail_silent:
134 ::munmap(newData, mInflatedSize);
135 ::close(ashmemFd);
136 return UNKNOWN_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137}
138
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600139status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outWindow) {
140 *outWindow = nullptr;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700141
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600142 CursorWindow* window = new CursorWindow();
143 if (!window) goto fail;
144
145 if (parcel->readString8(&window->mName)) goto fail;
146 if (parcel->readUint32(&window->mNumRows)) goto fail;
147 if (parcel->readUint32(&window->mNumColumns)) goto fail;
148 if (parcel->readUint32(&window->mSize)) goto fail;
149
150 if ((window->mNumRows * window->mNumColumns * kSlotSizeBytes) > window->mSize) {
151 LOG(ERROR) << "Unexpected size " << window->mSize << " for " << window->mNumRows
152 << " rows and " << window->mNumColumns << " columns";
153 goto fail_silent;
154 }
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600155
156 bool isAshmem;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600157 if (parcel->readBool(&isAshmem)) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600158 if (isAshmem) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600159 window->mAshmemFd = parcel->readFileDescriptor();
160 if (window->mAshmemFd < 0) {
161 LOG(ERROR) << "Failed readFileDescriptor";
162 goto fail_silent;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700163 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600164
165 window->mAshmemFd = ::fcntl(window->mAshmemFd, F_DUPFD_CLOEXEC, 0);
166 if (window->mAshmemFd < 0) {
167 PLOG(ERROR) << "Failed F_DUPFD_CLOEXEC";
168 goto fail_silent;
169 }
170
171 window->mData = ::mmap(nullptr, window->mSize, PROT_READ, MAP_SHARED, window->mAshmemFd, 0);
172 if (window->mData == MAP_FAILED) {
173 PLOG(ERROR) << "Failed mmap";
174 goto fail_silent;
175 }
176 } else {
177 window->mAshmemFd = -1;
178
179 if (window->mSize > kInlineSize) {
180 LOG(ERROR) << "Unexpected size " << window->mSize << " for inline window";
181 goto fail_silent;
182 }
183
184 window->mData = malloc(window->mSize);
185 if (!window->mData) goto fail;
186
187 if (parcel->read(window->mData, window->mSize)) goto fail;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600190 // We just came from a remote source, so we're read-only
191 // and we can't inflate ourselves
192 window->mInflatedSize = window->mSize;
193 window->mReadOnly = true;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600194
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600195 window->updateSlotsData();
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600196
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600197 LOG(DEBUG) << "Created from parcel: " << window->toString();
198 *outWindow = window;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600199 return OK;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600200
201fail:
202 LOG(ERROR) << "Failed createFromParcel";
203fail_silent:
204 delete window;
205 return UNKNOWN_ERROR;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600206}
207
Jeff Brown0cde89f2011-10-10 14:50:10 -0700208status_t CursorWindow::writeToParcel(Parcel* parcel) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600209 LOG(DEBUG) << "Writing to parcel: " << this->toString();
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600210
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600211 if (parcel->writeString8(mName)) goto fail;
212 if (parcel->writeUint32(mNumRows)) goto fail;
213 if (parcel->writeUint32(mNumColumns)) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600214 if (mAshmemFd != -1) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600215 if (parcel->writeUint32(mSize)) goto fail;
216 if (parcel->writeBool(true)) goto fail;
217 if (parcel->writeDupFileDescriptor(mAshmemFd)) goto fail;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600218 } else {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600219 // Since we know we're going to be read-only on the remote side,
220 // we can compact ourselves on the wire, with just enough padding
221 // to ensure our slots stay aligned
222 size_t slotsSize = mSize - mSlotsOffset;
223 size_t compactedSize = mAllocOffset + slotsSize;
224 compactedSize = (compactedSize + 3) & ~3;
225 if (parcel->writeUint32(compactedSize)) goto fail;
226 if (parcel->writeBool(false)) goto fail;
227 void* dest = parcel->writeInplace(compactedSize);
228 if (!dest) goto fail;
229 memcpy(static_cast<uint8_t*>(dest),
230 static_cast<uint8_t*>(mData), mAllocOffset);
231 memcpy(static_cast<uint8_t*>(dest) + compactedSize - slotsSize,
232 static_cast<uint8_t*>(mData) + mSlotsOffset, slotsSize);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700233 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600234 return OK;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600235
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600236fail:
237 LOG(ERROR) << "Failed writeToParcel";
238fail_silent:
239 return UNKNOWN_ERROR;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700240}
241
242status_t CursorWindow::clear() {
243 if (mReadOnly) {
244 return INVALID_OPERATION;
245 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600246 mAllocOffset = 0;
247 mSlotsOffset = mSize;
248 mNumRows = 0;
249 mNumColumns = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700250 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251}
252
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600253void CursorWindow::updateSlotsData() {
254 mSlotsData = static_cast<uint8_t*>(mData) + mSize - kSlotSizeBytes;
255}
256
257void* CursorWindow::offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) {
258 if (offset > mSize) {
259 LOG(ERROR) << "Offset " << offset
260 << " out of bounds, max value " << mSize;
261 return nullptr;
262 }
263 if (offset + bufferSize > mSize) {
264 LOG(ERROR) << "End offset " << (offset + bufferSize)
265 << " out of bounds, max value " << mSize;
266 return nullptr;
267 }
268 return static_cast<uint8_t*>(mData) + offset;
269}
270
271uint32_t CursorWindow::offsetFromPtr(void* ptr) {
272 return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData);
273}
274
Jeff Brown0cde89f2011-10-10 14:50:10 -0700275status_t CursorWindow::setNumColumns(uint32_t numColumns) {
276 if (mReadOnly) {
277 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600279 uint32_t cur = mNumColumns;
280 if ((cur > 0 || mNumRows > 0) && cur != numColumns) {
281 LOG(ERROR) << "Trying to go from " << cur << " columns to " << numColumns;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700282 return INVALID_OPERATION;
283 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600284 mNumColumns = numColumns;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700285 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286}
287
Jeff Brown0cde89f2011-10-10 14:50:10 -0700288status_t CursorWindow::allocRow() {
289 if (mReadOnly) {
290 return INVALID_OPERATION;
291 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600292 size_t size = mNumColumns * kSlotSizeBytes;
293 off_t newOffset = mSlotsOffset - size;
294 if (newOffset < mAllocOffset) {
295 maybeInflate();
296 newOffset = mSlotsOffset - size;
297 if (newOffset < mAllocOffset) {
298 return NO_MEMORY;
299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600301 memset(offsetToPtr(newOffset), 0, size);
302 mSlotsOffset = newOffset;
303 mNumRows++;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700304 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305}
306
Jeff Brown0cde89f2011-10-10 14:50:10 -0700307status_t CursorWindow::freeLastRow() {
308 if (mReadOnly) {
309 return INVALID_OPERATION;
310 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600311 size_t size = mNumColumns * kSlotSizeBytes;
312 off_t newOffset = mSlotsOffset + size;
313 if (newOffset > mSize) {
314 return NO_MEMORY;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700315 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600316 mSlotsOffset = newOffset;
317 mNumRows--;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700318 return OK;
319}
320
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600321status_t CursorWindow::alloc(size_t size, uint32_t* outOffset) {
322 if (mReadOnly) {
323 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600325 size_t alignedSize = (size + 3) & ~3;
326 off_t newOffset = mAllocOffset + alignedSize;
327 if (newOffset > mSlotsOffset) {
328 maybeInflate();
329 newOffset = mAllocOffset + alignedSize;
330 if (newOffset > mSlotsOffset) {
331 return NO_MEMORY;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600334 *outOffset = mAllocOffset;
335 mAllocOffset = newOffset;
336 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337}
338
Jeff Brown0cde89f2011-10-10 14:50:10 -0700339CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600340 if (row >= mNumRows || column >= mNumColumns) {
341 LOG(ERROR) << "Failed to read row " << row << ", column " << column
342 << " from a window with " << mNumRows << " rows, " << mNumColumns << " columns";
343 return nullptr;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700344 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600345
346 // This is carefully tuned to use as few cycles as
347 // possible, since this is an extremely hot code path;
348 // see CursorWindow_bench.cpp for more details
349 void *result = static_cast<uint8_t*>(mSlotsData)
350 - (((row * mNumColumns) + column) << kSlotShift);
351 return static_cast<FieldSlot*>(result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352}
353
Jeff Brown0cde89f2011-10-10 14:50:10 -0700354status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) {
355 return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356}
357
Jeff Brown0cde89f2011-10-10 14:50:10 -0700358status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
359 size_t sizeIncludingNull) {
360 return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361}
362
Jeff Brown0cde89f2011-10-10 14:50:10 -0700363status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
364 const void* value, size_t size, int32_t type) {
365 if (mReadOnly) {
366 return INVALID_OPERATION;
367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368
Jeff Brown0cde89f2011-10-10 14:50:10 -0700369 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700371 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
373
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600374 uint32_t offset;
375 if (alloc(size, &offset)) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700376 return NO_MEMORY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 }
378
Jeff Brown0cde89f2011-10-10 14:50:10 -0700379 memcpy(offsetToPtr(offset), value, size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600381 fieldSlot = getFieldSlot(row, column);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700382 fieldSlot->type = type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 fieldSlot->data.buffer.offset = offset;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700384 fieldSlot->data.buffer.size = size;
385 return OK;
386}
387
388status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) {
389 if (mReadOnly) {
390 return INVALID_OPERATION;
391 }
392
393 FieldSlot* fieldSlot = getFieldSlot(row, column);
394 if (!fieldSlot) {
395 return BAD_VALUE;
396 }
397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 fieldSlot->type = FIELD_TYPE_INTEGER;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700399 fieldSlot->data.l = value;
400 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401}
402
Jeff Brown0cde89f2011-10-10 14:50:10 -0700403status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) {
404 if (mReadOnly) {
405 return INVALID_OPERATION;
406 }
407
408 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700410 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 }
412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 fieldSlot->type = FIELD_TYPE_FLOAT;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700414 fieldSlot->data.d = value;
415 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416}
417
Jeff Brown0cde89f2011-10-10 14:50:10 -0700418status_t CursorWindow::putNull(uint32_t row, uint32_t column) {
419 if (mReadOnly) {
420 return INVALID_OPERATION;
421 }
422
423 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700425 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 }
427
428 fieldSlot->type = FIELD_TYPE_NULL;
429 fieldSlot->data.buffer.offset = 0;
430 fieldSlot->data.buffer.size = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700431 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432}
433
434}; // namespace android