• 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 #include "shared_block.h"
16 #include <ashmem.h>
17 #include <fcntl.h>
18 #include <securec.h>
19 #include <sys/mman.h>
20 #include <unistd.h>
21 
22 #include <codecvt>
23 #include <iostream>
24 
25 #include "string_ex.h"
26 #include "logger.h"
27 
28 namespace OHOS {
29 namespace AppDataFwk {
SharedBlock(const std::string & name,sptr<Ashmem> ashmem,size_t size,bool readOnly)30 SharedBlock::SharedBlock(const std::string &name, sptr<Ashmem> ashmem, size_t size, bool readOnly)
31     : mName(name), ashmem_(ashmem), mSize(size), mReadOnly(readOnly)
32 {
33 }
34 
~SharedBlock()35 SharedBlock::~SharedBlock()
36 {
37     if (ashmem_ != nullptr) {
38         ashmem_->UnmapAshmem();
39         ashmem_->CloseAshmem();
40         LOG_ERROR("SharedBlock: close ashmem");
41     }
42 }
43 
ToUtf16(std::string str)44 std::u16string SharedBlock::ToUtf16(std::string str)
45 {
46     return OHOS::Str8ToStr16(str);
47 }
48 
ToUtf8(std::u16string str16)49 std::string SharedBlock::ToUtf8(std::u16string str16)
50 {
51     return OHOS::Str16ToStr8(str16);
52 }
53 
Init()54 bool SharedBlock::Init()
55 {
56     mData = const_cast<void *>(ashmem_->ReadFromAshmem(sizeof(SharedBlockHeader), 0));
57     mHeader = static_cast<SharedBlockHeader *>(mData);
58     if (mHeader == nullptr) {
59         return false;
60     }
61     return true;
62 }
63 
CreateSharedBlock(const std::string & name,size_t size,sptr<Ashmem> ashmem,SharedBlock * & outSharedBlock)64 int SharedBlock::CreateSharedBlock(const std::string &name, size_t size, sptr<Ashmem> ashmem,
65     SharedBlock *&outSharedBlock)
66 {
67     LOG_DEBUG("CreateSharedBlock into.");
68     outSharedBlock = new SharedBlock(name, ashmem, size, false);
69     if (outSharedBlock == nullptr) {
70         LOG_ERROR("CreateSharedBlock: new SharedBlock error.");
71         return SHARED_BLOCK_BAD_VALUE;
72     }
73 
74     if (outSharedBlock->Init() == false) {
75         delete outSharedBlock;
76         LOG_ERROR("CreateSharedBlock: mHeader is null.");
77         return SHARED_BLOCK_ASHMEM_ERROR;
78     }
79     return SHARED_BLOCK_OK;
80 }
81 
Create(const std::string & name,size_t size,SharedBlock * & outSharedBlock)82 int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock)
83 {
84     std::string ashmemName = "SharedBlock:" + name;
85 
86     sptr<Ashmem> ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size);
87     if (ashmem == nullptr) {
88         LOG_ERROR("SharedBlock: CreateAshmem function error.");
89         return SHARED_BLOCK_ASHMEM_ERROR;
90     }
91 
92     bool ret = ashmem->MapReadAndWriteAshmem();
93     if (!ret) {
94         LOG_ERROR("SharedBlock: MapReadAndWriteAshmem function error.");
95         ashmem->CloseAshmem();
96         return SHARED_BLOCK_SET_PORT_ERROR;
97     }
98 
99     int result = CreateSharedBlock(name, size, ashmem, outSharedBlock);
100     if (result == SHARED_BLOCK_OK) {
101         return SHARED_BLOCK_OK;
102     }
103     ashmem->UnmapAshmem();
104     ashmem->CloseAshmem();
105     outSharedBlock = nullptr;
106     return result;
107 }
108 
WriteMessageParcel(MessageParcel & parcel)109 int SharedBlock::WriteMessageParcel(MessageParcel &parcel)
110 {
111     return parcel.WriteString16(ToUtf16(mName)) && parcel.WriteAshmem(ashmem_);
112 }
113 
ReadMessageParcel(MessageParcel & parcel,SharedBlock * & block)114 int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block)
115 {
116     std::string name = ToUtf8(parcel.ReadString16());
117     sptr<Ashmem> ashmem = parcel.ReadAshmem();
118     if (ashmem == nullptr) {
119         LOG_ERROR("ReadMessageParcel: No ashmem in the parcel.");
120         return SHARED_BLOCK_BAD_VALUE;
121     }
122     bool ret = ashmem->MapReadAndWriteAshmem();
123     if (!ret) {
124         LOG_ERROR("ReadMessageParcel: MapReadAndWriteAshmem function error.");
125         ashmem->CloseAshmem();
126         return SHARED_BLOCK_SET_PORT_ERROR;
127     }
128     block = new (std::nothrow) SharedBlock(name, ashmem, ashmem->GetAshmemSize(), true);
129     if (block == nullptr) {
130         LOG_ERROR("ReadMessageParcel new SharedBlock error.");
131         return SHARED_BLOCK_BAD_VALUE;
132     }
133     if (block->Init() == false) {
134         delete block;
135         LOG_ERROR("ReadMessageParcel: mHeader is null.");
136         return SHARED_BLOCK_ASHMEM_ERROR;
137     }
138 
139     LOG_DEBUG("Created SharedBlock from parcel: unusedOffset=%{private}d, "
140               "rowNums=%{private}d, columnNums=%{private}d, mSize=%{private}d, mData=%{private}p",
141               block->mHeader->unusedOffset, block->mHeader->rowNums, block->mHeader->columnNums,
142               static_cast<int>(block->mSize), block->mData);
143 
144     return SHARED_BLOCK_OK;
145 }
146 
Clear()147 int SharedBlock::Clear()
148 {
149     if (mReadOnly) {
150         return SHARED_BLOCK_INVALID_OPERATION;
151     }
152 
153     mHeader->unusedOffset = sizeof(SharedBlockHeader) + sizeof(RowGroupHeader);
154     mHeader->firstRowGroupOffset = sizeof(SharedBlockHeader);
155     mHeader->rowNums = 0;
156     mHeader->columnNums = 0;
157 
158     RowGroupHeader *firstGroup = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
159     if (!firstGroup) {
160         LOG_ERROR("Failed to get group in clear().");
161         return SHARED_BLOCK_BAD_VALUE;
162     }
163     firstGroup->nextGroupOffset = 0;
164     return SHARED_BLOCK_OK;
165 }
166 
SetColumnNum(uint32_t numColumns)167 int SharedBlock::SetColumnNum(uint32_t numColumns)
168 {
169     if (mReadOnly) {
170         return SHARED_BLOCK_INVALID_OPERATION;
171     }
172 
173     uint32_t cur = mHeader->columnNums;
174     if ((cur > 0 || mHeader->rowNums > 0) && cur != numColumns) {
175         LOG_ERROR("Trying to go from %{public}d columns to %{public}d", cur, numColumns);
176         return SHARED_BLOCK_INVALID_OPERATION;
177     }
178     if (numColumns > COL_MAX_NUM) {
179         LOG_ERROR("Trying to set %{public}d columns out of size", numColumns);
180         return SHARED_BLOCK_INVALID_OPERATION;
181     }
182     mHeader->columnNums = numColumns;
183     return SHARED_BLOCK_OK;
184 }
185 
AllocRow()186 int SharedBlock::AllocRow()
187 {
188     if (mReadOnly) {
189         return SHARED_BLOCK_INVALID_OPERATION;
190     }
191 
192     /* Fill in the row offset */
193     uint32_t *rowOffset = AllocRowOffset();
194     if (rowOffset == nullptr) {
195         return SHARED_BLOCK_NO_MEMORY;
196     }
197 
198     /* Allocate the units for the field directory */
199     size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
200 
201     /* Aligned */
202     uint32_t fieldDirOffset = Alloc(fieldDirSize, true);
203     if (!fieldDirOffset) {
204         mHeader->rowNums--;
205         LOG_INFO("Alloc the row failed, so back out the new row accounting from allocRowoffset %{public}d",
206             mHeader->rowNums);
207         return SHARED_BLOCK_NO_MEMORY;
208     }
209 
210     CellUnit *fieldDir = static_cast<CellUnit *>(OffsetToPtr(fieldDirOffset));
211     if (fieldDir == nullptr) {
212         return SHARED_BLOCK_BAD_VALUE;
213     }
214     int result = memset_s(fieldDir, fieldDirSize, 0, fieldDirSize);
215     if (result != 0) {
216         LOG_ERROR("Set memory failed");
217         return SHARED_BLOCK_NO_MEMORY;
218     }
219 
220     *rowOffset = fieldDirOffset;
221     return SHARED_BLOCK_OK;
222 }
223 
FreeLastRow()224 int SharedBlock::FreeLastRow()
225 {
226     if (mReadOnly) {
227         return SHARED_BLOCK_INVALID_OPERATION;
228     }
229 
230     if (mHeader->rowNums > 0) {
231         mHeader->rowNums--;
232     }
233 
234     return SHARED_BLOCK_OK;
235 }
236 
Alloc(size_t size,bool aligned)237 uint32_t SharedBlock::Alloc(size_t size, bool aligned)
238 {
239     /* Number of unused offsets in the header */
240     uint32_t offsetDigit = 3;
241     uint32_t padding = aligned ? (~mHeader->unusedOffset + 1) & offsetDigit : 0;
242     uint32_t offset = mHeader->unusedOffset + padding;
243     uint32_t nextFreeOffset;
244 
245     if (offset + size > mSize) {
246         LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes,"
247             " free space %{public}zu bytes, block size %{public}zu bytes",
248             size, mSize - mHeader->unusedOffset, mSize);
249         return 0;
250     }
251     nextFreeOffset = offset + size;
252     mHeader->unusedOffset = nextFreeOffset;
253     return offset;
254 }
255 
GetRowOffset(uint32_t row)256 uint32_t *SharedBlock::GetRowOffset(uint32_t row)
257 {
258     uint32_t rowPos = row;
259 
260     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
261     if (group == nullptr) {
262         LOG_ERROR("Failed to get group in getRowOffset().");
263         return nullptr;
264     }
265 
266     while (rowPos >= ROW_OFFSETS_NUM) {
267         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
268         if (group == nullptr) {
269             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset) when while loop.");
270             return nullptr;
271         }
272         rowPos -= ROW_OFFSETS_NUM;
273     }
274 
275     return &group->rowOffsets[rowPos];
276 }
277 
AllocRowOffset()278 uint32_t *SharedBlock::AllocRowOffset()
279 {
280     uint32_t rowPos = mHeader->rowNums;
281 
282     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
283     if (group == nullptr) {
284         LOG_ERROR("Failed to get group in allocRowOffset().");
285         return nullptr;
286     }
287 
288     while (rowPos > ROW_OFFSETS_NUM) {
289         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
290         if (group == nullptr) {
291             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset) when while loop.");
292             return nullptr;
293         }
294         rowPos -= ROW_OFFSETS_NUM;
295     }
296     if (rowPos == ROW_OFFSETS_NUM) {
297         if (!group->nextGroupOffset) {
298             /* Aligned */
299             group->nextGroupOffset = Alloc(sizeof(RowGroupHeader), true);
300             if (!group->nextGroupOffset) {
301                 return nullptr;
302             }
303         }
304         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
305         if (group == nullptr) {
306             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset).");
307             return nullptr;
308         }
309         group->nextGroupOffset = 0;
310         rowPos = 0;
311     }
312 
313     mHeader->rowNums += 1;
314     return &group->rowOffsets[rowPos];
315 }
316 
GetCellUnit(uint32_t row,uint32_t column)317 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
318 {
319     if (row >= mHeader->rowNums || column >= mHeader->columnNums) {
320         LOG_ERROR("Failed to read row %{public}d, column %{public}d from a SharedBlock"
321             " which has %{public}d rows, %{public}d columns.",
322             row, column, mHeader->rowNums, mHeader->columnNums);
323         return nullptr;
324     }
325 
326     uint32_t *rowOffset = GetRowOffset(row);
327     if (!rowOffset) {
328         LOG_ERROR("Failed to find rowOffset for row %{public}d.", row);
329         return nullptr;
330     }
331 
332     CellUnit *cellUnit = static_cast<CellUnit *>(OffsetToPtr(*rowOffset));
333     if (!cellUnit) {
334         LOG_ERROR("Failed to find cellUnit for rowOffset %{public}d.", *rowOffset);
335         return nullptr;
336     }
337 
338     return &cellUnit[column];
339 }
340 
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)341 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
342 {
343     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
344 }
345 
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)346 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
347 {
348     return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
349 }
350 
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)351 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
352 {
353     if (mReadOnly) {
354         return SHARED_BLOCK_INVALID_OPERATION;
355     }
356 
357     CellUnit *cellUnit = GetCellUnit(row, column);
358     if (!cellUnit) {
359         return SHARED_BLOCK_BAD_VALUE;
360     }
361 
362     uint32_t offset = Alloc(size);
363     if (!offset) {
364         return SHARED_BLOCK_NO_MEMORY;
365     }
366 
367     void *ptr = OffsetToPtr(offset);
368     if (!ptr) {
369         return SHARED_BLOCK_NO_MEMORY;
370     }
371 
372     if (size != 0) {
373         int result = memcpy_s(ptr, size, value, size);
374         if (result != EOK) {
375             return SHARED_BLOCK_NO_MEMORY;
376         }
377     }
378 
379     cellUnit->type = type;
380     cellUnit->cell.stringOrBlobValue.offset = offset;
381     cellUnit->cell.stringOrBlobValue.size = size;
382     return SHARED_BLOCK_OK;
383 }
384 
PutLong(uint32_t row,uint32_t column,int64_t value)385 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
386 {
387     if (mReadOnly) {
388         return SHARED_BLOCK_INVALID_OPERATION;
389     }
390 
391     CellUnit *cellUnit = GetCellUnit(row, column);
392     if (!cellUnit) {
393         return SHARED_BLOCK_BAD_VALUE;
394     }
395 
396     cellUnit->type = CELL_UNIT_TYPE_INTEGER;
397     cellUnit->cell.longValue = value;
398     return SHARED_BLOCK_OK;
399 }
400 
PutDouble(uint32_t row,uint32_t column,double value)401 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value)
402 {
403     if (mReadOnly) {
404         return SHARED_BLOCK_INVALID_OPERATION;
405     }
406 
407     CellUnit *cellUnit = GetCellUnit(row, column);
408     if (!cellUnit) {
409         return SHARED_BLOCK_BAD_VALUE;
410     }
411 
412     cellUnit->type = CELL_UNIT_TYPE_FLOAT;
413     cellUnit->cell.doubleValue = value;
414     return SHARED_BLOCK_OK;
415 }
416 
PutNull(uint32_t row,uint32_t column)417 int SharedBlock::PutNull(uint32_t row, uint32_t column)
418 {
419     if (mReadOnly) {
420         return SHARED_BLOCK_INVALID_OPERATION;
421     }
422 
423     CellUnit *cellUnit = GetCellUnit(row, column);
424     if (!cellUnit) {
425         return SHARED_BLOCK_BAD_VALUE;
426     }
427 
428     cellUnit->type = CELL_UNIT_TYPE_NULL;
429     cellUnit->cell.stringOrBlobValue.offset = 0;
430     cellUnit->cell.stringOrBlobValue.size = 0;
431     return SHARED_BLOCK_OK;
432 }
433 
SetRawData(const void * rawData,size_t size)434 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
435 {
436     if (size <= 0) {
437         LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
438         return SHARED_BLOCK_INVALID_OPERATION;
439     }
440     if (size > mSize) {
441         LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
442         return SHARED_BLOCK_NO_MEMORY;
443     }
444 
445     int result = memcpy_s(mHeader, mSize, rawData, size);
446     if (result != 0) {
447         return SHARED_BLOCK_NO_MEMORY;
448     }
449     return SHARED_BLOCK_OK;
450 }
451 
OffsetToPtr(uint32_t offset,uint32_t bufferSize)452 void *SharedBlock::OffsetToPtr(uint32_t offset, uint32_t bufferSize)
453 {
454     if (offset >= mSize) {
455         LOG_ERROR("Offset %" PRIu32 " out of bounds, max value %zu", offset, mSize);
456         return nullptr;
457     }
458     if (offset + bufferSize > mSize) {
459         LOG_ERROR("End offset %" PRIu32 " out of bounds, max value %zu", offset + bufferSize, mSize);
460         return nullptr;
461     }
462     return static_cast<uint8_t *>(mData) + offset;
463 }
464 
OffsetFromPtr(void * ptr)465 uint32_t SharedBlock::OffsetFromPtr(void *ptr)
466 {
467     return static_cast<uint8_t *>(ptr) - static_cast<uint8_t *>(mData);
468 }
469 } // namespace AppDataFwk
470 } // namespace OHOS
471