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