• 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), mHeader(nullptr)
32 {
33 }
34 
~SharedBlock()35 SharedBlock::~SharedBlock()
36 {
37     if (ashmem_ != nullptr) {
38         ashmem_->UnmapAshmem();
39         ashmem_->CloseAshmem();
40         LOG_WARN("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     outSharedBlock = new SharedBlock(name, ashmem, size, false);
68     if (outSharedBlock == nullptr) {
69         LOG_ERROR("CreateSharedBlock: new SharedBlock error.");
70         return SHARED_BLOCK_BAD_VALUE;
71     }
72 
73     if (outSharedBlock->Init() == false) {
74         delete outSharedBlock;
75         LOG_ERROR("CreateSharedBlock: mHeader is null.");
76         return SHARED_BLOCK_ASHMEM_ERROR;
77     }
78     return SHARED_BLOCK_OK;
79 }
80 
Create(const std::string & name,size_t size,SharedBlock * & outSharedBlock)81 int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock)
82 {
83     std::string ashmemName = "SharedBlock:" + name;
84 
85     sptr<Ashmem> ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size);
86     if (ashmem == nullptr) {
87         LOG_ERROR("SharedBlock: CreateAshmem function error.");
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(ToUtf16(mName)) && parcel.WriteAshmem(ashmem_);
111 }
112 
ReadMessageParcel(MessageParcel & parcel,SharedBlock * & block)113 int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block)
114 {
115     std::string name = ToUtf8(parcel.ReadString16());
116     sptr<Ashmem> ashmem = parcel.ReadAshmem();
117     if (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 (!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 (block == nullptr) {
129         LOG_ERROR("ReadMessageParcel new SharedBlock error.");
130         return SHARED_BLOCK_BAD_VALUE;
131     }
132     if (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 (mReadOnly) {
149         return SHARED_BLOCK_INVALID_OPERATION;
150     }
151 
152     mHeader->unusedOffset = sizeof(SharedBlockHeader) + sizeof(RowGroupHeader);
153     mHeader->firstRowGroupOffset = sizeof(SharedBlockHeader);
154     mHeader->rowNums = 0;
155     mHeader->columnNums = 0;
156     mHeader->startPos_ = 0;
157     mHeader->lastPos_ = 0;
158     mHeader->blockPos_ = 0;
159 
160     RowGroupHeader *firstGroup = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
161     if (!firstGroup) {
162         LOG_ERROR("Failed to get group in clear().");
163         return SHARED_BLOCK_BAD_VALUE;
164     }
165     firstGroup->nextGroupOffset = 0;
166     return SHARED_BLOCK_OK;
167 }
168 
SetColumnNum(uint32_t numColumns)169 int SharedBlock::SetColumnNum(uint32_t numColumns)
170 {
171     if (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     if (mReadOnly) {
191         return SHARED_BLOCK_INVALID_OPERATION;
192     }
193 
194     /* Fill in the row offset */
195     uint32_t *rowOffset = AllocRowOffset();
196     if (rowOffset == nullptr) {
197         return SHARED_BLOCK_NO_MEMORY;
198     }
199 
200     /* Allocate the units for the field directory */
201     size_t fieldDirSize = mHeader->columnNums * sizeof(CellUnit);
202 
203     /* Aligned */
204     uint32_t fieldDirOffset = Alloc(fieldDirSize, true);
205     if (!fieldDirOffset) {
206         mHeader->rowNums--;
207         LOG_INFO("Alloc the row failed, so back out the new row accounting from allocRowoffset %{public}" PRIu32 "",
208             mHeader->rowNums);
209         return SHARED_BLOCK_NO_MEMORY;
210     }
211 
212     CellUnit *fieldDir = static_cast<CellUnit *>(OffsetToPtr(fieldDirOffset));
213     if (fieldDir == nullptr) {
214         return SHARED_BLOCK_BAD_VALUE;
215     }
216     int result = memset_s(fieldDir, fieldDirSize, 0, fieldDirSize);
217     if (result != 0) {
218         LOG_ERROR("Set memory failed");
219         return SHARED_BLOCK_NO_MEMORY;
220     }
221 
222     *rowOffset = fieldDirOffset;
223     return SHARED_BLOCK_OK;
224 }
225 
FreeLastRow()226 int SharedBlock::FreeLastRow()
227 {
228     if (mReadOnly) {
229         return SHARED_BLOCK_INVALID_OPERATION;
230     }
231 
232     if (mHeader->rowNums > 0) {
233         mHeader->rowNums--;
234     }
235 
236     return SHARED_BLOCK_OK;
237 }
238 
Alloc(size_t size,bool aligned)239 uint32_t SharedBlock::Alloc(size_t size, bool aligned)
240 {
241     /* Number of unused offsets in the header */
242     uint32_t offsetDigit = 3;
243     uint32_t padding = aligned ? (~mHeader->unusedOffset + 1) & offsetDigit : 0;
244     uint32_t offset = mHeader->unusedOffset + padding;
245     uint32_t nextFreeOffset;
246 
247     if (offset + size > mSize) {
248         LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes,"
249             " free space %{public}zu bytes, block size %{public}zu bytes",
250             size, mSize - mHeader->unusedOffset, mSize);
251         return 0;
252     }
253     nextFreeOffset = offset + size;
254     mHeader->unusedOffset = nextFreeOffset;
255     return offset;
256 }
257 
GetRowOffset(uint32_t row)258 uint32_t *SharedBlock::GetRowOffset(uint32_t row)
259 {
260     uint32_t rowPos = row;
261 
262     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
263     if (group == nullptr) {
264         LOG_ERROR("Failed to get group in getRowOffset().");
265         return nullptr;
266     }
267 
268     while (rowPos >= ROW_OFFSETS_NUM) {
269         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
270         if (group == nullptr) {
271             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset) when while loop.");
272             return nullptr;
273         }
274         rowPos -= ROW_OFFSETS_NUM;
275     }
276 
277     return &group->rowOffsets[rowPos];
278 }
279 
AllocRowOffset()280 uint32_t *SharedBlock::AllocRowOffset()
281 {
282     uint32_t rowPos = mHeader->rowNums;
283 
284     RowGroupHeader *group = static_cast<RowGroupHeader *>(OffsetToPtr(mHeader->firstRowGroupOffset));
285     if (group == nullptr) {
286         LOG_ERROR("Failed to get group in allocRowOffset().");
287         return nullptr;
288     }
289 
290     while (rowPos > ROW_OFFSETS_NUM) {
291         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
292         if (group == nullptr) {
293             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset) when while loop.");
294             return nullptr;
295         }
296         rowPos -= ROW_OFFSETS_NUM;
297     }
298     if (rowPos == ROW_OFFSETS_NUM) {
299         if (!group->nextGroupOffset) {
300             /* Aligned */
301             group->nextGroupOffset = Alloc(sizeof(RowGroupHeader), true);
302             if (!group->nextGroupOffset) {
303                 return nullptr;
304             }
305         }
306         group = static_cast<RowGroupHeader *>(OffsetToPtr(group->nextGroupOffset));
307         if (group == nullptr) {
308             LOG_ERROR("Failed to get group in OffsetToPtr(group->nextGroupOffset).");
309             return nullptr;
310         }
311         group->nextGroupOffset = 0;
312         rowPos = 0;
313     }
314 
315     mHeader->rowNums += 1;
316     return &group->rowOffsets[rowPos];
317 }
318 
GetCellUnit(uint32_t row,uint32_t column)319 SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column)
320 {
321     if (row >= mHeader->rowNums || column >= mHeader->columnNums) {
322         LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock"
323             " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.",
324             row, column, mHeader->rowNums, mHeader->columnNums);
325         return nullptr;
326     }
327 
328     uint32_t *rowOffset = GetRowOffset(row);
329     if (!rowOffset) {
330         LOG_ERROR("Failed to find rowOffset for row %{public}" PRIu32 ".", row);
331         return nullptr;
332     }
333 
334     CellUnit *cellUnit = static_cast<CellUnit *>(OffsetToPtr(*rowOffset));
335     if (!cellUnit) {
336         LOG_ERROR("Failed to find cellUnit for rowOffset %{public}" PRIu32 ".", *rowOffset);
337         return nullptr;
338     }
339 
340     return &cellUnit[column];
341 }
342 
PutBlob(uint32_t row,uint32_t column,const void * value,size_t size)343 int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size)
344 {
345     return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB);
346 }
347 
PutString(uint32_t row,uint32_t column,const char * value,size_t sizeIncludingNull)348 int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull)
349 {
350     return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING);
351 }
352 
PutBlobOrString(uint32_t row,uint32_t column,const void * value,size_t size,int32_t type)353 int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type)
354 {
355     if (mReadOnly) {
356         return SHARED_BLOCK_INVALID_OPERATION;
357     }
358 
359     CellUnit *cellUnit = GetCellUnit(row, column);
360     if (!cellUnit) {
361         return SHARED_BLOCK_BAD_VALUE;
362     }
363 
364     uint32_t offset = Alloc(size);
365     if (!offset) {
366         return SHARED_BLOCK_NO_MEMORY;
367     }
368 
369     void *ptr = OffsetToPtr(offset);
370     if (!ptr) {
371         return SHARED_BLOCK_NO_MEMORY;
372     }
373 
374     if (size != 0) {
375         errno_t result = memcpy_s(ptr, size, value, size);
376         if (result != EOK) {
377             return SHARED_BLOCK_NO_MEMORY;
378         }
379     }
380 
381     cellUnit->type = type;
382     cellUnit->cell.stringOrBlobValue.offset = offset;
383     cellUnit->cell.stringOrBlobValue.size = size;
384     return SHARED_BLOCK_OK;
385 }
386 
PutLong(uint32_t row,uint32_t column,int64_t value)387 int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value)
388 {
389     if (mReadOnly) {
390         return SHARED_BLOCK_INVALID_OPERATION;
391     }
392 
393     CellUnit *cellUnit = GetCellUnit(row, column);
394     if (!cellUnit) {
395         return SHARED_BLOCK_BAD_VALUE;
396     }
397 
398     cellUnit->type = CELL_UNIT_TYPE_INTEGER;
399     cellUnit->cell.longValue = value;
400     return SHARED_BLOCK_OK;
401 }
402 
PutDouble(uint32_t row,uint32_t column,double value)403 int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value)
404 {
405     if (mReadOnly) {
406         return SHARED_BLOCK_INVALID_OPERATION;
407     }
408 
409     CellUnit *cellUnit = GetCellUnit(row, column);
410     if (!cellUnit) {
411         return SHARED_BLOCK_BAD_VALUE;
412     }
413 
414     cellUnit->type = CELL_UNIT_TYPE_FLOAT;
415     cellUnit->cell.doubleValue = value;
416     return SHARED_BLOCK_OK;
417 }
418 
PutNull(uint32_t row,uint32_t column)419 int SharedBlock::PutNull(uint32_t row, uint32_t column)
420 {
421     if (mReadOnly) {
422         return SHARED_BLOCK_INVALID_OPERATION;
423     }
424 
425     CellUnit *cellUnit = GetCellUnit(row, column);
426     if (!cellUnit) {
427         return SHARED_BLOCK_BAD_VALUE;
428     }
429 
430     cellUnit->type = CELL_UNIT_TYPE_NULL;
431     cellUnit->cell.stringOrBlobValue.offset = 0;
432     cellUnit->cell.stringOrBlobValue.size = 0;
433     return SHARED_BLOCK_OK;
434 }
435 
SetRawData(const void * rawData,size_t size)436 size_t SharedBlock::SetRawData(const void *rawData, size_t size)
437 {
438     if (size <= 0) {
439         LOG_ERROR("SharedBlock rawData is less than or equal to 0M");
440         return SHARED_BLOCK_INVALID_OPERATION;
441     }
442     if (size > mSize) {
443         LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size);
444         return SHARED_BLOCK_NO_MEMORY;
445     }
446 
447     int result = memcpy_s(mHeader, mSize, rawData, size);
448     if (result != 0) {
449         return SHARED_BLOCK_NO_MEMORY;
450     }
451     return SHARED_BLOCK_OK;
452 }
453 
OffsetToPtr(uint32_t offset,uint32_t bufferSize)454 void *SharedBlock::OffsetToPtr(uint32_t offset, uint32_t bufferSize)
455 {
456     if (offset >= mSize) {
457         LOG_ERROR("Offset %{public}" PRIu32 " out of bounds, max value %{public}zu", offset, mSize);
458         return nullptr;
459     }
460     if (offset + bufferSize > mSize) {
461         LOG_ERROR("End offset %{public}" PRIu32 " out of bounds, max value %{public}zu", offset + bufferSize, mSize);
462         return nullptr;
463     }
464     return static_cast<uint8_t *>(mData) + offset;
465 }
466 
OffsetFromPtr(void * ptr)467 uint32_t SharedBlock::OffsetFromPtr(void *ptr)
468 {
469     return static_cast<uint8_t *>(ptr) - static_cast<uint8_t *>(mData);
470 }
471 } // namespace AppDataFwk
472 } // namespace OHOS
473