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 LOG_ERROR("SharedBlock::AllocRow() Failed in AllocRowOffset().");
186 return SHARED_BLOCK_NO_MEMORY;
187 }
188
189 /* Allocate the units for the field directory */
190 size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
191
192 /* Aligned */
193 uint32_t fieldDirOffset = Alloc(fieldDirSize);
194 if (UNLIKELY(!fieldDirOffset)) {
195 mHeader->rowNums--;
196 LOG_INFO("Alloc the row size %{public}u failed, roll back row number %{public}u", fieldDirOffset,
197 mHeader->rowNums);
198 return SHARED_BLOCK_NO_MEMORY;
199 }
200
201 *rowOffset = fieldDirOffset;
202 return SHARED_BLOCK_OK;
203 }
204
FreeLastRow()205 int SharedBlock::FreeLastRow()
206 {
207 if (mHeader->rowNums > 0) {
208 mHeader->rowNums--;
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 LOG_ERROR("SharedBlock::AllocRowOffset() Failed to alloc group->nextGroupOffset "
240 "when while loop.");
241 return nullptr;
242 }
243 }
244
245 uint32_t rowPos = mHeader->rowNums % ROW_NUM_IN_A_GROUP;
246 RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->groupOffset[groupPos]));
247 mHeader->rowNums += 1;
248 return group->rowOffsets + rowPos;
249 }
250
GetCellUnit(uint32_t row,uint32_t column)251 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
252 {
253 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
254 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
255 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
256 row, column, mHeader->rowNums, mHeader->columnNums);
257 return nullptr;
258 }
259
260 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
261 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
262 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
263 return reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
264 }
265
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)266 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
267 {
268 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
269 }
270
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)271 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
272 {
273 return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
274 }
275
PutAsset(uint32_t row,uint32_t column,const void * value,size_t size)276 int SharedBlock::PutAsset(uint32_t row, uint32_t column, const void *value, size_t size)
277 {
278 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSET);
279 }
280
PutAssets(uint32_t row,uint32_t column,const void * value,size_t size)281 int SharedBlock::PutAssets(uint32_t row, uint32_t column, const void *value, size_t size)
282 {
283 return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSETS);
284 }
285
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)286 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
287 {
288 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
289 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
290 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
291 row, column, mHeader->rowNums, mHeader->columnNums);
292 return SHARED_BLOCK_BAD_VALUE;
293 }
294 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
295 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
296 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
297 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
298 uint32_t offset = mHeader->unusedOffset;
299 uint32_t end = offset + size;
300 if (UNLIKELY(end > mSize)) {
301 return SHARED_BLOCK_NO_MEMORY;
302 }
303 mHeader->unusedOffset = end;
304
305 if (size != 0) {
306 errno_t result = memcpy_s(mData + offset, size, value, size);
307 if (UNLIKELY(result != EOK)) {
308 return SHARED_BLOCK_NO_MEMORY;
309 }
310 }
311
312 cellUnit->type = type;
313 cellUnit->cell.stringOrBlobValue.offset = offset;
314 cellUnit->cell.stringOrBlobValue.size = size;
315 return SHARED_BLOCK_OK;
316 }
317
PutLong(uint32_t row,uint32_t column,int64_t value)318 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
319 {
320 if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
321 LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
322 " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
323 row, column, mHeader->rowNums, mHeader->columnNums);
324 return SHARED_BLOCK_BAD_VALUE;
325 }
326
327 uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
328 uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
329 RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
330 CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
331 cellUnit->type = CELL_UNIT_TYPE_INTEGER;
332 cellUnit->cell.longValue = value;
333 return SHARED_BLOCK_OK;
334 }
335
PutDouble(uint32_t row,uint32_t column,double value)336 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double 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_FLOAT;
350 cellUnit->cell.doubleValue = value;
351 return SHARED_BLOCK_OK;
352 }
353
PutNull(uint32_t row,uint32_t column)354 int SharedBlock::PutNull(uint32_t row, uint32_t column)
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
368 cellUnit->type = CELL_UNIT_TYPE_NULL;
369 cellUnit->cell.stringOrBlobValue.offset = 0;
370 cellUnit->cell.stringOrBlobValue.size = 0;
371 return SHARED_BLOCK_OK;
372 }
373
SetRawData(const void * rawData,size_t size)374 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
375 {
376 if (UNLIKELY(size <= 0)) {
377 LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
378 return SHARED_BLOCK_INVALID_OPERATION;
379 }
380 if (UNLIKELY(size > mSize)) {
381 LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
382 return SHARED_BLOCK_NO_MEMORY;
383 }
384
385 int result = memcpy_s(mHeader, mSize, rawData, size);
386 if (UNLIKELY(result != 0)) {
387 return SHARED_BLOCK_NO_MEMORY;
388 }
389 return SHARED_BLOCK_OK;
390 }
391 } // namespace AppDataFwk
392 } // namespace OHOS
393