summaryrefslogtreecommitdiff
path: root/libs/androidfw/include/androidfw/CursorWindow.h
blob: 6e55a9a0eb8b9ed739ed8ce890cf02055405378b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _ANDROID__DATABASE_WINDOW_H
#define _ANDROID__DATABASE_WINDOW_H

#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <string>

#include "android-base/stringprintf.h"
#include "binder/Parcel.h"
#include "utils/String8.h"

#define LOG_WINDOW(...)

namespace android {

/**
 * This class stores a set of rows from a database in a buffer. Internally
 * data is structured as a "heap" of string/blob allocations at the bottom
 * of the memory region, and a "stack" of FieldSlot allocations at the top
 * of the memory region. Here's an example visual representation:
 *
 *   +----------------------------------------------------------------+
 *   |heap\0of\0strings\0                                 222211110000| ...
 *   +-------------------+--------------------------------+-------+---+
 *    ^                  ^                                ^       ^   ^     ^
 *    |                  |                                |       |   |     |
 *    |                  +- mAllocOffset    mSlotsOffset -+       |   |     |
 *    +- mData                                       mSlotsStart -+   |     |
 *                                                             mSize -+     |
 *                                                           mInflatedSize -+
 *
 * Strings are stored in UTF-8.
 */
class CursorWindow {
    CursorWindow();

public:
    /* Field types. */
    enum {
        FIELD_TYPE_NULL = 0,
        FIELD_TYPE_INTEGER = 1,
        FIELD_TYPE_FLOAT = 2,
        FIELD_TYPE_STRING = 3,
        FIELD_TYPE_BLOB = 4,
    };

    /* Opaque type that describes a field slot. */
    struct FieldSlot {
    private:
        int32_t type;
        union {
            double d;
            int64_t l;
            struct {
                uint32_t offset;
                uint32_t size;
            } buffer;
        } data;

        friend class CursorWindow;
    } __attribute((packed));

    ~CursorWindow();

    static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow);
    static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);

    status_t writeToParcel(Parcel* parcel);

    inline String8 name() { return mName; }
    inline size_t size() { return mSize; }
    inline size_t freeSpace() { return mSlotsOffset - mAllocOffset; }
    inline uint32_t getNumRows() { return mNumRows; }
    inline uint32_t getNumColumns() { return mNumColumns; }

    status_t clear();
    status_t setNumColumns(uint32_t numColumns);

    /**
     * Allocate a row slot and its directory.
     * The row is initialized will null entries for each field.
     */
    status_t allocRow();
    status_t freeLastRow();

    status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size);
    status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull);
    status_t putLong(uint32_t row, uint32_t column, int64_t value);
    status_t putDouble(uint32_t row, uint32_t column, double value);
    status_t putNull(uint32_t row, uint32_t column);

    /**
     * Gets the field slot at the specified row and column.
     * Returns null if the requested row or column is not in the window.
     */
    FieldSlot* getFieldSlot(uint32_t row, uint32_t column);

    inline int32_t getFieldSlotType(FieldSlot* fieldSlot) {
        return fieldSlot->type;
    }

    inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) {
        return fieldSlot->data.l;
    }

    inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) {
        return fieldSlot->data.d;
    }

    inline const char* getFieldSlotValueString(FieldSlot* fieldSlot,
            size_t* outSizeIncludingNull) {
        *outSizeIncludingNull = fieldSlot->data.buffer.size;
        return static_cast<char*>(offsetToPtr(
                fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size));
    }

    inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) {
        *outSize = fieldSlot->data.buffer.size;
        return offsetToPtr(fieldSlot->data.buffer.offset, fieldSlot->data.buffer.size);
    }

    inline std::string toString() const {
        return android::base::StringPrintf("CursorWindow{name=%s, fd=%d, size=%d, inflatedSize=%d, "
                "allocOffset=%d, slotsOffset=%d, numRows=%d, numColumns=%d}", mName.c_str(),
                mAshmemFd, mSize, mInflatedSize, mAllocOffset, mSlotsOffset, mNumRows, mNumColumns);
    }

private:
    String8 mName;
    int mAshmemFd = -1;
    void* mData = nullptr;
    /**
     * Pointer to the first FieldSlot, used to optimize the extremely
     * hot code path of getFieldSlot().
     */
    void* mSlotsStart = nullptr;
    void* mSlotsEnd = nullptr;
    uint32_t mSize = 0;
    /**
     * When a window starts as lightweight inline allocation, this value
     * holds the "full" size to be created after ashmem inflation.
     */
    uint32_t mInflatedSize = 0;
    /**
     * Offset to the top of the "heap" of string/blob allocations. By
     * storing these allocations at the bottom of our memory region we
     * avoid having to rewrite offsets when inflating.
     */
    uint32_t mAllocOffset = 0;
    /**
     * Offset to the bottom of the "stack" of FieldSlot allocations.
     */
    uint32_t mSlotsOffset = 0;
    uint32_t mNumRows = 0;
    uint32_t mNumColumns = 0;
    bool mReadOnly = false;

    void updateSlotsData();

    void* offsetToPtr(uint32_t offset, uint32_t bufferSize);
    uint32_t offsetFromPtr(void* ptr);

    /**
     * By default windows are lightweight inline allocations; this method
     * inflates the window into a larger ashmem region.
     */
    status_t maybeInflate();

    /**
     * Allocate a portion of the window.
     */
    status_t alloc(size_t size, uint32_t* outOffset);

    status_t putBlobOrString(uint32_t row, uint32_t column,
            const void* value, size_t size, int32_t type);
};

}; // namespace android

#endif