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