• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &paramList = 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 }