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