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 93 status_t clear(); 94 status_t setNumColumns(uint32_t numColumns); 95 96 /** 97 * Allocate a row slot and its directory. 98 * The row is initialized will null entries for each field. 99 */ 100 status_t allocRow(); 101 status_t freeLastRow(); 102 103 status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size); 104 status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull); 105 status_t putLong(uint32_t row, uint32_t column, int64_t value); 106 status_t putDouble(uint32_t row, uint32_t column, double value); 107 status_t putNull(uint32_t row, uint32_t column); 108 109 /** 110 * Gets the field slot at the specified row and column. 111 * Returns null if the requested row or column is not in the window. 112 */ 113 FieldSlot* getFieldSlot(uint32_t row, uint32_t column); 114 getFieldSlotType(FieldSlot * fieldSlot)115 inline int32_t getFieldSlotType(FieldSlot* fieldSlot) { 116 return fieldSlot->type; 117 } 118 getFieldSlotValueLong(FieldSlot * fieldSlot)119 inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) { 120 return fieldSlot->data.l; 121 } 122 getFieldSlotValueDouble(FieldSlot * fieldSlot)123 inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) { 124 return fieldSlot->data.d; 125 } 126 getFieldSlotValueString(FieldSlot * fieldSlot,size_t * outSizeIncludingNull)127 inline const char* getFieldSlotValueString(FieldSlot* fieldSlot, 128 size_t* outSizeIncludingNull) { 129 *outSizeIncludingNull = fieldSlot->data.buffer.size; 130 return static_cast<char*>(offsetToPtr( 131 fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size)); 132 } 133 getFieldSlotValueBlob(FieldSlot * fieldSlot,size_t * outSize)134 inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) { 135 *outSize = fieldSlot->data.buffer.size; 136 return offsetToPtr(fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size); 137 } 138 toString()139 inline std::string toString() const { 140 return android::base::StringPrintf("CursorWindow{name=%s, fd=%d, size=%d, inflatedSize=%d, " 141 "allocOffset=%d, slotsOffset=%d, numRows=%d, numColumns=%d}", mName.c_str(), 142 mAshmemFd, mSize, mInflatedSize, mAllocOffset, mSlotsOffset, mNumRows, mNumColumns); 143 } 144 145 private: 146 String8 mName; 147 int mAshmemFd = -1; 148 void* mData = nullptr; 149 /** 150 * Pointer to the first FieldSlot, used to optimize the extremely 151 * hot code path of getFieldSlot(). 152 */ 153 void* mSlotsStart = nullptr; 154 void* mSlotsEnd = nullptr; 155 uint32_t mSize = 0; 156 /** 157 * When a window starts as lightweight inline allocation, this value 158 * holds the "full" size to be created after ashmem inflation. 159 */ 160 uint32_t mInflatedSize = 0; 161 /** 162 * Offset to the top of the "heap" of string/blob allocations. By 163 * storing these allocations at the bottom of our memory region we 164 * avoid having to rewrite offsets when inflating. 165 */ 166 uint32_t mAllocOffset = 0; 167 /** 168 * Offset to the bottom of the "stack" of FieldSlot allocations. 169 */ 170 uint32_t mSlotsOffset = 0; 171 uint32_t mNumRows = 0; 172 uint32_t mNumColumns = 0; 173 bool mReadOnly = false; 174 175 void updateSlotsData(); 176 177 void* offsetToPtr(uint32_t offset, uint32_t bufferSize); 178 uint32_t offsetFromPtr(void* ptr); 179 180 /** 181 * By default windows are lightweight inline allocations; this method 182 * inflates the window into a larger ashmem region. 183 */ 184 status_t maybeInflate(); 185 186 /** 187 * Allocate a portion of the window. 188 */ 189 status_t alloc(size_t size, uint32_t* outOffset); 190 191 status_t putBlobOrString(uint32_t row, uint32_t column, 192 const void* value, size_t size, int32_t type); 193 }; 194 195 }; // namespace android 196 197 #endif 198