1 /*
2 * Copyright (c) 2024 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 #include <map>
17 #include <string>
18 #include <securec.h>
19 #include <functional>
20 #include "nlohmann/json.hpp"
21 #include "common_utilities_hpp.h"
22 #include "ui_event_observer_impl.h"
23 #include "cj_lambda.h"
24
25 namespace OHOS::uitest {
26
27 using namespace nlohmann;
28 using namespace std;
29 static map<string, shared_ptr<function<void(CUIElementInfo)>>> g_callbacks;
30 static size_t g_incCbId = 0;
31
Get()32 UiEventObserverImpl &UiEventObserverImpl::Get()
33 {
34 static UiEventObserverImpl instance;
35 return instance;
36 }
37
PreprocessCallOnce(ApiCallInfo & call,int64_t callbackId,ApiCallErr & err)38 void UiEventObserverImpl::PreprocessCallOnce(ApiCallInfo &call, int64_t callbackId, ApiCallErr &err)
39 {
40 auto ¶mList = call.paramList_;
41 if (paramList.size() < 1 || paramList.at(0).type() != detail::value_t::string) {
42 LOG_E("[UiEventObserverImpl]Missing event type argument");
43 err = ApiCallErr(ERR_INVALID_INPUT, "Missing event type argument");
44 return;
45 }
46 auto event = paramList.at(0).get<string>();
47 if (callbackId <= 0) {
48 LOG_E("[UiEventObserverImpl]Invalid callback function argument");
49 err = ApiCallErr(ERR_INVALID_INPUT, "Invalid callback function argument");
50 return;
51 }
52 auto func = reinterpret_cast<void (*)(CUIElementInfo)>(callbackId);
53 auto sp = make_shared<function<void(CUIElementInfo)>>(CJLambda::Create(func));
54 if (sp == nullptr) {
55 err = ApiCallErr(INTERNAL_ERROR, "UIEventObserver memory error.");
56 return;
57 }
58 auto key = string("cj_callback#") + to_string(++g_incCbId);
59 LOG_I("CbId = %{public}s, CbRef = %{public}p", key.c_str(), sp.get());
60 LOG_D("Hold reference of %{public}s", key.c_str());
61 g_callbacks.insert({key, sp});
62 paramList.at(1) = key;
63 }
64
65 struct EventCallbackContext {
66 string observerId;
67 string callbackId;
68 weak_ptr<function<void(CUIElementInfo)>> callbackRef;
69 bool releaseCallback; // if or not release callback function after performing this callback
70 nlohmann::json elmentInfo;
71 };
72
InitCallbackContext(const ApiCallInfo & in,ApiReplyInfo & out,EventCallbackContext & ctx)73 static void InitCallbackContext(const ApiCallInfo &in, ApiReplyInfo &out, EventCallbackContext &ctx)
74 {
75 LOG_I("[UiEventObserverImpl]Handler api callback: %{public}s", in.apiId_.c_str());
76 if (in.apiId_ != "UIEventObserver.once") {
77 out.exception_ = ApiCallErr(ERR_INTERNAL, "Api dose not support callback: " + in.apiId_);
78 LOG_E("%{public}s", out.exception_.message_.c_str());
79 return;
80 }
81 DCHECK(in.paramList_.size() > INDEX_ZERO && in.paramList_.at(INDEX_ZERO).type() == detail::value_t::object);
82 DCHECK(in.paramList_.size() > INDEX_ONE && in.paramList_.at(INDEX_ONE).type() == detail::value_t::string);
83 DCHECK(in.paramList_.size() > INDEX_TWO && in.paramList_.at(INDEX_TWO).type() == detail::value_t::boolean);
84 DCHECK(in.paramList_.size() > INDEX_THREE && in.paramList_.at(INDEX_THREE).type() == detail::value_t::boolean);
85 auto &observerId = in.callerObjRef_;
86 auto &elementInfo = in.paramList_.at(INDEX_ZERO);
87 auto callbackId = in.paramList_.at(INDEX_ONE).get<string>();
88 LOG_I("[UiEventObserverImpl]Begin to callback UiEvent: observer=%{public}s, callback=%{public}s",
89 observerId.c_str(), callbackId.c_str());
90 auto findCallback = g_callbacks.find(callbackId);
91 if (findCallback == g_callbacks.end()) {
92 out.exception_ = ApiCallErr(INTERNAL_ERROR, "JsCallbackFunction is not referenced: " + callbackId);
93 LOG_E("%{public}s", out.exception_.message_.c_str());
94 return;
95 }
96 ctx.observerId = observerId;
97 ctx.callbackId = callbackId;
98 ctx.callbackRef = findCallback->second;
99 ctx.elmentInfo = move(elementInfo);
100 ctx.releaseCallback = in.paramList_.at(INDEX_THREE).get<bool>();
101 }
102
DestructElementInfo(CUIElementInfo & info)103 static void DestructElementInfo(CUIElementInfo &info)
104 {
105 if (info.bundleName != nullptr) {
106 free(info.bundleName);
107 info.bundleName = nullptr;
108 }
109 if (info.componentType != nullptr) {
110 free(info.componentType);
111 info.componentType = nullptr;
112 }
113 if (info.text != nullptr) {
114 free(info.text);
115 info.text = nullptr;
116 }
117 return;
118 }
119
CreateElementInfo(string str)120 static CUIElementInfo CreateElementInfo(string str)
121 {
122 int status = 0;
123 CUIElementInfo result{};
124 auto json = nlohmann::json::parse(str);
125 string bundleName = json["bundleName"];
126 string type = json["type"];
127 string text = json["text"];
128 result.bundleName = static_cast<char *>(malloc(bundleName.size() + 1));
129 if (result.bundleName == nullptr) {
130 LOG_E("[UiEventObserverImpl] memory error.");
131 return result;
132 }
133 result.componentType = static_cast<char *>(malloc(type.size() + 1));
134 if (result.componentType == nullptr) {
135 LOG_E("[UiEventObserverImpl] memory error.");
136 DestructElementInfo(result);
137 return result;
138 }
139 result.text = static_cast<char *>(malloc(text.size() + 1));
140 if (result.text == nullptr) {
141 LOG_E("[UiEventObserverImpl] memory error.");
142 DestructElementInfo(result);
143 return result;
144 }
145 status |= memcpy_s(result.bundleName, bundleName.size() + 1,
146 bundleName.c_str(), bundleName.size() + 1);
147 status |= memcpy_s(result.componentType, type.size() + 1,
148 type.c_str(), type.size() + 1);
149 status |= memcpy_s(result.text, text.size() + 1,
150 text.c_str(), text.size() + 1);
151 if (status != 0) {
152 LOG_E("[UiEventObserverImpl] memory error. %{public}d", status);
153 DestructElementInfo(result);
154 result.bundleName = nullptr;
155 result.componentType = nullptr;
156 result.text = nullptr;
157 }
158 return result;
159 }
160
HandleEventCallback(const ApiCallInfo & in,ApiReplyInfo & out)161 void UiEventObserverImpl::HandleEventCallback(const ApiCallInfo &in, ApiReplyInfo &out)
162 {
163 auto context = new (std::nothrow) EventCallbackContext();
164 if (context == nullptr) {
165 out.exception_ = ApiCallErr(INTERNAL_ERROR, "UIEventObserver memory error.");
166 return;
167 }
168 InitCallbackContext(in, out, *context);
169 if (out.exception_.code_ != NO_ERROR) {
170 delete context;
171 LOG_W("[UiEventObserverImpl]InitCallbackContext failed, cannot perform callback");
172 return;
173 }
174 auto info = CreateElementInfo(context->elmentInfo.dump().c_str());
175 if (info.bundleName == nullptr || info.componentType == nullptr || info.text == nullptr) {
176 delete context;
177 LOG_W("[UiEventObserverImpl]CreateUIElementInfo failed.");
178 out.exception_ = ApiCallErr(INTERNAL_ERROR, "UIEventObserver memory error.");
179 return;
180 }
181 auto callback = context->callbackRef.lock();
182 callback->operator()(info);
183 if (context->releaseCallback) {
184 LOG_D("[UiEventObserverImpl]Unref callback: %{public}s", context->callbackId.c_str());
185 g_callbacks.erase(context->callbackId);
186 }
187 DestructElementInfo(info);
188 delete context;
189 }
190
191 }