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