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