• 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_window_extension.h"
17 
18 #include <hitrace_meter.h>
19 #include <napi_common_want.h>
20 #include <native_engine/native_reference.h>
21 #include <native_engine/native_value.h>
22 #include <js_extension_context.h>
23 #include <js_runtime_utils.h>
24 
25 #include "ability_manager_client.h"
26 #include "js_window.h"
27 #include "js_window_extension_context.h"
28 #include "ui_extension_window_command.h"
29 #include "window_extension_connection.h"
30 #include "window_manager_hilog.h"
31 #include "wm_common.h"
32 #include "wm_common_inner.h"
33 #include "window_manager.h"
34 
35 namespace OHOS {
36 namespace Rosen {
37 namespace {
38 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "JSWindowExtension"};
39 }
40 int JsWindowExtension::extensionCnt_ = 0;
41 
42 class DispatchInputEventListener : public IDispatchInputEventListener {
43 public:
OnDispatchPointerEvent(std::shared_ptr<MMI::PointerEvent> & inputEvent)44     void OnDispatchPointerEvent(std::shared_ptr<MMI::PointerEvent>& inputEvent) override
45     {
46         TLOGI(WmsLogTag::WMS_UIEXT, "called");
47     }
OnDispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> & keyEvent)48     void OnDispatchKeyEvent(std::shared_ptr<MMI::KeyEvent>& keyEvent) override
49     {
50         TLOGI(WmsLogTag::WMS_UIEXT, "called");
51     }
52 };
53 
AttachWindowExtensionContext(napi_env env,void * value,void *)54 napi_value AttachWindowExtensionContext(napi_env env, void* value, void *)
55 {
56     TLOGI(WmsLogTag::WMS_UIEXT, "AttachWindowExtensionContext");
57     if (value == nullptr) {
58         TLOGE(WmsLogTag::WMS_UIEXT, "invalid parameter.");
59         return nullptr;
60     }
61     auto ptr = reinterpret_cast<std::weak_ptr<WindowExtensionContext> *>(value)->lock();
62     if (ptr == nullptr) {
63         TLOGE(WmsLogTag::WMS_UIEXT, "invalid context.");
64         return nullptr;
65     }
66     napi_value object = CreateJsWindowExtensionContext(env, ptr);
67     if (object == nullptr) {
68         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get js window extension context");
69         return nullptr;
70     }
71     auto contextObjRef = AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(env,
72         "application.WindowExtensionContext", &object, 1);
73     if (contextObjRef == nullptr) {
74         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get contextObjRef");
75         return nullptr;
76     }
77     auto contextObj = contextObjRef->GetNapiValue();
78     if (contextObj == nullptr) {
79         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get context native object");
80         return nullptr;
81     }
82     napi_coerce_to_native_binding_object(env, contextObj,
83         AbilityRuntime::DetachCallbackFunc, AttachWindowExtensionContext, value, nullptr);
84     auto workContext = new (std::nothrow) std::weak_ptr<WindowExtensionContext>(ptr);
85     if (workContext == nullptr) {
86         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get window extension context");
87         return nullptr;
88     }
89     napi_status status = napi_wrap(env, contextObj, workContext,
90         [](napi_env, void* data, void *) {
91             TLOGI(WmsLogTag::WMS_UIEXT, "Finalizer for weak_ptr service extension context is called");
92             delete static_cast<std::weak_ptr<WindowExtensionContext> *>(data);
93         }, nullptr, nullptr);
94     if (status != napi_ok) {
95         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to call napi_wrap");
96         delete workContext;
97         return nullptr;
98     }
99     return contextObj;
100 }
101 
Create(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)102 JsWindowExtension* JsWindowExtension::Create(const std::unique_ptr<AbilityRuntime::Runtime>& runtime)
103 {
104     TLOGD(WmsLogTag::WMS_UIEXT, "Create runtime");
105     return new JsWindowExtension(static_cast<AbilityRuntime::JsRuntime&>(*runtime));
106 }
107 
JsWindowExtension(AbilityRuntime::JsRuntime & jsRuntime)108 JsWindowExtension::JsWindowExtension(AbilityRuntime::JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
~JsWindowExtension()109 JsWindowExtension::~JsWindowExtension()
110 {
111     TLOGD(WmsLogTag::WMS_UIEXT, "Called");
112     auto context = GetContext();
113     if (context) {
114         context->Unbind();
115     }
116     jsRuntime_.FreeNativeReference(std::move(jsObj_));
117 }
118 
Init(const std::shared_ptr<AbilityRuntime::AbilityLocalRecord> & record,const std::shared_ptr<AbilityRuntime::OHOSApplication> & application,std::shared_ptr<AbilityRuntime::AbilityHandler> & handler,const sptr<IRemoteObject> & token)119 void JsWindowExtension::Init(const std::shared_ptr<AbilityRuntime::AbilityLocalRecord>& record,
120     const std::shared_ptr<AbilityRuntime::OHOSApplication>& application,
121     std::shared_ptr<AbilityRuntime::AbilityHandler>& handler,
122     const sptr<IRemoteObject>& token)
123 {
124     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "WindowExtension Init");
125     WindowExtension::Init(record, application, handler, token);
126     std::string srcPath;
127     GetSrcPath(srcPath);
128     if (srcPath.empty()) {
129         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get srcPath");
130         return;
131     }
132     if (Extension::abilityInfo_ == nullptr) {
133         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get abilityInfo");
134         return;
135     }
136     if (abilityInfo_ == nullptr) {
137         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get abilityInfo_");
138         return;
139     }
140     std::string moduleName(Extension::abilityInfo_->moduleName);
141     moduleName.append("::").append(abilityInfo_->name);
142     TLOGI(WmsLogTag::WMS_UIEXT, "JsWindowExtension::Init module:%{public}s,srcPath:%{public}s.",
143         moduleName.c_str(), srcPath.c_str());
144     AbilityRuntime::HandleScope handleScope(jsRuntime_);
145 
146     jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
147         abilityInfo_->compileMode == AbilityRuntime::CompileMode::ES_MODULE);
148     if (jsObj_ == nullptr) {
149         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get jsObj_");
150         return;
151     }
152     TLOGI(WmsLogTag::WMS_UIEXT, "JsWindowExtension::Init ConvertNativeValueTo.");
153     napi_env env = jsRuntime_.GetNapiEnv();
154     napi_value obj = jsObj_->GetNapiValue();
155     if (obj == nullptr) {
156         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get JsWindowExtension object");
157         return;
158     }
159 
160     BindContext(env, obj);
161 }
162 
BindContext(napi_env env,napi_value obj)163 void JsWindowExtension::BindContext(napi_env env, napi_value obj)
164 {
165     auto context = GetContext();
166     if (context == nullptr) {
167         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get context");
168         return;
169     }
170 
171     napi_value contextObj = CreateJsWindowExtensionContext(jsRuntime_.GetNapiEnv(), context);
172     if (contextObj == nullptr) {
173         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get js window extension context");
174         return;
175     }
176     auto shellContextRef = jsRuntime_.LoadSystemModule("application.WindowExtensionContext", &contextObj, 1);
177     if (shellContextRef == nullptr) {
178         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get shell context");
179         return;
180     }
181     contextObj = shellContextRef->GetNapiValue();
182     if (contextObj == nullptr) {
183         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get context native object");
184         return;
185     }
186     auto workContext = new (std::nothrow) std::weak_ptr<WindowExtensionContext>(context);
187     if (workContext == nullptr) {
188         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get window extension context");
189         return;
190     }
191     napi_coerce_to_native_binding_object(env, contextObj,
192         AbilityRuntime::DetachCallbackFunc, AttachWindowExtensionContext, workContext, nullptr);
193     TLOGI(WmsLogTag::WMS_UIEXT, "JsWindowExtension::Init Bind.");
194     context->Bind(jsRuntime_, shellContextRef.release());
195     TLOGI(WmsLogTag::WMS_UIEXT, "JsWindowExtension::SetProperty.");
196     napi_set_named_property(env, obj, "context", contextObj);
197 
198     napi_status status = napi_wrap(env, contextObj, workContext,
199         [](napi_env, void* data, void *) {
200             TLOGI(WmsLogTag::WMS_UIEXT, "Finalizer for weak_ptr extension context is called");
201             delete static_cast<std::weak_ptr<WindowExtensionContext>*>(data);
202         }, nullptr, nullptr);
203     if (status != napi_ok) {
204         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to call napi_wrap");
205         delete workContext;
206         return;
207     }
208     TLOGI(WmsLogTag::WMS_UIEXT, "JsWindowExtension::Init end.");
209 }
210 
GetSrcPath(std::string & srcPath) const211 void JsWindowExtension::GetSrcPath(std::string& srcPath) const
212 {
213     if (!Extension::abilityInfo_) {
214         TLOGE(WmsLogTag::WMS_UIEXT, "abilityInfo_ is nullptr");
215         return;
216     }
217 
218     if (!Extension::abilityInfo_->isModuleJson) {
219         srcPath.append(Extension::abilityInfo_->package);
220         srcPath.append("/assets/js/");
221         if (!Extension::abilityInfo_->srcPath.empty()) {
222             srcPath.append(Extension::abilityInfo_->srcPath);
223         }
224         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
225         return;
226     }
227 
228     if (!Extension::abilityInfo_->srcEntrance.empty()) {
229         srcPath.append(Extension::abilityInfo_->moduleName + "/");
230         srcPath.append(Extension::abilityInfo_->srcEntrance);
231         srcPath.erase(srcPath.rfind('.'));
232         srcPath.append(".abc");
233     }
234 }
235 
OnConnect(const AAFwk::Want & want)236 sptr<IRemoteObject> JsWindowExtension::OnConnect(const AAFwk::Want& want)
237 {
238     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "WindowExtension OnConnect %s-%s",
239         want.GetElement().GetAbilityName().c_str(), want.GetElement().GetAbilityName().c_str());
240     TLOGI(WmsLogTag::WMS_UIEXT, "called.");
241     Extension::OnConnect(want);
242     napi_env env = jsRuntime_.GetNapiEnv();
243     if (!jsObj_) {
244         TLOGW(WmsLogTag::WMS_UIEXT, "Not found WindowExtension.js");
245         return nullptr;
246     }
247     napi_value value = jsObj_->GetNapiValue();
248     auto jsCallback = [want, env, value] {
249         napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
250         napi_value argv[] = { napiWant };
251         CallJsMethod("onConnect", argv, AbilityRuntime::ArraySize(argv), env, value);
252     };
253     if (napi_send_event(env, jsCallback, napi_eprio_high, "OnConnect") != napi_status::napi_ok) {
254         WLOGE("send event failed");
255     }
256 
257     if (!stub_) {
258         TLOGE(WmsLogTag::WMS_UIEXT, "stub is nullptr.");
259         return nullptr;
260     }
261     TLOGD(WmsLogTag::WMS_UIEXT, "Create stub successfully!");
262     WindowManager::GetInstance().NotifyWindowExtensionVisibilityChange(getprocpid(), getuid(), true);
263     auto context = GetContext();
264     if (context == nullptr) {
265         TLOGE(WmsLogTag::WMS_UIEXT, "context is nullptr.");
266         return nullptr;
267     }
268     auto client = AAFwk::AbilityManagerClient::GetInstance();
269     if (client == nullptr) {
270         TLOGE(WmsLogTag::WMS_UIEXT, "client is nullptr.");
271         return nullptr;
272     }
273     client->ScheduleCommandAbilityWindowDone(
274         context->GetToken(), sessionInfo_, AAFwk::WIN_CMD_FOREGROUND, AAFwk::ABILITY_CMD_FOREGROUND);
275     return stub_->AsObject();
276 }
277 
OnDisconnect(const AAFwk::Want & want)278 void JsWindowExtension::OnDisconnect(const AAFwk::Want& want)
279 {
280     Extension::OnDisconnect(want);
281     napi_env env = jsRuntime_.GetNapiEnv();
282     if (!jsObj_) {
283         TLOGW(WmsLogTag::WMS_UIEXT, "Not found WindowExtension.js");
284         return;
285     }
286     napi_value value = jsObj_->GetNapiValue();
287     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
288     napi_value argv[] = { napiWant };
289     CallJsMethod("onDisconnect", argv, AbilityRuntime::ArraySize(argv), env, value);
290     auto window = stub_ != nullptr ? stub_->GetWindow() : nullptr;
291     if (window != nullptr) {
292         window->Destroy();
293         TLOGI(WmsLogTag::WMS_UIEXT, "Destroy window.");
294     }
295     TLOGI(WmsLogTag::WMS_UIEXT, "called.");
296     WindowManager::GetInstance().NotifyWindowExtensionVisibilityChange(getprocpid(), getuid(), false);
297     auto context = GetContext();
298     if (context == nullptr) {
299         TLOGE(WmsLogTag::WMS_UIEXT, "context is nullptr.");
300         return;
301     }
302     auto client = AAFwk::AbilityManagerClient::GetInstance();
303     if (client == nullptr) {
304         TLOGE(WmsLogTag::WMS_UIEXT, "client is nullptr.");
305         return;
306     }
307     client->ScheduleCommandAbilityWindowDone(
308         context->GetToken(), sessionInfo_, AAFwk::WIN_CMD_DESTROY, AAFwk::ABILITY_CMD_DESTROY);
309 }
310 
OnStart(const AAFwk::Want & want,sptr<AAFwk::SessionInfo> sessionInfo)311 void JsWindowExtension::OnStart(const AAFwk::Want& want, sptr<AAFwk::SessionInfo> sessionInfo)
312 {
313     TLOGI(WmsLogTag::WMS_UIEXT, "OnStart");
314     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "WindowExtension OnStart %s-%s",
315         want.GetElement().GetAbilityName().c_str(), want.GetElement().GetAbilityName().c_str());
316     sessionInfo_ = sessionInfo;
317     Extension::OnStart(want);
318 
319     AbilityRuntime::ElementName elementName = want.GetElement();
320     std::string windowName = elementName.GetBundleName() + elementName.GetModuleName() +
321         elementName.GetAbilityName() + std::to_string(extensionCnt_);
322     extensionCnt_++;
323 
324     stub_ = new(std::nothrow) WindowExtensionStubImpl(windowName);
325     TLOGI(WmsLogTag::WMS_UIEXT, "JsWindowExtension OnStart begin..");
326     Rect rect { want.GetIntParam(RECT_FORM_KEY_POS_X, 0),
327     want.GetIntParam(RECT_FORM_KEY_POS_Y, 0),
328     want.GetIntParam(RECT_FORM_KEY_WIDTH, 0),
329     want.GetIntParam(RECT_FORM_KEY_HEIGHT, 0) };
330     uint32_t windowId = static_cast<uint32_t>(want.GetIntParam(WINDOW_ID, INVALID_WINDOW_ID));
331     if (stub_ != nullptr) {
332         auto context = GetContext();
333         if (context == nullptr) {
334             TLOGE(WmsLogTag::WMS_UIEXT, "get context failed");
335             return;
336         }
337         sptr<Window> window = stub_->CreateWindow(rect, windowId, context,
338             sessionInfo == nullptr ? nullptr : sessionInfo->sessionToken);
339         if (window == nullptr) {
340             TLOGE(WmsLogTag::WMS_UIEXT, "create window failed");
341             return;
342         }
343         OnWindowCreated();
344         TLOGI(WmsLogTag::WMS_UIEXT,
345             "ability context onWindowReady rect x =%{public}d y=%{public}d w=%{public}d h=%{public}d ",
346             rect.posX_, rect.posY_, rect.width_, rect.height_);
347     }
348 }
349 
OnWindowCreated() const350 void JsWindowExtension::OnWindowCreated() const
351 {
352     napi_env env = jsRuntime_.GetNapiEnv();
353     if (stub_ == nullptr) {
354         WLOGE("stub is nullptr");
355         return;
356     }
357     auto jsCallback = [stub = stub_, env] {
358         auto window = stub->GetWindow();
359         if (window == nullptr) {
360             WLOGE("get window failed");
361             return;
362         }
363         napi_value value = CreateJsWindowObject(env, window);
364         if (value == nullptr) {
365             WLOGE("Create js window failed");
366             return;
367         }
368         napi_value argv[] = { value };
369         CallJsMethod("onWindowReady", argv, AbilityRuntime::ArraySize(argv), env, value);
370     };
371     if (napi_send_event(env, jsCallback, napi_eprio_high, "OnWindowCreated") != napi_status::napi_ok) {
372         WLOGE("send event failed");
373     }
374 }
375 
GetType(napi_env env,napi_value value)376 napi_valuetype GetType(napi_env env, napi_value value)
377 {
378     napi_valuetype res = napi_undefined;
379     napi_typeof(env, value, &res);
380     return res;
381 }
382 
CallJsMethod(const char * name,napi_value const * argv,size_t argc,napi_env env,napi_value value)383 napi_value CallJsMethod(const char* name, napi_value const * argv, size_t argc,
384     napi_env env, napi_value value)
385 {
386     TLOGI(WmsLogTag::WMS_UIEXT, "called (%{public}s), begin", name);
387     if (value == nullptr) {
388         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get WindowExtension object");
389         return nullptr;
390     }
391 
392     napi_value method = nullptr;
393     napi_get_named_property(env, value, name, &method);
394     if (method == nullptr || GetType(env, method) != napi_function) {
395         TLOGE(WmsLogTag::WMS_UIEXT, "Failed to get '%{public}s' from WindowExtension object", name);
396         return nullptr;
397     }
398     TLOGI(WmsLogTag::WMS_UIEXT, "(%{public}s), success", name);
399     napi_value result = nullptr;
400     napi_call_function(env, value, method, argc, argv, &result);
401     return result;
402 }
403 } // namespace Rosen
404 } // namespace OHOS
405