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