1 /*
2 * Copyright (c) 2025 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_application.h"
17
18 #include "context_impl.h"
19 #include "hilog_tag_wrapper.h"
20 #include "js_context_utils.h"
21 #include "js_error_utils.h"
22 #include "js_runtime.h"
23 #include "napi_base_context.h"
24
25 namespace OHOS {
26 namespace AbilityRuntime {
27 namespace {
28 constexpr size_t ARGC_ZERO = 0;
29 constexpr size_t ARGC_ONE = 1;
30 constexpr size_t ARGC_TWO = 2;
31 constexpr size_t ARGC_THREE = 3;
32 constexpr const char *PERMISSION_GET_BUNDLE_INFO = "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED";
33 } // namespace
34
Finalizer(napi_env env,void * data,void * hint)35 void JsApplication::Finalizer(napi_env env, void *data, void *hint)
36 {
37 TAG_LOGD(AAFwkTag::ABILITY_SIM, "Called.");
38 std::unique_ptr<JsApplication>(static_cast<JsApplication *>(data));
39 }
40
GetApplicationContext(napi_env env,napi_callback_info info)41 napi_value JsApplication::GetApplicationContext(napi_env env, napi_callback_info info)
42 {
43 return nullptr;
44 }
45
CreateBundleContext(napi_env env,napi_callback_info info)46 napi_value JsApplication::CreateBundleContext(napi_env env, napi_callback_info info)
47 {
48 return nullptr;
49 }
50
CreateModuleContext(napi_env env,napi_callback_info info)51 napi_value JsApplication::CreateModuleContext(napi_env env, napi_callback_info info)
52 {
53 GET_NAPI_INFO_AND_CALL(env, info, JsApplication, OnCreateModuleContext);
54 }
55
OnCreateModuleContext(napi_env env,NapiCallbackInfo & info)56 napi_value JsApplication::OnCreateModuleContext(napi_env env, NapiCallbackInfo &info)
57 {
58 TAG_LOGD(AAFwkTag::ABILITY_SIM, "Called");
59 if (info.argc < ARGC_TWO) {
60 TAG_LOGE(AAFwkTag::ABILITY_SIM, "invalid argc");
61 ThrowTooFewParametersError(env);
62 return CreateJsUndefined(env);
63 }
64
65 bool stageMode = false;
66 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, info.argv[ARGC_ZERO], stageMode);
67 if (status != napi_ok || !stageMode) {
68 TAG_LOGE(AAFwkTag::ABILITY_SIM, "not stageMode");
69 ThrowInvalidParamError(env, "Parse param context failed, must be a context of stageMode.");
70 return CreateJsUndefined(env);
71 }
72
73 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, info.argv[ARGC_ZERO]);
74 if (context == nullptr) {
75 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null context");
76 ThrowInvalidParamError(env, "Parse param context failed, must not be nullptr.");
77 return CreateJsUndefined(env);
78 }
79
80 auto inputContextPtr = Context::ConvertTo<Context>(context);
81 if (inputContextPtr == nullptr) {
82 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Convert to context failed");
83 ThrowInvalidParamError(env, "Parse param context failed, must be a context.");
84 return CreateJsUndefined(env);
85 }
86
87 std::shared_ptr<std::shared_ptr<Context>> moduleContext = std::make_shared<std::shared_ptr<Context>>();
88 std::shared_ptr<ContextImpl> contextImpl = std::make_shared<ContextImpl>();
89 if (contextImpl == nullptr) {
90 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null contextImpl");
91 ThrowInvalidParamError(env, "create context failed.");
92 return CreateJsUndefined(env);
93 }
94 std::string moduleName = "";
95 std::string bundleName = "";
96 if (info.argc == ARGC_TWO) {
97 TAG_LOGD(AAFwkTag::ABILITY_SIM, "Called");
98 if (!ConvertFromJsValue(env, info.argv[ARGC_ONE], moduleName)) {
99 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Parse failed");
100 ThrowInvalidParamError(env, "Parse param moduleName failed, moduleName must be string.");
101 return CreateJsUndefined(env);
102 }
103 } else {
104 TAG_LOGD(AAFwkTag::ABILITY_SIM, "Called");
105 if (!CheckCallerIsSystemApp()) {
106 TAG_LOGE(AAFwkTag::ABILITY_SIM, "no system app");
107 ThrowNotSystemAppError(env);
108 return CreateJsUndefined(env);
109 }
110
111 if (!CheckCallerPermission(PERMISSION_GET_BUNDLE_INFO)) {
112 TAG_LOGE(AAFwkTag::ABILITY_SIM, "no permission");
113 ThrowNoPermissionError(env, PERMISSION_GET_BUNDLE_INFO);
114 return CreateJsUndefined(env);
115 }
116
117 if (!ConvertFromJsValue(env, info.argv[ARGC_TWO], moduleName)
118 || !ConvertFromJsValue(env, info.argv[ARGC_ONE], bundleName)) {
119 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Parse failed");
120 ThrowInvalidParamError(env, "Parse param failed, moduleName and bundleName must be string.");
121 return CreateJsUndefined(env);
122 }
123 }
124 TAG_LOGD(AAFwkTag::ABILITY_SIM, "moduleName: %{public}s, bundlename: %{public}s",
125 moduleName.c_str(), bundleName.c_str());
126 NapiAsyncTask::ExecuteCallback execute = [moduleName, bundleName, contextImpl,
127 moduleContext, inputContextPtr]() {
128 if (bundleName.empty()) {
129 *moduleContext = contextImpl->CreateModuleContext(moduleName, inputContextPtr);
130 } else {
131 *moduleContext = contextImpl->CreateModuleContext(bundleName, moduleName, inputContextPtr);
132 }
133 };
134
135 NapiAsyncTask::CompleteCallback complete;
136 SetCreateCompleteCallback(moduleContext, complete);
137
138 napi_value result = nullptr;
139 NapiAsyncTask::ScheduleHighQos("JsApplication::OnCreateModuleContext",
140 env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
141
142 return result;
143 }
144
CreatePluginModuleContext(napi_env env,napi_callback_info info)145 napi_value JsApplication::CreatePluginModuleContext(napi_env env, napi_callback_info info)
146 {
147 return nullptr;
148 }
149
150
CheckCallerIsSystemApp()151 bool JsApplication::CheckCallerIsSystemApp()
152 {
153 return true;
154 }
155
CheckCallerPermission(const std::string & permission)156 bool JsApplication::CheckCallerPermission(const std::string &permission)
157 {
158 return true;
159 }
160
SetCreateCompleteCallback(std::shared_ptr<std::shared_ptr<Context>> contextPtr,NapiAsyncTask::CompleteCallback & complete)161 void JsApplication::SetCreateCompleteCallback(std::shared_ptr<std::shared_ptr<Context>> contextPtr,
162 NapiAsyncTask::CompleteCallback &complete)
163 {
164 complete = [contextPtr](napi_env env, NapiAsyncTask &task, int32_t status) {
165 auto context = *contextPtr;
166 if (context == nullptr) {
167 TAG_LOGE(AAFwkTag::ABILITY_SIM, "failed to create context");
168 task.Reject(env, CreateJsError(env,
169 static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), "invalid param."));
170 return;
171 }
172 napi_value value = CreateJsBaseContext(env, context, true);
173 auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &value, 1);
174 if (systemModule == nullptr) {
175 TAG_LOGW(AAFwkTag::ABILITY_SIM, "invalid systemModule");
176 task.Reject(env, CreateJsError(env,
177 static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), "invalid param."));
178 return;
179 }
180
181 napi_value object = systemModule->GetNapiValue();
182 if (!CheckTypeForNapiValue(env, object, napi_object)) {
183 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Failed to get object");
184 task.Reject(env, CreateJsError(env,
185 static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), "invalid param."));
186 return;
187 }
188
189 auto workContext = new (std::nothrow) std::weak_ptr<Context>(context);
190 napi_coerce_to_native_binding_object(env, object, DetachCallbackFunc, AttachBaseContext, workContext, nullptr);
191 napi_status ret = napi_wrap(env, object, workContext,
192 [](napi_env, void *data, void *) {
193 TAG_LOGD(AAFwkTag::ABILITY_SIM, "Finalizer for weak_ptr module context is called");
194 delete static_cast<std::weak_ptr<Context> *>(data);
195 },
196 nullptr, nullptr);
197 if (ret != napi_ok && workContext != nullptr) {
198 TAG_LOGE(AAFwkTag::ABILITY_SIM, "napi_wrap Failed: %{public}d", ret);
199 delete workContext;
200 return;
201 }
202 task.ResolveWithNoError(env, object);
203 };
204 }
205
OnCreateBundleContext(napi_env env,NapiCallbackInfo & info)206 napi_value JsApplication::OnCreateBundleContext(napi_env env, NapiCallbackInfo &info)
207 {
208 return nullptr;
209 }
210
OnCreatePluginModuleContext(napi_env env,NapiCallbackInfo & info)211 napi_value JsApplication::OnCreatePluginModuleContext(napi_env env, NapiCallbackInfo &info)
212 {
213 return nullptr;
214 }
215
CreateJsContext(napi_env env,const std::shared_ptr<Context> & context)216 napi_value JsApplication::CreateJsContext(napi_env env, const std::shared_ptr<Context> &context)
217 {
218 return nullptr;
219 }
220
OnGetApplicationContext(napi_env env,NapiCallbackInfo & info)221 napi_value JsApplication::OnGetApplicationContext(napi_env env, NapiCallbackInfo &info)
222 {
223 return nullptr;
224 }
225
ApplicationInit(napi_env env,napi_value exportObj)226 napi_value ApplicationInit(napi_env env, napi_value exportObj)
227 {
228 TAG_LOGD(AAFwkTag::ABILITY_SIM, "Called");
229 if (env == nullptr || exportObj == nullptr) {
230 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null env or exportObj");
231 return nullptr;
232 }
233
234 auto jsApplication = std::make_unique<JsApplication>();
235 napi_wrap(env, exportObj, jsApplication.release(), JsApplication::Finalizer, nullptr, nullptr);
236
237 const char *moduleName = "application";
238 BindNativeFunction(env, exportObj, "getApplicationContext", moduleName,
239 JsApplication::GetApplicationContext);
240
241 BindNativeFunction(env, exportObj, "createModuleContext", moduleName,
242 JsApplication::CreateModuleContext);
243
244 BindNativeFunction(env, exportObj, "createBundleContext", moduleName,
245 JsApplication::CreateBundleContext);
246
247 BindNativeFunction(env, exportObj, "createPluginModuleContext", moduleName,
248 JsApplication::CreatePluginModuleContext);
249 return CreateJsUndefined(env);
250 }
251 } // namespace AbilityRuntime
252 } // namespace OHOS