1 /*
2 * Copyright (c) 2023 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
16 #define LOG_TAG "ObserverProxy"
17 #include "data_share_obs_proxy.h"
18 #include "datashare_errno.h"
19
20 #include "itypes_util.h"
21 #include "datashare_itypes_utils.h"
22 #include "log_print.h"
23 #include "log_debug.h"
24
25 namespace OHOS {
26 namespace DataShare {
27 static constexpr int REQUEST_CODE = 0;
28 // length of int32 bytes
29 static constexpr int32_t INT32_BYTE_LEN = static_cast<int32_t>(sizeof(int32_t));
30 // using DATA_SIZEASHMEM_TRANSFER_LIMIT as the maximum length of changeNode.data_[i]
31 static constexpr size_t MAX_STR_LEN = static_cast<size_t>(DATA_SIZE_ASHMEM_TRANSFER_LIMIT);
32 // maximum size of changeNode.data_(all 0-length strings)
33 static constexpr size_t MAX_DATA_SIZE = MAX_STR_LEN >> 2;
CreateAshmem(RdbChangeNode & changeNode)34 int RdbObserverProxy::CreateAshmem(RdbChangeNode &changeNode)
35 {
36 OHOS::sptr<Ashmem> memory = Ashmem::CreateAshmem(ASHMEM_NAME, DATA_SIZE_ASHMEM_TRANSFER_LIMIT);
37 if (memory == nullptr) {
38 ZLOGE("failed to create Ashmem instance.");
39 return E_ERROR;
40 }
41 bool mapRet = memory->MapReadAndWriteAshmem();
42 if (!mapRet) {
43 ZLOGE("failed to map read and write ashmem, ret=%{public}d", mapRet);
44 memory->CloseAshmem();
45 return E_ERROR;
46 }
47 if (changeNode.memory_ != nullptr) {
48 ZLOGE(
49 "Unknown error: changeNode.memory_ should be null, but something is there %{public}p",
50 (void *)changeNode.memory_
51 );
52 return E_ERROR;
53 }
54 changeNode.memory_ = memory;
55 return E_OK;
56 }
57
WriteAshmem(RdbChangeNode & changeNode,void * data,int32_t len,int32_t & offset)58 int RdbObserverProxy::WriteAshmem(RdbChangeNode &changeNode, void *data, int32_t len, int32_t &offset)
59 {
60 if (changeNode.memory_ == nullptr) {
61 ZLOGE("changeNode memory is nullptr.");
62 return E_ERROR;
63 }
64 bool writeRet = changeNode.memory_->WriteToAshmem(data, len, offset);
65 if (!writeRet) {
66 ZLOGE("failed to write into ashmem, ret=%{public}d", writeRet);
67 changeNode.memory_->UnmapAshmem();
68 changeNode.memory_->CloseAshmem();
69 changeNode.memory_ = nullptr;
70 return E_ERROR;
71 }
72 offset += len;
73 return E_OK;
74 }
75
SerializeDataIntoAshmem(RdbChangeNode & changeNode)76 int RdbObserverProxy::SerializeDataIntoAshmem(RdbChangeNode &changeNode)
77 {
78 if (changeNode.memory_ == nullptr) {
79 ZLOGE("changeNode.memory_ is nullptr");
80 return E_ERROR;
81 }
82 // move data
83 // simple serialization: [vec_size(int32); str1_len(int32), str1; str2_len(int32), str2; ...],
84 // total byte size is recorded in changeNode.size
85 int32_t offset = 0;
86 size_t dataSize = changeNode.data_.size();
87 // maximum dataSize
88 if (dataSize > MAX_DATA_SIZE) {
89 ZLOGE("changeNode size:%{public}zu, exceeds the maximum limit.", dataSize);
90 return E_ERROR;
91 }
92 if (WriteAshmem(changeNode, (void *)&dataSize, INT32_BYTE_LEN, offset) != E_OK) {
93 ZLOGE("failed to write data with len %{public}d, offset %{public}d.", INT32_BYTE_LEN, offset);
94 return E_ERROR;
95 }
96 for (size_t i = 0; i < dataSize; i++) {
97 const char *str = changeNode.data_[i].c_str();
98 size_t uStrLen = changeNode.data_[i].length();
99 // maximum strLen
100 if (uStrLen > MAX_STR_LEN) {
101 ZLOGE("string length:%{public}zu, exceeds the maximum limit.", uStrLen);
102 return E_ERROR;
103 }
104 int32_t strLen = static_cast<int32_t>(uStrLen);
105 // write length int
106 if (WriteAshmem(changeNode, (void *)&strLen, INT32_BYTE_LEN, offset) != E_OK) {
107 ZLOGE("failed to write data with index %{public}zu, len %{public}d, offset %{public}d.",
108 i, INT32_BYTE_LEN, offset);
109 return E_ERROR;
110 }
111 // write str
112 if (WriteAshmem(changeNode, (void *)str, strLen, offset) != E_OK) {
113 ZLOGE("failed to write data with index %{public}zu, len %{public}d, offset %{public}d.",
114 i, strLen, offset);
115 return E_ERROR;
116 }
117 }
118 changeNode.size_ = offset;
119 return E_OK;
120 }
121
PrepareRdbChangeNodeData(RdbChangeNode & changeNode)122 int RdbObserverProxy::PrepareRdbChangeNodeData(RdbChangeNode &changeNode)
123 {
124 // If data size is bigger than the limit, move it to the shared memory
125 int32_t size = INT32_BYTE_LEN;
126 size_t dataSize = changeNode.data_.size();
127 // maximum dataSize
128 if (dataSize > MAX_DATA_SIZE) {
129 ZLOGE("changeNode size:%{public}zu, exceeds the maximum limit.", dataSize);
130 return E_ERROR;
131 }
132 for (size_t i = 0; i < dataSize; i++) {
133 size += INT32_BYTE_LEN;
134 size_t uStrLen = changeNode.data_[i].length();
135 // maximum strLen
136 if (uStrLen > DATA_SIZE_ASHMEM_TRANSFER_LIMIT) {
137 ZLOGE("string length:%{public}zu, exceeds the maximum limit.", uStrLen);
138 return E_ERROR;
139 }
140 int32_t strLen = static_cast<int32_t>(uStrLen);
141 size += strLen;
142 }
143 if (size > DATA_SIZE_ASHMEM_TRANSFER_LIMIT) {
144 ZLOGE("Data to write into ashmem is %{public}d bytes, over 10M.", size);
145 return E_ERROR;
146 }
147 if (size > DATA_SIZE_IPC_TRANSFER_LIMIT) {
148 ZLOGD_MACRO("Data size is over 200k, transfer it by the shared memory");
149 if (RdbObserverProxy::CreateAshmem(changeNode) != E_OK) {
150 ZLOGE("failed to create ashmem.");
151 return E_ERROR;
152 }
153 if (RdbObserverProxy::SerializeDataIntoAshmem(changeNode) != E_OK) {
154 ZLOGE("failed to serialize data into ashmem.");
155 return E_ERROR;
156 }
157 // clear original data spot
158 changeNode.data_.clear();
159 changeNode.isSharedMemory_ = true;
160 ZLOGD_MACRO("Preparation done. Data size: %{public}d", changeNode.size_);
161 }
162 return E_OK;
163 }
164
OnChangeFromRdb(RdbChangeNode & changeNode)165 void RdbObserverProxy::OnChangeFromRdb(RdbChangeNode &changeNode)
166 {
167 MessageParcel parcel;
168 if (!parcel.WriteInterfaceToken(RdbObserverProxy::GetDescriptor())) {
169 return;
170 }
171
172 if (RdbObserverProxy::PrepareRdbChangeNodeData(changeNode) != E_OK) {
173 ZLOGE("failed to prepare RdbChangeNode data.");
174 return;
175 }
176
177 if (!ITypesUtil::Marshal(parcel, changeNode)) {
178 ZLOGE("failed to WriteParcelable changeNode ");
179 return;
180 }
181
182 MessageParcel reply;
183 MessageOption option;
184 int32_t result = Remote()->SendRequest(REQUEST_CODE, parcel, reply, option);
185 if (result != ERR_NONE) {
186 ZLOGE("SendRequest error, result=%{public}d", result);
187 return;
188 }
189 ZLOGI("SendRequest ok, retval is %{public}d", reply.ReadInt32());
190 }
191
OnChangeFromPublishedData(PublishedDataChangeNode & changeNode)192 void PublishedDataObserverProxy::OnChangeFromPublishedData(PublishedDataChangeNode &changeNode)
193 {
194 MessageParcel parcel;
195 if (!parcel.WriteInterfaceToken(PublishedDataObserverProxy::GetDescriptor())) {
196 return;
197 }
198
199 if (!ITypesUtil::Marshal(parcel, changeNode)) {
200 ZLOGE("failed to WriteParcelable changeNode ");
201 return;
202 }
203
204 MessageParcel reply;
205 MessageOption option;
206 int32_t result = Remote()->SendRequest(REQUEST_CODE, parcel, reply, option);
207 if (result != ERR_NONE) {
208 ZLOGE("SendRequest error, result=%{public}d", result);
209 return;
210 }
211 ZLOGI("SendRequest ok, retval is %{public}d", reply.ReadInt32());
212 }
213 } // namespace DataShare
214 } // namespace OHOS