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