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