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