• 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 
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