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 #define LOG_TAG "SharedBlock"
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 std::atomic<int64_t> identifier {0};
34
35 #define LIKELY(x) __builtin_expect(!!(x), 1)
36 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
SharedBlock(const std::string & name,sptr<Ashmem> ashmem,size_t size,bool readOnly)37 SharedBlock::SharedBlock(const std::string &name, sptr<Ashmem> ashmem, size_t size, bool readOnly)
38 : mName(name), ashmem_(ashmem), mSize(size), mReadOnly(readOnly), mHeader(nullptr)
39 {
40 }
41
~SharedBlock()42 SharedBlock::~SharedBlock()
43 {
44 if (ashmem_ != nullptr) {
45 ashmem_->UnmapAshmem();
46 ashmem_->CloseAshmem();
47 }
48 }
49
Init()50 bool SharedBlock::Init()
51 {
52 mData = static_cast<uint8_t *>(const_cast<void *>(ashmem_->ReadFromAshmem(sizeof(SharedBlockHeader), 0)));
53 mHeader = reinterpret_cast<SharedBlockHeader *>(mData);
54 if (mHeader == nullptr) {
55 return false;
56 }
57 Clear();
58 return true;
59 }
60
CreateSharedBlock(const std::string & name,size_t size,sptr<Ashmem> ashmem,SharedBlock * & outSharedBlock)61 int SharedBlock::CreateSharedBlock(const std::string &name, size_t size, sptr<Ashmem> ashmem,
62 SharedBlock *&outSharedBlock)
63 {
64 outSharedBlock = new SharedBlock(name, ashmem, size, false);
65 if (outSharedBlock == nullptr) {
66 LOG_ERROR("CreateSharedBlock: new SharedBlock error.");
67 return SHARED_BLOCK_BAD_VALUE;
68 }
69
70 if (outSharedBlock->Init() == false) {
71 delete outSharedBlock;
72 LOG_ERROR("CreateSharedBlock: mHeader is null.");
73 return SHARED_BLOCK_ASHMEM_ERROR;
74 }
75 return SHARED_BLOCK_OK;
76 }
77
Create(const std::string & name,size_t size,SharedBlock * & outSharedBlock)78 int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock)
79 {
80 std::string ashmemPath;
81 size_t lastSlashPos = name.find_last_of('/');
82 ashmemPath = (lastSlashPos != std::string::npos) ? name.substr(lastSlashPos) : name;
83 std::string ashmemName = "SharedBlock:" + ashmemPath + std::to_string(identifier.fetch_add(1));
84
85 sptr<Ashmem> ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size);
86 if (ashmem == nullptr) {
87 LOG_ERROR("failed to create ashmem errno %{public}d", errno);
88 return SHARED_BLOCK_ASHMEM_ERROR;
89 }
90
91 bool ret = ashmem->MapReadAndWriteAshmem();
92 if (!ret) {
93 LOG_ERROR("SharedBlock: MapReadAndWriteAshmem function error.");
94 ashmem->CloseAshmem();
95 return SHARED_BLOCK_SET_PORT_ERROR;
96 }
97
98 int result = CreateSharedBlock(name, size, ashmem, outSharedBlock);
99 if (result == SHARED_BLOCK_OK) {
100 return SHARED_BLOCK_OK;
101 }
102 ashmem->UnmapAshmem();
103 ashmem->CloseAshmem();
104 outSharedBlock = nullptr;
105 return result;
106 }
107
WriteMessageParcel(MessageParcel & parcel)108 int SharedBlock::WriteMessageParcel(MessageParcel &parcel)
109 {
110 return parcel.WriteString16(OHOS::Str8ToStr16(mName)) && parcel.WriteAshmem(ashmem_);
111 }
112
ReadMessageParcel(MessageParcel & parcel,SharedBlock * & block)113 int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block)
114 {
115 std::string name = OHOS::Str16ToStr8(parcel.ReadString16());
116 sptr<Ashmem> ashmem = parcel.ReadAshmem();
117 if (UNLIKELY(ashmem == nullptr)) {
118 LOG_ERROR("ReadMessageParcel: No ashmem in the parcel.");
119 return SHARED_BLOCK_BAD_VALUE;
120 }
121 bool ret = ashmem->MapReadAndWriteAshmem();
122 if (UNLIKELY(!ret)) {
123 LOG_ERROR("ReadMessageParcel: MapReadAndWriteAshmem function error.");
124 ashmem->CloseAshmem();
125 return SHARED_BLOCK_SET_PORT_ERROR;
126 }
127 block = new (std::nothrow) SharedBlock(name, ashmem, ashmem->GetAshmemSize(), true);
128 if (UNLIKELY(block == nullptr)) {
129 LOG_ERROR("ReadMessageParcel new SharedBlock error.");
130 return SHARED_BLOCK_BAD_VALUE;
131 }
132 if (UNLIKELY(block->Init() == false)) {
133 delete block;
134 LOG_ERROR("ReadMessageParcel: mHeader is null.");
135 return SHARED_BLOCK_ASHMEM_ERROR;
136 }
137
138 LOG_DEBUG("Created SharedBlock from parcel: unusedOffset=%{private}" PRIu32 ", "
139 "rowNums=%{private}" PRIu32 ", columnNums=%{private}" PRIu32 ", mSize=%{private}d",
140 block->mHeader->unusedOffset, block->mHeader->rowNums, block->mHeader->columnNums,
141 static_cast<int>(block->mSize));
142
143 return SHARED_BLOCK_OK;
144 }
145
Clear()146 int SharedBlock::Clear()
147 {
148 if (UNLIKELY(mReadOnly)) {
149 return SHARED_BLOCK_INVALID_OPERATION;
150 }
151 if (LIKELY(mHeader != nullptr)) {
152 mHeader->unusedOffset = sizeof(SharedBlockHeader) + sizeof(RowGroupHeader);
153 mHeader->rowNums = 0;
154 mHeader->columnNums = 0;
155 mHeader->startPos_ = 0;
156 mHeader->lastPos_ = 0;
157 mHeader->blockPos_ = 0;
158 memset_s(mHeader->groupOffset, sizeof(mHeader->groupOffset), 0, sizeof(mHeader->groupOffset));
159 mHeader->groupOffset[0] = sizeof(SharedBlockHeader);
160 return SHARED_BLOCK_OK;
161 }
162 LOG_ERROR("SharedBlock::Clear mHeader is nullptr.");
163 return SHARED_BLOCK_BAD_VALUE;
164 }
165
SetColumnNum(uint32_t numColumns)166 int SharedBlock::SetColumnNum(uint32_t numColumns)
167 {
168 if (UNLIKELY(mReadOnly)) {
169 return SHARED_BLOCK_INVALID_OPERATION;
170 }
171
172 uint32_t cur = mHeader->columnNums;
173 if ((cur > 0 || mHeader->rowNums > 0) && cur != numColumns) {
174 LOG_ERROR("Trying to go from %{public}" PRIu32 " columns to %{public}" PRIu32 "", cur, numColumns);
175 return SHARED_BLOCK_INVALID_OPERATION;
176 }
177 if (numColumns > COL_MAX_NUM) {
178 LOG_ERROR("Trying to set %{public}" PRIu32 " columns out of size", numColumns);
179 return SHARED_BLOCK_INVALID_OPERATION;
180 }
181 mHeader->columnNums = numColumns;
182 return SHARED_BLOCK_OK;
183 }
184
AllocRow()185 int SharedBlock::AllocRow()
186 {
187 /* Fill in the row offset */
188 uint32_t *rowOffset = AllocRowOffset();
189 if (UNLIKELY(rowOffset == nullptr)) {
190 LOG_ERROR("SharedBlock::AllocRow() Failed in AllocRowOffset().");
191 return SHARED_BLOCK_NO_MEMORY;
192 }
193
194 /* Allocate the units for the field directory */
195 size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
196
197 /* Aligned */
198 uint32_t fieldDirOffset = Alloc(fieldDirSize);
199 if (UNLIKELY(!fieldDirOffset)) {
200 mHeader->rowNums--;
201 LOG_INFO("Alloc the row size %{public}u failed, roll back row number %{public}u", fieldDirOffset,
202 mHeader->rowNums);
203 return SHARED_BLOCK_NO_MEMORY;
204 }
205
206 *rowOffset = fieldDirOffset;
207 return SHARED_BLOCK_OK;
208 }
209
FreeLastRow()210 int SharedBlock::FreeLastRow()
211 {
212 if (mHeader->rowNums > 0) {
213 mHeader->rowNums--;
214 }
215 return SHARED_BLOCK_OK;
216 }
217
Alloc(size_t size)218 uint32_t SharedBlock::Alloc(size_t size)
219 {
220 /* Number of unused offsets in the header */
221 uint32_t offsetDigit = 3;
222 uint32_t offset = mHeader->unusedOffset + ((~mHeader->unusedOffset + 1) & offsetDigit);
223 uint32_t nextFreeOffset = offset + size;
224 if (UNLIKELY(nextFreeOffset > mSize)) {
225 LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes,"
226 " free space %{public}zu bytes, block size %{public}zu bytes",
227 size, mSize - mHeader->unusedOffset, mSize);
228 return 0;
229 }
230 mHeader->unusedOffset = nextFreeOffset;
231 return offset;
232 }
233
AllocRowOffset()234 uint32_t *SharedBlock::AllocRowOffset()
235 {
236 uint32_t groupPos = mHeader->rowNums / ROW_NUM_IN_A_GROUP;
237 if (UNLIKELY(groupPos >= GROUP_NUM)) {
238 LOG_ERROR("rows is full. row number %{public}u, groupPos %{public}u", mHeader->rowNums, groupPos);
239 return nullptr;
240 }
241 if (mHeader->groupOffset[groupPos] == 0) {
242 mHeader->groupOffset[groupPos] = Alloc(sizeof(RowGroupHeader));
243 if (UNLIKELY(mHeader->groupOffset[groupPos] == 0)) {
244 LOG_ERROR("SharedBlock::AllocRowOffset() Failed to alloc group->nextGroupOffset "
245 "when while loop.");
246 return nullptr;
247 }
248 }
249
250 uint32_t rowPos = mHeader->rowNums % ROW_NUM_IN_A_GROUP;
251 RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->groupOffset[groupPos]));
252 mHeader->rowNums += 1;
253 if (group == nullptr) {
254 return nullptr;
255 }
256 return group->rowOffsets + rowPos;
257 }
258
GetCellUnit(uint32_t row,uint32_t column)259 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
260 {
261 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
262 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
263 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
264 row, column, mHeader->rowNums, mHeader->columnNums);
265 return nullptr;
266 }
267
268 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
269 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
270 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
271 return reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
272 }
273
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)274 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
275 {
276 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
277 }
278
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)279 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
280 {
281 return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
282 }
283
PutAsset(uint32_t row,uint32_t column,const void * value,size_t size)284 int SharedBlock::PutAsset(uint32_t row, uint32_t column, const void *value, size_t size)
285 {
286 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSET);
287 }
288
PutAssets(uint32_t row,uint32_t column,const void * value,size_t size)289 int SharedBlock::PutAssets(uint32_t row, uint32_t column, const void *value, size_t size)
290 {
291 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSETS);
292 }
293
PutFloats(uint32_t row,uint32_t column,const void * value,size_t size)294 int SharedBlock::PutFloats(uint32_t row, uint32_t column, const void* value, size_t size)
295 {
296 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_FLOATS);
297 }
298
PutBigInt(uint32_t row,uint32_t column,const void * value,size_t size)299 int SharedBlock::PutBigInt(uint32_t row, uint32_t column, const void* value, size_t size)
300 {
301 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BIGINT);
302 }
303
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)304 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
305 {
306 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
307 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
308 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
309 row, column, mHeader->rowNums, mHeader->columnNums);
310 return SHARED_BLOCK_BAD_VALUE;
311 }
312 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
313 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
314 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
315 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
316 uint32_t offset = mHeader->unusedOffset;
317 uint32_t end = offset + size;
318 if (UNLIKELY(end > mSize)) {
319 return SHARED_BLOCK_NO_MEMORY;
320 }
321 mHeader->unusedOffset = end;
322
323 if (size != 0) {
324 errno_t result = memcpy_s(mData + offset, size, value, size);
325 if (UNLIKELY(result != EOK)) {
326 return SHARED_BLOCK_NO_MEMORY;
327 }
328 }
329
330 cellUnit->type = type;
331 cellUnit->cell.stringOrBlobValue.offset = offset;
332 cellUnit->cell.stringOrBlobValue.size = size;
333 return SHARED_BLOCK_OK;
334 }
335
PutLong(uint32_t row,uint32_t column,int64_t value)336 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
337 {
338 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
339 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
340 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
341 row, column, mHeader->rowNums, mHeader->columnNums);
342 return SHARED_BLOCK_BAD_VALUE;
343 }
344
345 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
346 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
347 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
348 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
349 cellUnit->type = CELL_UNIT_TYPE_INTEGER;
350 cellUnit->cell.longValue = value;
351 return SHARED_BLOCK_OK;
352 }
353
PutDouble(uint32_t row,uint32_t column,double value)354 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value)
355 {
356 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
357 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
358 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
359 row, column, mHeader->rowNums, mHeader->columnNums);
360 return SHARED_BLOCK_BAD_VALUE;
361 }
362
363 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
364 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
365 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
366 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
367 cellUnit->type = CELL_UNIT_TYPE_FLOAT;
368 cellUnit->cell.doubleValue = value;
369 return SHARED_BLOCK_OK;
370 }
371
PutNull(uint32_t row,uint32_t column)372 int SharedBlock::PutNull(uint32_t row, uint32_t column)
373 {
374 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
375 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
376 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
377 row, column, mHeader->rowNums, mHeader->columnNums);
378 return SHARED_BLOCK_BAD_VALUE;
379 }
380
381 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
382 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
383 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
384 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
385
386 cellUnit->type = CELL_UNIT_TYPE_NULL;
387 cellUnit->cell.stringOrBlobValue.offset = 0;
388 cellUnit->cell.stringOrBlobValue.size = 0;
389 return SHARED_BLOCK_OK;
390 }
391
SetRawData(const void * rawData,size_t size)392 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
393 {
394 if (UNLIKELY(size <= 0)) {
395 LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
396 return SHARED_BLOCK_INVALID_OPERATION;
397 }
398 if (UNLIKELY(size > mSize)) {
399 LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
400 return SHARED_BLOCK_NO_MEMORY;
401 }
402
403 int result = memcpy_s(mHeader, mSize, rawData, size);
404 if (UNLIKELY(result != 0)) {
405 return SHARED_BLOCK_NO_MEMORY;
406 }
407 return SHARED_BLOCK_OK;
408 }
409
GetString(SharedBlock * block) const410 std::string SharedBlock::CellUnit::GetString(SharedBlock *block) const
411 {
412 auto value = static_cast<char*>(block->OffsetToPtr(cell.stringOrBlobValue.offset, cell.stringOrBlobValue.size));
413 if (cell.stringOrBlobValue.size < 1 || value == nullptr) {
414 return "";
415 }
416 return value;
417 }
418
GetBlob(SharedBlock * block) const419 std::vector<uint8_t> SharedBlock::CellUnit::GetBlob(SharedBlock* block) const
420 {
421 auto value = reinterpret_cast<uint8_t*>(block->OffsetToPtr(cell.stringOrBlobValue.offset,
422 cell.stringOrBlobValue.size));
423 return std::vector<uint8_t>(value, value + cell.stringOrBlobValue.size);
424 }
425
GetRawData(SharedBlock * block) const426 const uint8_t* SharedBlock::CellUnit::GetRawData(SharedBlock* block) const
427 {
428 return static_cast<uint8_t*>(block->OffsetToPtr(cell.stringOrBlobValue.offset, cell.stringOrBlobValue.size));
429 }
430 } // namespace AppDataFwk
431 } // namespace OHOS
432