1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "shared_block.h"
17
18 #include <ashmem.h>
19 #include <fcntl.h>
20 #include <securec.h>
21 #include <sys/mman.h>
22 #include <unistd.h>
23
24 #include <codecvt>
25 #include <iostream>
26
27 #include "logger.h"
28 #include "string_ex.h"
29
30 namespace OHOS {
31 namespace AppDataFwk {
32 using namespace OHOS::Rdb;
33
34 #define LIKELY(x) __builtin_expect(!!(x), 1)
35 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
SharedBlock(const std::string & name,sptr<Ashmem> ashmem,size_t size,bool readOnly)36 SharedBlock::SharedBlock(const std::string &name, sptr<Ashmem> ashmem, size_t size, bool readOnly)
37 : mName(name), ashmem_(ashmem), mSize(size), mReadOnly(readOnly), mHeader(nullptr)
38 {
39 }
40
~SharedBlock()41 SharedBlock::~SharedBlock()
42 {
43 if (ashmem_ != nullptr) {
44 ashmem_->UnmapAshmem();
45 ashmem_->CloseAshmem();
46 }
47 }
48
Init()49 bool SharedBlock::Init()
50 {
51 mData = static_cast<uint8_t *>(const_cast<void *>(ashmem_->ReadFromAshmem(sizeof(SharedBlockHeader), 0)));
52 mHeader = reinterpret_cast<SharedBlockHeader *>(mData);
53 if (mHeader == nullptr) {
54 return false;
55 }
56 return true;
57 }
58
CreateSharedBlock(const std::string & name,size_t size,sptr<Ashmem> ashmem,SharedBlock * & outSharedBlock)59 int SharedBlock::CreateSharedBlock(const std::string &name, size_t size, sptr<Ashmem> ashmem,
60 SharedBlock *&outSharedBlock)
61 {
62 outSharedBlock = new SharedBlock(name, ashmem, size, false);
63 if (outSharedBlock == nullptr) {
64 LOG_ERROR("CreateSharedBlock: new SharedBlock error.");
65 return SHARED_BLOCK_BAD_VALUE;
66 }
67
68 if (outSharedBlock->Init() == false) {
69 delete outSharedBlock;
70 LOG_ERROR("CreateSharedBlock: mHeader is null.");
71 return SHARED_BLOCK_ASHMEM_ERROR;
72 }
73 return SHARED_BLOCK_OK;
74 }
75
Create(const std::string & name,size_t size,SharedBlock * & outSharedBlock)76 int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock)
77 {
78 std::string ashmemName = "SharedBlock:" + name;
79
80 sptr<Ashmem> ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size);
81 if (ashmem == nullptr) {
82 LOG_ERROR("SharedBlock: CreateAshmem function error.");
83 return SHARED_BLOCK_ASHMEM_ERROR;
84 }
85
86 bool ret = ashmem->MapReadAndWriteAshmem();
87 if (!ret) {
88 LOG_ERROR("SharedBlock: MapReadAndWriteAshmem function error.");
89 ashmem->CloseAshmem();
90 return SHARED_BLOCK_SET_PORT_ERROR;
91 }
92
93 int result = CreateSharedBlock(name, size, ashmem, outSharedBlock);
94 if (result == SHARED_BLOCK_OK) {
95 return SHARED_BLOCK_OK;
96 }
97 ashmem->UnmapAshmem();
98 ashmem->CloseAshmem();
99 outSharedBlock = nullptr;
100 return result;
101 }
102
WriteMessageParcel(MessageParcel & parcel)103 int SharedBlock::WriteMessageParcel(MessageParcel &parcel)
104 {
105 return parcel.WriteString16(OHOS::Str8ToStr16(mName)) && parcel.WriteAshmem(ashmem_);
106 }
107
ReadMessageParcel(MessageParcel & parcel,SharedBlock * & block)108 int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block)
109 {
110 std::string name = OHOS::Str16ToStr8(parcel.ReadString16());
111 sptr<Ashmem> ashmem = parcel.ReadAshmem();
112 if (UNLIKELY(ashmem == nullptr)) {
113 LOG_ERROR("ReadMessageParcel: No ashmem in the parcel.");
114 return SHARED_BLOCK_BAD_VALUE;
115 }
116 bool ret = ashmem->MapReadAndWriteAshmem();
117 if (UNLIKELY(!ret)) {
118 LOG_ERROR("ReadMessageParcel: MapReadAndWriteAshmem function error.");
119 ashmem->CloseAshmem();
120 return SHARED_BLOCK_SET_PORT_ERROR;
121 }
122 block = new (std::nothrow) SharedBlock(name, ashmem, ashmem->GetAshmemSize(), true);
123 if (UNLIKELY(block == nullptr)) {
124 LOG_ERROR("ReadMessageParcel new SharedBlock error.");
125 return SHARED_BLOCK_BAD_VALUE;
126 }
127 if (UNLIKELY(block->Init() == false)) {
128 delete block;
129 LOG_ERROR("ReadMessageParcel: mHeader is null.");
130 return SHARED_BLOCK_ASHMEM_ERROR;
131 }
132
133 LOG_DEBUG("Created SharedBlock from parcel: unusedOffset=%{private}" PRIu32 ", "
134 "rowNums=%{private}" PRIu32 ", columnNums=%{private}" PRIu32 ", mSize=%{private}d",
135 block->mHeader->unusedOffset, block->mHeader->rowNums, block->mHeader->columnNums,
136 static_cast<int>(block->mSize));
137
138 return SHARED_BLOCK_OK;
139 }
140
Clear()141 int SharedBlock::Clear()
142 {
143 if (UNLIKELY(mReadOnly)) {
144 return SHARED_BLOCK_INVALID_OPERATION;
145 }
146 if (LIKELY(mHeader != nullptr)) {
147 mHeader->unusedOffset = sizeof(SharedBlockHeader) + sizeof(RowGroupHeader);
148 mHeader->rowNums = 0;
149 mHeader->columnNums = 0;
150 mHeader->startPos_ = 0;
151 mHeader->lastPos_ = 0;
152 mHeader->blockPos_ = 0;
153 memset_s(mHeader->groupOffset, sizeof(mHeader->groupOffset), 0, sizeof(mHeader->groupOffset));
154 mHeader->groupOffset[0] = sizeof(SharedBlockHeader);
155 return SHARED_BLOCK_OK;
156 }
157 LOG_ERROR("SharedBlock::Clear mHeader is nullptr");
158 return SHARED_BLOCK_BAD_VALUE;
159 }
160
SetColumnNum(uint32_t numColumns)161 int SharedBlock::SetColumnNum(uint32_t numColumns)
162 {
163 if (UNLIKELY(mReadOnly)) {
164 return SHARED_BLOCK_INVALID_OPERATION;
165 }
166
167 uint32_t cur = mHeader->columnNums;
168 if ((cur > 0 || mHeader->rowNums > 0) && cur != numColumns) {
169 LOG_ERROR("Trying to go from %{public}" PRIu32 " columns to %{public}" PRIu32 "", cur, numColumns);
170 return SHARED_BLOCK_INVALID_OPERATION;
171 }
172 if (numColumns > COL_MAX_NUM) {
173 LOG_ERROR("Trying to set %{public}" PRIu32 " columns out of size", numColumns);
174 return SHARED_BLOCK_INVALID_OPERATION;
175 }
176 mHeader->columnNums = numColumns;
177 return SHARED_BLOCK_OK;
178 }
179
AllocRow()180 int SharedBlock::AllocRow()
181 {
182 /* Fill in the row offset */
183 uint32_t *rowOffset = AllocRowOffset();
184 if (UNLIKELY(rowOffset == nullptr)) {
185 return SHARED_BLOCK_NO_MEMORY;
186 }
187
188 /* Allocate the units for the field directory */
189 size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
190
191 /* Aligned */
192 uint32_t fieldDirOffset = Alloc(fieldDirSize);
193 if (UNLIKELY(!fieldDirOffset)) {
194 mHeader->rowNums--;
195 LOG_INFO("Alloc the row size %{public}u failed, roll back row number %{public}u", fieldDirOffset,
196 mHeader->rowNums);
197 return SHARED_BLOCK_NO_MEMORY;
198 }
199
200 *rowOffset = fieldDirOffset;
201 return SHARED_BLOCK_OK;
202 }
203
FreeLastRow()204 int SharedBlock::FreeLastRow()
205 {
206 if (mHeader->rowNums > 0) {
207 mHeader->rowNums--;
208 }
209
210 return SHARED_BLOCK_OK;
211 }
212
Alloc(size_t size)213 uint32_t SharedBlock::Alloc(size_t size)
214 {
215 /* Number of unused offsets in the header */
216 uint32_t offsetDigit = 3;
217 uint32_t offset = mHeader->unusedOffset + ((~mHeader->unusedOffset + 1) & offsetDigit);
218 uint32_t nextFreeOffset = offset + size;
219 if (UNLIKELY(nextFreeOffset > mSize)) {
220 LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes,"
221 " free space %{public}zu bytes, block size %{public}zu bytes",
222 size, mSize - mHeader->unusedOffset, mSize);
223 return 0;
224 }
225 mHeader->unusedOffset = nextFreeOffset;
226 return offset;
227 }
228
AllocRowOffset()229 uint32_t *SharedBlock::AllocRowOffset()
230 {
231 uint32_t groupPos = mHeader->rowNums / ROW_NUM_IN_A_GROUP;
232 if (UNLIKELY(groupPos >= GROUP_NUM)) {
233 LOG_ERROR("rows is full. row number %{public}u, groupPos %{public}u", mHeader->rowNums, groupPos);
234 return nullptr;
235 }
236 if (mHeader->groupOffset[groupPos] == 0) {
237 mHeader->groupOffset[groupPos] = Alloc(sizeof(RowGroupHeader));
238 if (UNLIKELY(mHeader->groupOffset[groupPos] == 0)) {
239 return nullptr;
240 }
241 }
242
243 uint32_t rowPos = mHeader->rowNums % ROW_NUM_IN_A_GROUP;
244 RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->groupOffset[groupPos]));
245 mHeader->rowNums += 1;
246 return group->rowOffsets + rowPos;
247 }
248
GetCellUnit(uint32_t row,uint32_t column)249 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
250 {
251 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
252 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
253 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
254 row, column, mHeader->rowNums, mHeader->columnNums);
255 return nullptr;
256 }
257
258 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
259 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
260 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
261 return reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
262 }
263
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)264 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
265 {
266 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
267 }
268
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)269 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
270 {
271 return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
272 }
273
PutAsset(uint32_t row,uint32_t column,const void * value,size_t size)274 int SharedBlock::PutAsset(uint32_t row, uint32_t column, const void *value, size_t size)
275 {
276 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSET);
277 }
278
PutAssets(uint32_t row,uint32_t column,const void * value,size_t size)279 int SharedBlock::PutAssets(uint32_t row, uint32_t column, const void *value, size_t size)
280 {
281 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSETS);
282 }
283
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)284 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
285 {
286 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
287 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
288 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
289 row, column, mHeader->rowNums, mHeader->columnNums);
290 return SHARED_BLOCK_BAD_VALUE;
291 }
292 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
293 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
294 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
295 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
296 uint32_t offset = mHeader->unusedOffset;
297 uint32_t end = offset + size;
298 if (UNLIKELY(end > mSize)) {
299 return SHARED_BLOCK_NO_MEMORY;
300 }
301 mHeader->unusedOffset = end;
302
303 if (size != 0) {
304 errno_t result = memcpy_s(mData + offset, size, value, size);
305 if (UNLIKELY(result != EOK)) {
306 return SHARED_BLOCK_NO_MEMORY;
307 }
308 }
309
310 cellUnit->type = type;
311 cellUnit->cell.stringOrBlobValue.offset = offset;
312 cellUnit->cell.stringOrBlobValue.size = size;
313 return SHARED_BLOCK_OK;
314 }
315
PutLong(uint32_t row,uint32_t column,int64_t value)316 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
317 {
318 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
319 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
320 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
321 row, column, mHeader->rowNums, mHeader->columnNums);
322 return SHARED_BLOCK_BAD_VALUE;
323 }
324
325 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
326 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
327 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
328 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
329 cellUnit->type = CELL_UNIT_TYPE_INTEGER;
330 cellUnit->cell.longValue = value;
331 return SHARED_BLOCK_OK;
332 }
333
PutDouble(uint32_t row,uint32_t column,double value)334 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value)
335 {
336 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
337 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
338 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
339 row, column, mHeader->rowNums, mHeader->columnNums);
340 return SHARED_BLOCK_BAD_VALUE;
341 }
342
343 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
344 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
345 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
346 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
347 cellUnit->type = CELL_UNIT_TYPE_FLOAT;
348 cellUnit->cell.doubleValue = value;
349 return SHARED_BLOCK_OK;
350 }
351
PutNull(uint32_t row,uint32_t column)352 int SharedBlock::PutNull(uint32_t row, uint32_t column)
353 {
354 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
355 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
356 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
357 row, column, mHeader->rowNums, mHeader->columnNums);
358 return SHARED_BLOCK_BAD_VALUE;
359 }
360
361 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
362 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
363 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
364 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
365
366 cellUnit->type = CELL_UNIT_TYPE_NULL;
367 cellUnit->cell.stringOrBlobValue.offset = 0;
368 cellUnit->cell.stringOrBlobValue.size = 0;
369 return SHARED_BLOCK_OK;
370 }
371
SetRawData(const void * rawData,size_t size)372 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
373 {
374 if (UNLIKELY(size <= 0)) {
375 LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
376 return SHARED_BLOCK_INVALID_OPERATION;
377 }
378 if (UNLIKELY(size > mSize)) {
379 LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
380 return SHARED_BLOCK_NO_MEMORY;
381 }
382
383 int result = memcpy_s(mHeader, mSize, rawData, size);
384 if (UNLIKELY(result != 0)) {
385 return SHARED_BLOCK_NO_MEMORY;
386 }
387 return SHARED_BLOCK_OK;
388 }
389 } // namespace AppDataFwk
390 } // namespace OHOS
391