• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
62     const std::string &name, size_t size, sptr<Ashmem> ashmem, 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         auto result = memset_s(mHeader->groupOffset, sizeof(mHeader->groupOffset), 0, sizeof(mHeader->groupOffset));
159         if (result != EOK) {
160             LOG_ERROR("memset_s failed, error code is %{public}d", result);
161         }
162         mHeader->groupOffset[0] = sizeof(SharedBlockHeader);
163         return SHARED_BLOCK_OK;
164     }
165     LOG_ERROR("SharedBlock::Clear mHeader is nullptr.");
166     return SHARED_BLOCK_BAD_VALUE;
167 }
168 
SetColumnNum(uint32_t numColumns)169 int SharedBlock::SetColumnNum(uint32_t numColumns)
170 {
171     if (UNLIKELY(mReadOnly)) {
172         return SHARED_BLOCK_INVALID_OPERATION;
173     }
174 
175     uint32_t cur = mHeader->columnNums;
176     if ((cur > 0 || mHeader->rowNums > 0) && cur != numColumns) {
177         LOG_ERROR("Trying to go from %{public}" PRIu32 " columns to %{public}" PRIu32 "", cur, numColumns);
178         return SHARED_BLOCK_INVALID_OPERATION;
179     }
180     if (numColumns > COL_MAX_NUM) {
181         LOG_ERROR("Trying to set %{public}" PRIu32 " columns out of size", numColumns);
182         return SHARED_BLOCK_INVALID_OPERATION;
183     }
184     mHeader->columnNums = numColumns;
185     return SHARED_BLOCK_OK;
186 }
187 
AllocRow()188 int SharedBlock::AllocRow()
189 {
190     /* Fill in the row offset */
191     uint32_t *rowOffset = AllocRowOffset();
192     if (UNLIKELY(rowOffset == nullptr)) {
193         LOG_ERROR("SharedBlock::AllocRow() Failed in AllocRowOffset().");
194         return SHARED_BLOCK_NO_MEMORY;
195     }
196 
197     /* Allocate the units for the field directory */
198     size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
199 
200     /* Aligned */
201     uint32_t fieldDirOffset = Alloc(fieldDirSize);
202     if (UNLIKELY(!fieldDirOffset)) {
203         mHeader->rowNums--;
204         LOG_INFO(
205             "Alloc the row size %{public}u failed, roll back row number %{public}u", fieldDirOffset, mHeader->rowNums);
206         return SHARED_BLOCK_NO_MEMORY;
207     }
208 
209     *rowOffset = fieldDirOffset;
210     return SHARED_BLOCK_OK;
211 }
212 
FreeLastRow()213 int SharedBlock::FreeLastRow()
214 {
215     if (mHeader->rowNums > 0) {
216         mHeader->rowNums--;
217     }
218     return SHARED_BLOCK_OK;
219 }
220 
Alloc(size_t size)221 uint32_t SharedBlock::Alloc(size_t size)
222 {
223     /* Number of unused offsets in the header */
224     uint32_t offsetDigit = 3;
225     uint32_t offset = mHeader->unusedOffset + ((~mHeader->unusedOffset + 1) & offsetDigit);
226     uint32_t nextFreeOffset = offset + size;
227     if (UNLIKELY(nextFreeOffset > mSize)) {
228         LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes,"
229                   " free space %{public}zu bytes, block size %{public}zu bytes",
230             size, mSize - mHeader->unusedOffset, mSize);
231         return 0;
232     }
233     mHeader->unusedOffset = nextFreeOffset;
234     return offset;
235 }
236 
AllocRowOffset()237 uint32_t *SharedBlock::AllocRowOffset()
238 {
239     uint32_t groupPos = mHeader->rowNums / ROW_NUM_IN_A_GROUP;
240     if (UNLIKELY(groupPos >= GROUP_NUM)) {
241         LOG_ERROR("Rows is full. row number %{public}u, groupPos %{public}u", mHeader->rowNums, groupPos);
242         return nullptr;
243     }
244     if (mHeader->groupOffset[groupPos] == 0) {
245         mHeader->groupOffset[groupPos] = Alloc(sizeof(RowGroupHeader));
246         if (UNLIKELY(mHeader->groupOffset[groupPos] == 0)) {
247             LOG_ERROR("SharedBlock::AllocRowOffset() Failed to alloc group->nextGroupOffset "
248                       "when while loop.");
249             return nullptr;
250         }
251     }
252 
253     uint32_t rowPos = mHeader->rowNums % ROW_NUM_IN_A_GROUP;
254     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->groupOffset[groupPos]));
255     mHeader->rowNums += 1;
256     if (group == nullptr) {
257         return nullptr;
258     }
259     return group->rowOffsets + rowPos;
260 }
261 
GetCellUnit(uint32_t row,uint32_t column)262 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
263 {
264     if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
265         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
266                   " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
267             row, column, mHeader->rowNums, mHeader->columnNums);
268         return nullptr;
269     }
270 
271     uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
272     uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
273     RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
274     return reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
275 }
276 
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)277 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
278 {
279     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
280 }
281 
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)282 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
283 {
284     return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
285 }
286 
PutAsset(uint32_t row,uint32_t column,const void * value,size_t size)287 int SharedBlock::PutAsset(uint32_t row, uint32_t column, const void *value, size_t size)
288 {
289     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSET);
290 }
291 
PutAssets(uint32_t row,uint32_t column,const void * value,size_t size)292 int SharedBlock::PutAssets(uint32_t row, uint32_t column, const void *value, size_t size)
293 {
294     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSETS);
295 }
296 
PutFloats(uint32_t row,uint32_t column,const void * value,size_t size)297 int SharedBlock::PutFloats(uint32_t row, uint32_t column, const void *value, size_t size)
298 {
299     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_FLOATS);
300 }
301 
PutBigInt(uint32_t row,uint32_t column,const void * value,size_t size)302 int SharedBlock::PutBigInt(uint32_t row, uint32_t column, const void *value, size_t size)
303 {
304     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BIGINT);
305 }
306 
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)307 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
308 {
309     if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums || value == nullptr)) {
310         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
311                   " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
312             row, column, mHeader->rowNums, mHeader->columnNums);
313         return SHARED_BLOCK_BAD_VALUE;
314     }
315     uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
316     uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
317     RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
318     CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
319     uint32_t offset = mHeader->unusedOffset;
320     uint32_t end = offset + size;
321     if (UNLIKELY(end > mSize)) {
322         return SHARED_BLOCK_NO_MEMORY;
323     }
324     mHeader->unusedOffset = end;
325 
326     if (size != 0) {
327         errno_t result = memcpy_s(mData + offset, size, value, size);
328         if (UNLIKELY(result != EOK)) {
329             return SHARED_BLOCK_NO_MEMORY;
330         }
331     }
332 
333     cellUnit->type = type;
334     cellUnit->cell.stringOrBlobValue.offset = offset;
335     cellUnit->cell.stringOrBlobValue.size = size;
336     return SHARED_BLOCK_OK;
337 }
338 
PutLong(uint32_t row,uint32_t column,int64_t value)339 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
340 {
341     if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
342         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
343                   " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
344             row, column, mHeader->rowNums, mHeader->columnNums);
345         return SHARED_BLOCK_BAD_VALUE;
346     }
347 
348     uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
349     uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
350     RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
351     CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
352     cellUnit->type = CELL_UNIT_TYPE_INTEGER;
353     cellUnit->cell.longValue = value;
354     return SHARED_BLOCK_OK;
355 }
356 
PutDouble(uint32_t row,uint32_t column,double value)357 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value)
358 {
359     if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
360         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
361                   " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
362             row, column, mHeader->rowNums, mHeader->columnNums);
363         return SHARED_BLOCK_BAD_VALUE;
364     }
365 
366     uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
367     uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
368     RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
369     CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
370     cellUnit->type = CELL_UNIT_TYPE_FLOAT;
371     cellUnit->cell.doubleValue = value;
372     return SHARED_BLOCK_OK;
373 }
374 
PutNull(uint32_t row,uint32_t column)375 int SharedBlock::PutNull(uint32_t row, uint32_t column)
376 {
377     if (UNLIKELY(row >= mHeader->rowNums || column >= mHeader->columnNums)) {
378         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
379                   " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
380             row, column, mHeader->rowNums, mHeader->columnNums);
381         return SHARED_BLOCK_BAD_VALUE;
382     }
383 
384     uint32_t groupPos = row / ROW_NUM_IN_A_GROUP;
385     uint32_t rowPos = row % ROW_NUM_IN_A_GROUP;
386     RowGroupHeader *group = reinterpret_cast<RowGroupHeader *>(mData + mHeader->groupOffset[groupPos]);
387     CellUnit *cellUnit = reinterpret_cast<CellUnit *>(mData + group->rowOffsets[rowPos]) + column;
388 
389     cellUnit->type = CELL_UNIT_TYPE_NULL;
390     cellUnit->cell.stringOrBlobValue.offset = 0;
391     cellUnit->cell.stringOrBlobValue.size = 0;
392     return SHARED_BLOCK_OK;
393 }
394 
SetRawData(const void * rawData,size_t size)395 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
396 {
397     if (UNLIKELY(size <= 0 || rawData == nullptr)) {
398         LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
399         return SHARED_BLOCK_INVALID_OPERATION;
400     }
401     if (UNLIKELY(size > mSize)) {
402         LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
403         return SHARED_BLOCK_NO_MEMORY;
404     }
405 
406     int result = memcpy_s(mHeader, mSize, rawData, size);
407     if (UNLIKELY(result != 0)) {
408         return SHARED_BLOCK_NO_MEMORY;
409     }
410     return SHARED_BLOCK_OK;
411 }
412 
GetString(SharedBlock * block) const413 std::string SharedBlock::CellUnit::GetString(SharedBlock *block) const
414 {
415     if (UNLIKELY(block == nullptr)) {
416         return "";
417     }
418     auto value = static_cast<char *>(block->OffsetToPtr(cell.stringOrBlobValue.offset, cell.stringOrBlobValue.size));
419     if (cell.stringOrBlobValue.size < 1 || value == nullptr) {
420         return "";
421     }
422     return value;
423 }
424 
GetBlob(SharedBlock * block) const425 std::vector<uint8_t> SharedBlock::CellUnit::GetBlob(SharedBlock *block) const
426 {
427     if (UNLIKELY(block == nullptr)) {
428         return {};
429     }
430     auto value =
431         reinterpret_cast<uint8_t *>(block->OffsetToPtr(cell.stringOrBlobValue.offset, cell.stringOrBlobValue.size));
432     return std::vector<uint8_t>(value, value + cell.stringOrBlobValue.size);
433 }
434 
GetRawData(SharedBlock * block) const435 const uint8_t *SharedBlock::CellUnit::GetRawData(SharedBlock *block) const
436 {
437     if (UNLIKELY(block == nullptr)) {
438         return nullptr;
439     }
440     return static_cast<uint8_t *>(block->OffsetToPtr(cell.stringOrBlobValue.offset, cell.stringOrBlobValue.size));
441 }
442 } // namespace AppDataFwk
443 } // namespace OHOS
444