• 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) { free(info.bundleName); }
106     if (info.componentType != nullptr) { free(info.componentType); }
107     if (info.text != nullptr) { free(info.text); }
108     return;
109 }
110 
CreateElementInfo(string str)111 static CUIElementInfo CreateElementInfo(string str)
112 {
113     int status = 0;
114     CUIElementInfo result{};
115     auto json = nlohmann::json::parse(str);
116     string bundleName = json["bundleName"];
117     string type = json["type"];
118     string text = json["text"];
119     result.bundleName = static_cast<char *>(malloc(bundleName.size() + 1));
120     if (result.bundleName == nullptr) {
121         LOG_E("[UiEventObserverImpl] memory error.");
122         return result;
123     }
124     result.componentType = static_cast<char *>(malloc(type.size() + 1));
125     if (result.componentType == nullptr) {
126         LOG_E("[UiEventObserverImpl] memory error.");
127         DestructElementInfo(result);
128         return result;
129     }
130     result.text = static_cast<char *>(malloc(text.size() + 1));
131     if (result.text == nullptr) {
132         LOG_E("[UiEventObserverImpl] memory error.");
133         DestructElementInfo(result);
134         return result;
135     }
136     status |= memcpy_s(result.bundleName, bundleName.size() + 1,
137         bundleName.c_str(), bundleName.size() + 1);
138     status |= memcpy_s(result.componentType, type.size() + 1,
139         type.c_str(), type.size() + 1);
140     status |= memcpy_s(result.text, text.size() + 1,
141         text.c_str(), text.size() + 1);
142     if (status != 0) {
143         LOG_E("[UiEventObserverImpl] memory error. %{public}d", status);
144         DestructElementInfo(result);
145         result.bundleName = nullptr;
146         result.componentType = nullptr;
147         result.text = nullptr;
148     }
149     return result;
150 }
151 
HandleEventCallback(const ApiCallInfo & in,ApiReplyInfo & out)152 void UiEventObserverImpl::HandleEventCallback(const ApiCallInfo &in, ApiReplyInfo &out)
153 {
154     auto context = new (std::nothrow) EventCallbackContext();
155     if (context == nullptr) {
156         out.exception_ = ApiCallErr(INTERNAL_ERROR, "UIEventObserver memory error.");
157         return;
158     }
159     InitCallbackContext(in, out, *context);
160     if (out.exception_.code_ != NO_ERROR) {
161         delete context;
162         LOG_W("[UiEventObserverImpl]InitCallbackContext failed, cannot perform callback");
163         return;
164     }
165     auto info = CreateElementInfo(context->elmentInfo.dump().c_str());
166     if (info.bundleName == nullptr || info.componentType == nullptr || info.text == nullptr) {
167         delete context;
168         LOG_W("[UiEventObserverImpl]CreateUIElementInfo failed.");
169         out.exception_ = ApiCallErr(INTERNAL_ERROR, "UIEventObserver memory error.");
170         return;
171     }
172     auto callback = context->callbackRef.lock();
173     callback->operator()(info);
174     if (context->releaseCallback) {
175         LOG_D("[UiEventObserverImpl]Unref callback: %{public}s", context->callbackId.c_str());
176         g_callbacks.erase(context->callbackId);
177     }
178     DestructElementInfo(info);
179     delete context;
180 }
181 
182 }