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