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