blob: 915c0d75a2803f81f56303cbc8ef03752e364ce9 [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() {
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600254 mSlotsStart = static_cast<uint8_t*>(mData) + mSize - kSlotSizeBytes;
255 mSlotsEnd = static_cast<uint8_t*>(mData) + mSlotsOffset;
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600256}
257
258void* CursorWindow::offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) {
259 if (offset > mSize) {
260 LOG(ERROR) << "Offset " << offset
261 << " out of bounds, max value " << mSize;
262 return nullptr;
263 }
264 if (offset + bufferSize > mSize) {
265 LOG(ERROR) << "End offset " << (offset + bufferSize)
266 << " out of bounds, max value " << mSize;
267 return nullptr;
268 }
269 return static_cast<uint8_t*>(mData) + offset;
270}
271
272uint32_t CursorWindow::offsetFromPtr(void* ptr) {
273 return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData);
274}
275
Jeff Brown0cde89f2011-10-10 14:50:10 -0700276status_t CursorWindow::setNumColumns(uint32_t numColumns) {
277 if (mReadOnly) {
278 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600280 uint32_t cur = mNumColumns;
281 if ((cur > 0 || mNumRows > 0) && cur != numColumns) {
282 LOG(ERROR) << "Trying to go from " << cur << " columns to " << numColumns;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700283 return INVALID_OPERATION;
284 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600285 mNumColumns = numColumns;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700286 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287}
288
Jeff Brown0cde89f2011-10-10 14:50:10 -0700289status_t CursorWindow::allocRow() {
290 if (mReadOnly) {
291 return INVALID_OPERATION;
292 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600293 size_t size = mNumColumns * kSlotSizeBytes;
294 off_t newOffset = mSlotsOffset - size;
295 if (newOffset < mAllocOffset) {
296 maybeInflate();
297 newOffset = mSlotsOffset - size;
298 if (newOffset < mAllocOffset) {
299 return NO_MEMORY;
300 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600302 memset(offsetToPtr(newOffset), 0, size);
303 mSlotsOffset = newOffset;
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600304 updateSlotsData();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600305 mNumRows++;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700306 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307}
308
Jeff Brown0cde89f2011-10-10 14:50:10 -0700309status_t CursorWindow::freeLastRow() {
310 if (mReadOnly) {
311 return INVALID_OPERATION;
312 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600313 size_t size = mNumColumns * kSlotSizeBytes;
314 off_t newOffset = mSlotsOffset + size;
315 if (newOffset > mSize) {
316 return NO_MEMORY;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700317 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600318 mSlotsOffset = newOffset;
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600319 updateSlotsData();
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600320 mNumRows--;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700321 return OK;
322}
323
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600324status_t CursorWindow::alloc(size_t size, uint32_t* outOffset) {
325 if (mReadOnly) {
326 return INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600328 size_t alignedSize = (size + 3) & ~3;
329 off_t newOffset = mAllocOffset + alignedSize;
330 if (newOffset > mSlotsOffset) {
331 maybeInflate();
332 newOffset = mAllocOffset + alignedSize;
333 if (newOffset > mSlotsOffset) {
334 return NO_MEMORY;
Jeff Sharkey539fdff2020-09-23 21:43:23 -0600335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600337 *outOffset = mAllocOffset;
338 mAllocOffset = newOffset;
339 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340}
341
Jeff Brown0cde89f2011-10-10 14:50:10 -0700342CursorWindow::FieldSlot* CursorWindow::getFieldSlot(uint32_t row, uint32_t column) {
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600343 // This is carefully tuned to use as few cycles as
344 // possible, since this is an extremely hot code path;
345 // see CursorWindow_bench.cpp for more details
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600346 void *result = static_cast<uint8_t*>(mSlotsStart)
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600347 - (((row * mNumColumns) + column) << kSlotShift);
Jeff Sharkey256da5a2020-10-13 09:40:52 -0600348 if (result < mSlotsEnd || column >= mNumColumns) {
349 LOG(ERROR) << "Failed to read row " << row << ", column " << column
350 << " from a window with " << mNumRows << " rows, " << mNumColumns << " columns";
351 return nullptr;
352 } else {
353 return static_cast<FieldSlot*>(result);
354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355}
356
Jeff Brown0cde89f2011-10-10 14:50:10 -0700357status_t CursorWindow::putBlob(uint32_t row, uint32_t column, const void* value, size_t size) {
358 return putBlobOrString(row, column, value, size, FIELD_TYPE_BLOB);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359}
360
Jeff Brown0cde89f2011-10-10 14:50:10 -0700361status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
362 size_t sizeIncludingNull) {
363 return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364}
365
Jeff Brown0cde89f2011-10-10 14:50:10 -0700366status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
367 const void* value, size_t size, int32_t type) {
368 if (mReadOnly) {
369 return INVALID_OPERATION;
370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371
Jeff Brown0cde89f2011-10-10 14:50:10 -0700372 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700374 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600377 uint32_t offset;
378 if (alloc(size, &offset)) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700379 return NO_MEMORY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
381
Jeff Brown0cde89f2011-10-10 14:50:10 -0700382 memcpy(offsetToPtr(offset), value, size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383
Jeff Sharkeyae2d88a2020-09-26 18:57:32 -0600384 fieldSlot = getFieldSlot(row, column);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700385 fieldSlot->type = type;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 fieldSlot->data.buffer.offset = offset;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700387 fieldSlot->data.buffer.size = size;
388 return OK;
389}
390
391status_t CursorWindow::putLong(uint32_t row, uint32_t column, int64_t value) {
392 if (mReadOnly) {
393 return INVALID_OPERATION;
394 }
395
396 FieldSlot* fieldSlot = getFieldSlot(row, column);
397 if (!fieldSlot) {
398 return BAD_VALUE;
399 }
400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 fieldSlot->type = FIELD_TYPE_INTEGER;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700402 fieldSlot->data.l = value;
403 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404}
405
Jeff Brown0cde89f2011-10-10 14:50:10 -0700406status_t CursorWindow::putDouble(uint32_t row, uint32_t column, double value) {
407 if (mReadOnly) {
408 return INVALID_OPERATION;
409 }
410
411 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700413 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 }
415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 fieldSlot->type = FIELD_TYPE_FLOAT;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700417 fieldSlot->data.d = value;
418 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419}
420
Jeff Brown0cde89f2011-10-10 14:50:10 -0700421status_t CursorWindow::putNull(uint32_t row, uint32_t column) {
422 if (mReadOnly) {
423 return INVALID_OPERATION;
424 }
425
426 FieldSlot* fieldSlot = getFieldSlot(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 if (!fieldSlot) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700428 return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 }
430
431 fieldSlot->type = FIELD_TYPE_NULL;
432 fieldSlot->data.buffer.offset = 0;
433 fieldSlot->data.buffer.size = 0;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700434 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435}
436
437}; // namespace android