• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "js_inputmethod_extension.h"
17 
18 #include "ability_info.h"
19 #include "global.h"
20 #include "input_method_ability.h"
21 #include "inputmethod_trace.h"
22 #include "js_inputmethod_extension_context.h"
23 #include "js_runtime.h"
24 #include "js_runtime_utils.h"
25 #include "napi/native_api.h"
26 #include "napi/native_node_api.h"
27 #include "napi_common_util.h"
28 #include "napi_common_want.h"
29 #include "napi_remote_object.h"
30 
31 namespace OHOS {
32 namespace AbilityRuntime {
33 namespace {
34 constexpr size_t ARGC_ONE = 1;
35 constexpr size_t ARGC_TWO = 2;
36 }
37 JsInputMethodExtension *JsInputMethodExtension::jsInputMethodExtension = nullptr;
38 using namespace OHOS::AppExecFwk;
39 using namespace OHOS::MiscServices;
40 
AttachInputMethodExtensionContext(NativeEngine * engine,void * value,void *)41 NativeValue *AttachInputMethodExtensionContext(NativeEngine *engine, void *value, void *)
42 {
43     IMSA_HILOGI("AttachInputMethodExtensionContext");
44     if (value == nullptr) {
45         IMSA_HILOGW("invalid parameter.");
46         return nullptr;
47     }
48     auto ptr = reinterpret_cast<std::weak_ptr<InputMethodExtensionContext> *>(value)->lock();
49     if (ptr == nullptr) {
50         IMSA_HILOGW("invalid context.");
51         return nullptr;
52     }
53     NativeValue *object = CreateJsInputMethodExtensionContext(*engine, ptr);
54     auto contextObj = JsRuntime::LoadSystemModuleByEngine(engine, "InputMethodExtensionContext", &object, 1)->Get();
55     NativeObject *nObject = ConvertNativeValueTo<NativeObject>(contextObj);
56     nObject->ConvertToNativeBindingObject(
57         engine, DetachCallbackFunc, AttachInputMethodExtensionContext, value, nullptr);
58     auto workContext = new (std::nothrow) std::weak_ptr<InputMethodExtensionContext>(ptr);
59     nObject->SetNativePointer(
60         workContext,
61         [](NativeEngine *, void *data, void *) {
62             IMSA_HILOGI("Finalizer for weak_ptr input method extension context is called");
63             delete static_cast<std::weak_ptr<InputMethodExtensionContext> *>(data);
64         },
65         nullptr);
66     return contextObj;
67 }
68 
Create(const std::unique_ptr<Runtime> & runtime)69 JsInputMethodExtension *JsInputMethodExtension::Create(const std::unique_ptr<Runtime> &runtime)
70 {
71     IMSA_HILOGI("JsInputMethodExtension Create");
72     jsInputMethodExtension = new JsInputMethodExtension(static_cast<JsRuntime &>(*runtime));
73     return jsInputMethodExtension;
74 }
75 
JsInputMethodExtension(JsRuntime & jsRuntime)76 JsInputMethodExtension::JsInputMethodExtension(JsRuntime &jsRuntime) : jsRuntime_(jsRuntime)
77 {
78 }
79 
~JsInputMethodExtension()80 JsInputMethodExtension::~JsInputMethodExtension()
81 {
82     jsRuntime_.FreeNativeReference(std::move(jsObj_));
83 }
84 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)85 void JsInputMethodExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
86     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
87     const sptr<IRemoteObject> &token)
88 {
89     IMSA_HILOGI("JsInputMethodExtension Init");
90     InputMethodExtension::Init(record, application, handler, token);
91     std::string srcPath;
92     GetSrcPath(srcPath);
93     if (srcPath.empty()) {
94         IMSA_HILOGE("Failed to get srcPath");
95         return;
96     }
97 
98     std::string moduleName(Extension::abilityInfo_->moduleName);
99     moduleName.append("::").append(abilityInfo_->name);
100     IMSA_HILOGI(
101         "JsInputMethodExtension::Init module:%{public}s,srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
102     HandleScope handleScope(jsRuntime_);
103     auto &engine = jsRuntime_.GetNativeEngine();
104 
105     jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
106         abilityInfo_->compileMode == CompileMode::ES_MODULE);
107     if (jsObj_ == nullptr) {
108         IMSA_HILOGE("Failed to get jsObj_");
109         return;
110     }
111     IMSA_HILOGI("JsInputMethodExtension::Init ConvertNativeValueTo.");
112     NativeObject *obj = ConvertNativeValueTo<NativeObject>(jsObj_->Get());
113     if (obj == nullptr) {
114         IMSA_HILOGE("Failed to get JsInputMethodExtension object");
115         return;
116     }
117     BindContext(engine, obj);
118     IMSA_HILOGI("JsInputMethodExtension::Init end.");
119 }
120 
BindContext(NativeEngine & engine,NativeObject * obj)121 void JsInputMethodExtension::BindContext(NativeEngine &engine, NativeObject *obj)
122 {
123     IMSA_HILOGI("JsInputMethodExtension::BindContext");
124     auto context = GetContext();
125     if (context == nullptr) {
126         IMSA_HILOGE("Failed to get context");
127         return;
128     }
129     IMSA_HILOGI("JsInputMethodExtension::Init CreateJsInputMethodExtensionContext.");
130     NativeValue *contextObj = CreateJsInputMethodExtensionContext(engine, context);
131     auto shellContextRef = jsRuntime_.LoadSystemModule("InputMethodExtensionContext", &contextObj, ARGC_ONE);
132     contextObj = shellContextRef->Get();
133     auto nativeObj = ConvertNativeValueTo<NativeObject>(contextObj);
134     if (nativeObj == nullptr) {
135         IMSA_HILOGE("Failed to get input method extension native object");
136         return;
137     }
138     auto workContext = new (std::nothrow) std::weak_ptr<InputMethodExtensionContext>(context);
139     nativeObj->ConvertToNativeBindingObject(
140         &engine, DetachCallbackFunc, AttachInputMethodExtensionContext, workContext, nullptr);
141     IMSA_HILOGI("JsInputMethodExtension::Init Bind.");
142     context->Bind(jsRuntime_, shellContextRef.release());
143     IMSA_HILOGI("JsInputMethodExtension::SetProperty.");
144     obj->SetProperty("context", contextObj);
145     nativeObj->SetNativePointer(
146         workContext,
147         [](NativeEngine *, void *data, void *) {
148             IMSA_HILOGI("Finalizer for weak_ptr input method extension context is called");
149             delete static_cast<std::weak_ptr<InputMethodExtensionContext> *>(data);
150         },
151         nullptr);
152 }
153 
OnStart(const AAFwk::Want & want)154 void JsInputMethodExtension::OnStart(const AAFwk::Want &want)
155 {
156     StartAsync(HITRACE_TAG_MISC, "OnStart", static_cast<int32_t>(TraceTaskId::ONSTART_EXTENSION));
157     StartAsync(
158         HITRACE_TAG_MISC, "Extension::OnStart", static_cast<int32_t>(TraceTaskId::ONSTART_MIDDLE_EXTENSION));
159     Extension::OnStart(want);
160     FinishAsync(
161         HITRACE_TAG_MISC, "Extension::OnStart", static_cast<int32_t>(TraceTaskId::ONSTART_MIDDLE_EXTENSION));
162     IMSA_HILOGI("JsInputMethodExtension OnStart begin..");
163     HandleScope handleScope(jsRuntime_);
164     NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
165     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
166     NativeValue *nativeWant = reinterpret_cast<NativeValue *>(napiWant);
167     NativeValue *argv[] = { nativeWant };
168     StartAsync(HITRACE_TAG_MISC, "onCreate", static_cast<int32_t>(TraceTaskId::ONCREATE_EXTENSION));
169     CallObjectMethod("onCreate", argv, ARGC_ONE);
170     auto ret = InputMethodAbility::GetInstance()->SetCoreAndAgent();
171     IMSA_HILOGI("ime bind imf ret: %{public}d", ret);
172     InputMethodAbility::GetInstance()->OnImeReady();
173     FinishAsync(HITRACE_TAG_MISC, "onCreate", static_cast<int32_t>(TraceTaskId::ONSTART_EXTENSION));
174 }
175 
OnStop()176 void JsInputMethodExtension::OnStop()
177 {
178     InputMethodExtension::OnStop();
179     IMSA_HILOGI("JsInputMethodExtension OnStop begin.");
180     CallObjectMethod("onDestroy");
181     bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
182     if (ret) {
183         IMSA_HILOGI("The input method extension connection is not disconnected.");
184     }
185     IMSA_HILOGI("JsInputMethodExtension %{public}s end.", __func__);
186 }
187 
OnConnect(const AAFwk::Want & want)188 sptr<IRemoteObject> JsInputMethodExtension::OnConnect(const AAFwk::Want &want)
189 {
190     IMSA_HILOGI("JsInputMethodExtension OnConnect begin.");
191     StartAsync(HITRACE_TAG_MISC, "OnConnect", static_cast<int32_t>(TraceTaskId::ONCONNECT_EXTENSION));
192     StartAsync(
193         HITRACE_TAG_MISC, "Extension::OnConnect", static_cast<int32_t>(TraceTaskId::ONCONNECT_MIDDLE_EXTENSION));
194     Extension::OnConnect(want);
195     FinishAsync(
196         HITRACE_TAG_MISC, "Extension::OnConnect", static_cast<int32_t>(TraceTaskId::ONCONNECT_MIDDLE_EXTENSION));
197     IMSA_HILOGI("%{public}s begin.", __func__);
198     HandleScope handleScope(jsRuntime_);
199     NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
200     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
201     NativeValue *nativeWant = reinterpret_cast<NativeValue *>(napiWant);
202     NativeValue *argv[] = { nativeWant };
203     if (!jsObj_) {
204         IMSA_HILOGW("Not found InputMethodExtension.js");
205         return nullptr;
206     }
207 
208     NativeValue *value = jsObj_->Get();
209     NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
210     if (obj == nullptr) {
211         IMSA_HILOGE("Failed to get InputMethodExtension object");
212         return nullptr;
213     }
214 
215     NativeValue *method = obj->GetProperty("onConnect");
216     if (method == nullptr) {
217         IMSA_HILOGE("Failed to get onConnect from InputMethodExtension object");
218         return nullptr;
219     }
220     IMSA_HILOGI("JsInputMethodExtension::CallFunction onConnect, success");
221     NativeValue *remoteNative = nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
222     if (remoteNative == nullptr) {
223         IMSA_HILOGE("remoteNative nullptr.");
224     }
225     auto remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(
226         reinterpret_cast<napi_env>(nativeEngine), reinterpret_cast<napi_value>(remoteNative));
227     if (remoteObj == nullptr) {
228         IMSA_HILOGE("remoteObj nullptr.");
229     }
230     FinishAsync(HITRACE_TAG_MISC, "OnConnect", static_cast<int32_t>(TraceTaskId::ONCONNECT_EXTENSION));
231     return remoteObj;
232 }
233 
OnDisconnect(const AAFwk::Want & want)234 void JsInputMethodExtension::OnDisconnect(const AAFwk::Want &want)
235 {
236     IMSA_HILOGI("JsInputMethodExtension OnDisconnect begin.");
237     Extension::OnDisconnect(want);
238     IMSA_HILOGI("%{public}s begin.", __func__);
239     HandleScope handleScope(jsRuntime_);
240     NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
241     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
242     NativeValue *nativeWant = reinterpret_cast<NativeValue *>(napiWant);
243     NativeValue *argv[] = { nativeWant };
244     if (!jsObj_) {
245         IMSA_HILOGW("Not found InputMethodExtension.js");
246         return;
247     }
248 
249     NativeValue *value = jsObj_->Get();
250     NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
251     if (obj == nullptr) {
252         IMSA_HILOGE("Failed to get InputMethodExtension object");
253         return;
254     }
255 
256     NativeValue *method = obj->GetProperty("onDisconnect");
257     if (method == nullptr) {
258         IMSA_HILOGE("Failed to get onDisconnect from InputMethodExtension object");
259         return;
260     }
261     nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
262     IMSA_HILOGI("%{public}s end.", __func__);
263 }
264 
OnCommand(const AAFwk::Want & want,bool restart,int startId)265 void JsInputMethodExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
266 {
267     IMSA_HILOGI("JsInputMethodExtension OnCommand begin.");
268     Extension::OnCommand(want, restart, startId);
269     IMSA_HILOGI(
270         "%{public}s begin restart=%{public}s,startId=%{public}d.", __func__, restart ? "true" : "false", startId);
271     HandleScope handleScope(jsRuntime_);
272     NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
273     napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
274     NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
275     napi_value napiStartId = nullptr;
276     napi_create_int32(reinterpret_cast<napi_env>(nativeEngine), startId, &napiStartId);
277     NativeValue* nativeStartId = reinterpret_cast<NativeValue*>(napiStartId);
278     NativeValue* argv[] = {nativeWant, nativeStartId};
279     CallObjectMethod("onRequest", argv, ARGC_TWO);
280     IMSA_HILOGI("%{public}s end.", __func__);
281 }
282 
CallObjectMethod(const char * name,NativeValue * const * argv,size_t argc)283 NativeValue *JsInputMethodExtension::CallObjectMethod(const char *name, NativeValue *const *argv, size_t argc)
284 {
285     IMSA_HILOGI("JsInputMethodExtension::CallObjectMethod(%{public}s), begin", name);
286 
287     if (!jsObj_) {
288         IMSA_HILOGW("Not found InputMethodExtension.js");
289         return nullptr;
290     }
291 
292     HandleScope handleScope(jsRuntime_);
293     auto &nativeEngine = jsRuntime_.GetNativeEngine();
294 
295     NativeValue *value = jsObj_->Get();
296     NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
297     if (obj == nullptr) {
298         IMSA_HILOGE("Failed to get InputMethodExtension object");
299         return nullptr;
300     }
301 
302     NativeValue *method = obj->GetProperty(name);
303     if (method == nullptr) {
304         IMSA_HILOGE("Failed to get '%{public}s' from InputMethodExtension object", name);
305         return nullptr;
306     }
307     IMSA_HILOGI("JsInputMethodExtension::CallFunction(%{public}s), success", name);
308     return nativeEngine.CallFunction(value, method, argv, argc);
309 }
310 
GetSrcPath(std::string & srcPath)311 void JsInputMethodExtension::GetSrcPath(std::string &srcPath)
312 {
313     IMSA_HILOGI("JsInputMethodExtension GetSrcPath begin.");
314     if (!Extension::abilityInfo_->isModuleJson) {
315         /* temporary compatibility api8 + config.json */
316         srcPath.append(Extension::abilityInfo_->package);
317         srcPath.append("/assets/js/");
318         if (!Extension::abilityInfo_->srcPath.empty()) {
319             srcPath.append(Extension::abilityInfo_->srcPath);
320         }
321         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
322         return;
323     }
324 
325     if (!Extension::abilityInfo_->srcEntrance.empty()) {
326         srcPath.append(Extension::abilityInfo_->moduleName + "/");
327         srcPath.append(Extension::abilityInfo_->srcEntrance);
328         srcPath.erase(srcPath.rfind('.'));
329         srcPath.append(".abc");
330     }
331 }
332 } // namespace AbilityRuntime
333 } // namespace OHOS
334