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