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_context.h"
17 #include "js_window_extension.h"
18
19 #include <js_runtime_utils.h>
20 #include <js_extension_context.h>
21
22 #include "napi_common_start_options.h"
23 #include "napi_common_want.h"
24 #include "permission.h"
25 #include "service_extension_context.h"
26 #include "start_options.h"
27 #include "window_manager_hilog.h"
28
29 namespace OHOS {
30 namespace Rosen {
31 using namespace AbilityRuntime;
32
33 namespace {
34 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "JSWindowExtensionContext"};
35 std::shared_ptr<AppExecFwk::EventHandler> handler_;
36 constexpr int32_t MIN_ARG_COUNT = 2;
37 }
38
NapiGetUndefined(napi_env env)39 napi_value NapiGetUndefined(napi_env env)
40 {
41 napi_value result = nullptr;
42 napi_get_undefined(env, &result);
43 return result;
44 }
45
46 class JsWindowExtensionContext final {
47 public:
JsWindowExtensionContext(const std::shared_ptr<WindowExtensionContext> & context)48 explicit JsWindowExtensionContext(
49 const std::shared_ptr<WindowExtensionContext>& context) : context_(context) {}
50 ~JsWindowExtensionContext() = default;
51
Finalizer(napi_env env,void * data,void * hint)52 static void Finalizer(napi_env env, void* data, void* hint)
53 {
54 WLOGI("JsWindowExtensionContext::Finalizer is called");
55 std::unique_ptr<JsWindowExtensionContext>(static_cast<JsWindowExtensionContext*>(data));
56 }
57
StartAbility(napi_env env,napi_callback_info info)58 static napi_value StartAbility(napi_env env, napi_callback_info info)
59 {
60 JsWindowExtensionContext* me = CheckParamsAndGetThis<JsWindowExtensionContext>(env, info);
61 return (me != nullptr) ? me->OnStartAbility(env, info) : nullptr;
62 }
63 private:
64 std::weak_ptr<WindowExtensionContext> context_;
65
CheckStartAbilityInputParam(napi_env env,napi_callback_info info,AAFwk::Want & want,AAFwk::StartOptions & startOptions) const66 bool CheckStartAbilityInputParam(
67 napi_env env, napi_callback_info info,
68 AAFwk::Want& want, AAFwk::StartOptions& startOptions) const
69 {
70 size_t argc = 2; // 2 : max param number
71 napi_value argv[2] = {nullptr}; // 2 : max param number
72 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
73 if (argc < 1) {
74 return false;
75 }
76 // Check input want
77 if (!CheckWantParam(env, argv[0], want)) {
78 return false;
79 }
80 if (argc > 1 && GetType(env, argv[1]) == napi_object) {
81 WLOGI("OnStartAbility start options is used.");
82 AppExecFwk::UnwrapStartOptions(env, argv[1], startOptions);
83 }
84 return true;
85 }
86
CheckWantParam(napi_env env,napi_value value,AAFwk::Want & want) const87 bool CheckWantParam(napi_env env, napi_value value, AAFwk::Want& want) const
88 {
89 if (!OHOS::AppExecFwk::UnwrapWant(env, value, want)) {
90 WLOGFE("The input want is invalid.");
91 return false;
92 }
93 WLOGI("UnwrapWant, BundleName: %{public}s, AbilityName: %{public}s.",
94 want.GetBundle().c_str(),
95 want.GetElement().GetAbilityName().c_str());
96 return true;
97 }
98
OnStartAbility(napi_env env,napi_callback_info info)99 napi_value OnStartAbility(napi_env env, napi_callback_info info)
100 {
101 if (!Permission::IsSystemCalling()) {
102 TLOGE(WmsLogTag::DEFAULT, "Permission denied!");
103 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_NOT_SYSTEM_APP)));
104 return NapiGetUndefined(env);
105 }
106 WLOGI("OnStartAbility is called");
107 size_t argc = 4;
108 napi_value argv[4] = {nullptr};
109 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
110 if (argc < MIN_ARG_COUNT) { // at least two argc
111 WLOGFE("Start ability failed, not enough params.");
112 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
113 return NapiGetUndefined(env);
114 }
115
116 AAFwk::Want want;
117 AAFwk::StartOptions startOptions;
118 if (!CheckStartAbilityInputParam(env, info, want, startOptions)) {
119 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
120 return NapiGetUndefined(env);
121 }
122
123 NapiAsyncTask::CompleteCallback complete =
124 [weak = context_, want, startOptions](napi_env env, NapiAsyncTask& task, int32_t status) {
125 WLOGI("startAbility begin");
126 auto context = weak.lock();
127 if (!context) {
128 WLOGFW("context is released");
129 task.Reject(env, CreateJsError(env,
130 static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY)));
131 return;
132 }
133
134 WmErrorCode ret = WM_JS_TO_ERROR_CODE_MAP.at(context->StartAbility(want, startOptions));
135 if (ret == WmErrorCode::WM_OK) {
136 task.Resolve(env, NapiGetUndefined(env));
137 } else {
138 task.Reject(env, CreateJsError(env, static_cast<int32_t>(ret)));
139 }
140 };
141
142 napi_value lastParam = (argc <= 2) ? nullptr : argv[2]; // at least two argc
143 napi_value result = nullptr;
144 NapiAsyncTask::Schedule("JSServiceExtensionContext::OnStartAbility",
145 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
146 return result;
147 }
148 };
149
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)150 void JsWindowConnectCallback::OnAbilityConnectDone(const AppExecFwk::ElementName& element,
151 const sptr<IRemoteObject>& remoteObject, int resultCode)
152 {
153 WLOGI("called");
154 }
155
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)156 void JsWindowConnectCallback::OnAbilityDisconnectDone(const AppExecFwk::ElementName& element, int resultCode)
157 {
158 WLOGI("called");
159 }
160
CreateJsWindowExtensionContext(napi_env env,const std::shared_ptr<WindowExtensionContext> & context)161 napi_value CreateJsWindowExtensionContext(napi_env env, const std::shared_ptr<WindowExtensionContext>& context)
162 {
163 WLOGI("CreateJsWindowExtensionContext begin");
164 napi_value objValue = CreateJsExtensionContext(env, context);
165
166 std::unique_ptr<JsWindowExtensionContext> jsContext
167 = std::make_unique<JsWindowExtensionContext>(context);
168 napi_wrap(env, objValue, jsContext.release(), JsWindowExtensionContext::Finalizer, nullptr, nullptr);
169
170 // make handler
171 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
172
173 const char *moduleName = "JsWindowExtensionContext";
174 BindNativeFunction(env, objValue, "startAbility", moduleName, JsWindowExtensionContext::StartAbility);
175
176 return objValue;
177 }
178 } // namespace Rosen
179 } // namespace OHOS