1 /* 2 * Copyright (C) 2006 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 #ifndef _ANDROID__DATABASE_WINDOW_H 18 #define _ANDROID__DATABASE_WINDOW_H 19 20 #include <inttypes.h> 21 #include <stddef.h> 22 #include <stdint.h> 23 #include <string> 24 25 #include "android-base/stringprintf.h" 26 #include "binder/Parcel.h" 27 #include "utils/String8.h" 28 29 #define LOG_WINDOW(...) 30 31 namespace android { 32 33 /** 34 * This class stores a set of rows from a database in a buffer. Internally 35 * data is structured as a "heap" of string/blob allocations at the bottom 36 * of the memory region, and a "stack" of FieldSlot allocations at the top 37 * of the memory region. Here's an example visual representation: 38 * 39 * +----------------------------------------------------------------+ 40 * |heap\0of\0strings\0 222211110000| ... 41 * +-------------------+--------------------------------+-------+---+ 42 * ^ ^ ^ ^ ^ ^ 43 * | | | | | | 44 * | +- mAllocOffset mSlotsOffset -+ | | | 45 * +- mData mSlotsStart -+ | | 46 * mSize -+ | 47 * mInflatedSize -+ 48 * 49 * Strings are stored in UTF-8. 50 */ 51 class CursorWindow { 52 CursorWindow(); 53 54 public: 55 /* Field types. */ 56 enum { 57 FIELD_TYPE_NULL = 0, 58 FIELD_TYPE_INTEGER = 1, 59 FIELD_TYPE_FLOAT = 2, 60 FIELD_TYPE_STRING = 3, 61 FIELD_TYPE_BLOB = 4, 62 }; 63 64 /* Opaque type that describes a field slot. */ 65 struct FieldSlot { 66 private: 67 int32_t type; 68 union { 69 double d; 70 int64_t l; 71 struct { 72 uint32_t offset; 73 uint32_t size; 74 } buffer; 75 } data; 76 77 friend class CursorWindow; 78 } __attribute((packed)); 79 80 ~CursorWindow(); 81 82 static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow); 83 static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow); 84 85 status_t writeToParcel(Parcel* parcel); 86 name()87 inline String8 name() { return mName; } size()88 inline size_t size() { return mSize; } freeSpace()89 inline size_t freeSpace() { return mSlotsOffset - mAllocOffset; } getNumRows()90 inline uint32_t getNumRows() { return mNumRows; } getNumColumns()91 inline uint32_t getNumColumns() { return mNumColumns; } 92 sizeOfSlots()93 inline size_t sizeOfSlots() const { return mSize - mSlotsOffset; } sizeInUse()94 inline size_t sizeInUse() const { return mAllocOffset + sizeOfSlots(); } 95 96 status_t clear(); 97 status_t setNumColumns(uint32_t numColumns); 98 99 /** 100 * Allocate a row slot and its directory. 101 * The row is initialized will null entries for each field. 102 */ 103 status_t allocRow(); 104 status_t freeLastRow(); 105 106 status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size); 107 status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull); 108 status_t putLong(uint32_t row, uint32_t column, int64_t value); 109 status_t putDouble(uint32_t row, uint32_t column, double value); 110 status_t putNull(uint32_t row, uint32_t column); 111 112 /** 113 * Gets the field slot at the specified row and column. 114 * Returns null if the requested row or column is not in the window. 115 */ 116 FieldSlot* getFieldSlot(uint32_t row, uint32_t column); 117 getFieldSlotType(FieldSlot * fieldSlot)118 inline int32_t getFieldSlotType(FieldSlot* fieldSlot) { 119 return fieldSlot->type; 120 } 121 getFieldSlotValueLong(FieldSlot * fieldSlot)122 inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) { 123 return fieldSlot->data.l; 124 } 125 getFieldSlotValueDouble(FieldSlot * fieldSlot)126 inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) { 127 return fieldSlot->data.d; 128 } 129 getFieldSlotValueString(FieldSlot * fieldSlot,size_t * outSizeIncludingNull)130 inline const char* getFieldSlotValueString(FieldSlot* fieldSlot, 131 size_t* outSizeIncludingNull) { 132 *outSizeIncludingNull = fieldSlot->data.buffer.size; 133 return static_cast<char*>(offsetToPtr( 134 fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size)); 135 } 136 getFieldSlotValueBlob(FieldSlot * fieldSlot,size_t * outSize)137 inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) { 138 *outSize = fieldSlot->data.buffer.size; 139 return offsetToPtr(fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size); 140 } 141 toString()142 inline std::string toString() const { 143 return android::base::StringPrintf("CursorWindow{name=%s, fd=%d, size=%d, inflatedSize=%d, " 144 "allocOffset=%d, slotsOffset=%d, numRows=%d, numColumns=%d}", mName.c_str(), 145 mAshmemFd, mSize, mInflatedSize, mAllocOffset, mSlotsOffset, mNumRows, mNumColumns); 146 } 147 148 private: 149 String8 mName; 150 int mAshmemFd = -1; 151 void* mData = nullptr; 152 /** 153 * Pointer to the first FieldSlot, used to optimize the extremely 154 * hot code path of getFieldSlot(). 155 */ 156 void* mSlotsStart = nullptr; 157 void* mSlotsEnd = nullptr; 158 uint32_t mSize = 0; 159 /** 160 * When a window starts as lightweight inline allocation, this value 161 * holds the "full" size to be created after ashmem inflation. 162 */ 163 uint32_t mInflatedSize = 0; 164 /** 165 * Offset to the top of the "heap" of string/blob allocations. By 166 * storing these allocations at the bottom of our memory region we 167 * avoid having to rewrite offsets when inflating. 168 */ 169 uint32_t mAllocOffset = 0; 170 /** 171 * Offset to the bottom of the "stack" of FieldSlot allocations. 172 */ 173 uint32_t mSlotsOffset = 0; 174 uint32_t mNumRows = 0; 175 uint32_t mNumColumns = 0; 176 bool mReadOnly = false; 177 178 void updateSlotsData(); 179 180 void* offsetToPtr(uint32_t offset, uint32_t bufferSize); 181 uint32_t offsetFromPtr(void* ptr); 182 183 /** 184 * By default windows are lightweight inline allocations; this method 185 * inflates the window into a larger ashmem region. 186 */ 187 status_t maybeInflate(); 188 189 /** 190 * Allocate a portion of the window. 191 */ 192 status_t alloc(size_t size, uint32_t* outOffset); 193 194 status_t putBlobOrString(uint32_t row, uint32_t column, 195 const void* value, size_t size, int32_t type); 196 }; 197 198 }; // namespace android 199 200 #endif 201