• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "ability_runtime_error_util.h"
19 #include "accesstoken_kit.h"
20 #include "context_impl.h"
21 #include "hilog_tag_wrapper.h"
22 #include "js_application_context_utils.h"
23 #include "js_error_utils.h"
24 #include "js_runtime_utils.h"
25 #include "js_context_utils.h"
26 #include "napi_base_context.h"
27 
28 namespace OHOS {
29 namespace AbilityRuntime {
30 namespace {
31     constexpr size_t ARGC_ZERO = 0;
32     constexpr size_t ARGC_ONE = 1;
33     constexpr size_t ARGC_TWO = 2;
34     constexpr const char* PERMISSION_GET_BUNDLE_INFO = "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED";
35 }
Finalizer(napi_env env,void * data,void * hint)36 void JsApplication::Finalizer(napi_env env, void *data, void *hint)
37 {
38     TAG_LOGD(AAFwkTag::APPKIT, "Called.");
39     std::unique_ptr<JsApplication>(static_cast<JsApplication *>(data));
40 }
41 
GetApplicationContext(napi_env env,napi_callback_info info)42 napi_value JsApplication::GetApplicationContext(napi_env env, napi_callback_info info)
43 {
44     GET_NAPI_INFO_AND_CALL(env, info, JsApplication, OnGetApplicationContext);
45 }
46 
OnGetApplicationContext(napi_env env,NapiCallbackInfo & info)47 napi_value JsApplication::OnGetApplicationContext(napi_env env, NapiCallbackInfo &info)
48 {
49     TAG_LOGD(AAFwkTag::APPKIT, "Called.");
50     napi_value value = JsApplicationContextUtils::CreateJsApplicationContext(env);
51     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.ApplicationContext", &value, 1);
52     if (systemModule == nullptr) {
53         TAG_LOGE(AAFwkTag::APPKIT, "invalid systemModule");
54         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INTERNAL_ERROR);
55         return CreateJsUndefined(env);
56     }
57     napi_value object = systemModule->GetNapiValue();
58     if (!CheckTypeForNapiValue(env, object, napi_object)) {
59         TAG_LOGE(AAFwkTag::APPKIT, "failed to get context native object");
60         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INTERNAL_ERROR);
61         return CreateJsUndefined(env);
62     }
63     return object;
64 }
65 
CreateModuleContext(napi_env env,napi_callback_info info)66 napi_value JsApplication::CreateModuleContext(napi_env env, napi_callback_info info)
67 {
68     GET_NAPI_INFO_AND_CALL(env, info, JsApplication, OnCreateModuleContext);
69 }
70 
CreateBundleContext(napi_env env,napi_callback_info info)71 napi_value JsApplication::CreateBundleContext(napi_env env, napi_callback_info info)
72 {
73     GET_NAPI_INFO_AND_CALL(env, info, JsApplication, OnCreateBundleContext);
74 }
75 
OnCreateModuleContext(napi_env env,NapiCallbackInfo & info)76 napi_value JsApplication::OnCreateModuleContext(napi_env env, NapiCallbackInfo &info)
77 {
78     TAG_LOGD(AAFwkTag::APPKIT, "Called");
79     if (info.argc < ARGC_TWO) {
80         TAG_LOGE(AAFwkTag::APPKIT, "invalid argc");
81         ThrowTooFewParametersError(env);
82         return CreateJsUndefined(env);
83     }
84 
85     bool stageMode = false;
86     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, info.argv[ARGC_ZERO], stageMode);
87     if (status != napi_ok || !stageMode) {
88         TAG_LOGE(AAFwkTag::APPKIT, "not stageMode");
89         ThrowInvalidParamError(env, "Parse param context failed, must be a context of stageMode.");
90         return CreateJsUndefined(env);
91     }
92 
93     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, info.argv[ARGC_ZERO]);
94     if (context == nullptr) {
95         TAG_LOGE(AAFwkTag::APPKIT, "null context");
96         ThrowInvalidParamError(env, "Parse param context failed, must not be nullptr.");
97         return CreateJsUndefined(env);
98     }
99 
100     auto inputContextPtr = Context::ConvertTo<Context>(context);
101     if (inputContextPtr == nullptr) {
102         TAG_LOGE(AAFwkTag::APPKIT, "Convert to context failed");
103         ThrowInvalidParamError(env, "Parse param context failed, must be a context.");
104         return CreateJsUndefined(env);
105     }
106 
107     std::shared_ptr<std::shared_ptr<Context>> moduleContext = std::make_shared<std::shared_ptr<Context>>();
108     std::shared_ptr<ContextImpl> contextImpl = std::make_shared<ContextImpl>();
109     if (contextImpl == nullptr) {
110         TAG_LOGE(AAFwkTag::APPKIT, "null contextImpl");
111         ThrowInvalidParamError(env, "create context failed.");
112         return CreateJsUndefined(env);
113     }
114     contextImpl->SetProcessName(context->GetProcessName());
115     std::string moduleName = "";
116     std::string bundleName = "";
117     if (info.argc == ARGC_TWO) {
118         TAG_LOGD(AAFwkTag::APPKIT, "Called");
119         if (!ConvertFromJsValue(env, info.argv[ARGC_ONE], moduleName)) {
120             TAG_LOGE(AAFwkTag::APPKIT, "Parse failed");
121             ThrowInvalidParamError(env, "Parse param moduleName failed, moduleName must be string.");
122             return CreateJsUndefined(env);
123         }
124     } else {
125         TAG_LOGD(AAFwkTag::APPKIT, "Called");
126         if (!CheckCallerIsSystemApp()) {
127             TAG_LOGE(AAFwkTag::APPKIT, "no system app");
128             ThrowNotSystemAppError(env);
129             return CreateJsUndefined(env);
130         }
131 
132         if (!CheckCallerPermission(PERMISSION_GET_BUNDLE_INFO)) {
133             TAG_LOGE(AAFwkTag::APPKIT, "no permission");
134             ThrowNoPermissionError(env, PERMISSION_GET_BUNDLE_INFO);
135             return CreateJsUndefined(env);
136         }
137 
138         if (!ConvertFromJsValue(env, info.argv[ARGC_TWO], moduleName)
139             || !ConvertFromJsValue(env, info.argv[ARGC_ONE], bundleName)) {
140             TAG_LOGE(AAFwkTag::APPKIT, "Parse failed");
141             ThrowInvalidParamError(env, "Parse param failed, moduleName and bundleName must be string.");
142             return CreateJsUndefined(env);
143         }
144     }
145     TAG_LOGD(AAFwkTag::APPKIT, "moduleName: %{public}s, bundlename: %{public}s",
146         moduleName.c_str(), bundleName.c_str());
147     NapiAsyncTask::ExecuteCallback execute = [moduleName, bundleName, contextImpl,
148         moduleContext, inputContextPtr]() {
149         if (bundleName.empty()) {
150             *moduleContext = contextImpl->CreateModuleContext(moduleName, inputContextPtr);
151         } else {
152             *moduleContext = contextImpl->CreateModuleContext(bundleName, moduleName, inputContextPtr);
153         }
154     };
155 
156     NapiAsyncTask::CompleteCallback complete;
157     SetCreateCompleteCallback(moduleContext, complete);
158 
159     napi_value result = nullptr;
160     NapiAsyncTask::ScheduleHighQos("JsApplication::OnCreateModuleContext",
161         env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
162 
163     return result;
164 }
165 
CheckCallerIsSystemApp()166 bool JsApplication::CheckCallerIsSystemApp()
167 {
168     auto selfToken = IPCSkeleton::GetSelfTokenID();
169     if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
170         return false;
171     }
172     return true;
173 }
174 
CheckCallerPermission(const std::string & permission)175 bool JsApplication::CheckCallerPermission(const std::string &permission)
176 {
177     auto selfToken = IPCSkeleton::GetSelfTokenID();
178     int ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(selfToken, permission);
179     if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
180         return false;
181     }
182     return true;
183 }
184 
185 
OnCreateBundleContext(napi_env env,NapiCallbackInfo & info)186 napi_value JsApplication::OnCreateBundleContext(napi_env env, NapiCallbackInfo &info)
187 {
188     TAG_LOGD(AAFwkTag::APPKIT, "Called");
189     if (!CheckCallerIsSystemApp()) {
190         TAG_LOGE(AAFwkTag::APPKIT, "no system app");
191         ThrowNotSystemAppError(env);
192         return CreateJsUndefined(env);
193     }
194 
195     if (info.argc < ARGC_TWO) {
196         TAG_LOGE(AAFwkTag::APPKIT, "invalid argc");
197         ThrowTooFewParametersError(env);
198         return CreateJsUndefined(env);
199     }
200 
201     if (!CheckCallerPermission(PERMISSION_GET_BUNDLE_INFO)) {
202         TAG_LOGE(AAFwkTag::APPKIT, "no permission");
203         ThrowNoPermissionError(env, PERMISSION_GET_BUNDLE_INFO);
204         return CreateJsUndefined(env);
205     }
206 
207     bool stageMode = false;
208     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, info.argv[ARGC_ZERO], stageMode);
209     if (status != napi_ok || !stageMode) {
210         TAG_LOGE(AAFwkTag::APPKIT, "not stageMode");
211         ThrowInvalidParamError(env, "Parse param context failed, must be a context of stageMode.");
212         return CreateJsUndefined(env);
213     }
214 
215     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, info.argv[ARGC_ZERO]);
216     if (context == nullptr) {
217         TAG_LOGE(AAFwkTag::APPKIT, "null context");
218         ThrowInvalidParamError(env, "Parse param context failed, must not be nullptr.");
219         return CreateJsUndefined(env);
220     }
221 
222     auto inputContextPtr = Context::ConvertTo<Context>(context);
223     if (inputContextPtr == nullptr) {
224         TAG_LOGE(AAFwkTag::APPKIT, "Convert to context failed");
225         ThrowInvalidParamError(env, "Parse param context failed, must be a context.");
226         return CreateJsUndefined(env);
227     }
228 
229     std::string bundleName;
230     if (!ConvertFromJsValue(env, info.argv[ARGC_ONE], bundleName)) {
231         TAG_LOGE(AAFwkTag::APPKIT, "Parse bundleName failed");
232         ThrowInvalidParamError(env, "Parse param bundleName failed, bundleName must be string.");
233         return CreateJsUndefined(env);
234     }
235 
236     auto bundleContext = std::make_shared<std::shared_ptr<Context>>();
237     std::shared_ptr<ContextImpl> contextImpl = std::make_shared<ContextImpl>();
238     contextImpl->SetProcessName(context->GetProcessName());
239 
240     NapiAsyncTask::ExecuteCallback execute = [bundleName, contextImpl,
241         bundleContext, inputContextPtr]() {
242         contextImpl->CreateBundleContext(*bundleContext, bundleName, inputContextPtr);
243     };
244 
245     NapiAsyncTask::CompleteCallback complete;
246     SetCreateCompleteCallback(bundleContext, complete);
247 
248     napi_value result = nullptr;
249     NapiAsyncTask::ScheduleHighQos("JsApplication::OnCreateBundleContext",
250         env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
251 
252     return result;
253 }
254 
SetCreateCompleteCallback(std::shared_ptr<std::shared_ptr<Context>> contextPtr,NapiAsyncTask::CompleteCallback & complete)255 void JsApplication::SetCreateCompleteCallback(std::shared_ptr<std::shared_ptr<Context>> contextPtr,
256     NapiAsyncTask::CompleteCallback &complete)
257 {
258     TAG_LOGD(AAFwkTag::APPKIT, "Called");
259     complete = [contextPtr](napi_env env, NapiAsyncTask &task, int32_t status) {
260         auto context = *contextPtr;
261         if (!context) {
262             TAG_LOGE(AAFwkTag::APPKIT, "failed to create context");
263             task.Reject(env, CreateJsError(env,
264                 static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), "invalid param."));
265             return;
266         }
267         napi_value value = CreateJsBaseContext(env, context, true);
268         auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &value, 1);
269         if (systemModule == nullptr) {
270             TAG_LOGW(AAFwkTag::APPKIT, "invalid systemModule");
271             task.Reject(env, CreateJsError(env,
272                 static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), "invalid param."));
273             return;
274         }
275 
276         napi_value object = systemModule->GetNapiValue();
277         if (!CheckTypeForNapiValue(env, object, napi_object)) {
278             TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
279             task.Reject(env, CreateJsError(env,
280                 static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM), "invalid param."));
281             return;
282         }
283 
284         auto workContext = new (std::nothrow) std::weak_ptr<Context>(context);
285         napi_coerce_to_native_binding_object(env, object, DetachCallbackFunc, AttachBaseContext, workContext, nullptr);
286         napi_status ret = napi_wrap(env, object, workContext,
287             [](napi_env, void *data, void *) {
288                 TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr module context is called");
289                 delete static_cast<std::weak_ptr<Context> *>(data);
290             },
291             nullptr, nullptr);
292         if (ret != napi_ok && workContext != nullptr) {
293             TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap Failed: %{public}d", ret);
294             delete workContext;
295             return;
296         }
297         task.ResolveWithNoError(env, object);
298     };
299 }
300 
CreateJsContext(napi_env env,const std::shared_ptr<Context> & context)301 napi_value JsApplication::CreateJsContext(napi_env env, const std::shared_ptr<Context> &context)
302 {
303     napi_value value = CreateJsBaseContext(env, context, true);
304     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &value, 1);
305     if (systemModule == nullptr) {
306         TAG_LOGW(AAFwkTag::APPKIT, "invalid systemModule");
307         ThrowInvalidParamError(env, "invalid param.");
308         return CreateJsUndefined(env);
309     }
310     napi_value object = systemModule->GetNapiValue();
311     if (!CheckTypeForNapiValue(env, object, napi_object)) {
312         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
313         ThrowInvalidParamError(env, "invalid param.");
314         return CreateJsUndefined(env);
315     }
316 
317     auto workContext = new (std::nothrow) std::weak_ptr<Context>(context);
318     napi_coerce_to_native_binding_object(env, object, DetachCallbackFunc, AttachBaseContext, workContext, nullptr);
319     napi_status status = napi_wrap(env, object, workContext,
320         [](napi_env, void *data, void *) {
321             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr module context is called");
322             delete static_cast<std::weak_ptr<Context> *>(data);
323         },
324         nullptr, nullptr);
325     if (status != napi_ok && workContext != nullptr) {
326         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap Failed: %{public}d", status);
327         delete workContext;
328         ThrowInvalidParamError(env, "invalid param.");
329         return CreateJsUndefined(env);
330     }
331 
332     return object;
333 }
334 
ApplicationInit(napi_env env,napi_value exportObj)335 napi_value ApplicationInit(napi_env env, napi_value exportObj)
336 {
337     TAG_LOGD(AAFwkTag::APPKIT, "Called");
338     if (env == nullptr || exportObj == nullptr) {
339         TAG_LOGE(AAFwkTag::APPKIT, "null env or exportObj");
340         return nullptr;
341     }
342 
343     auto jsApplication = std::make_unique<JsApplication>();
344     napi_wrap(env, exportObj, jsApplication.release(), JsApplication::Finalizer, nullptr, nullptr);
345 
346     const char *moduleName = "application";
347     BindNativeFunction(env, exportObj, "getApplicationContext", moduleName,
348         JsApplication::GetApplicationContext);
349 
350     BindNativeFunction(env, exportObj, "createModuleContext", moduleName,
351         JsApplication::CreateModuleContext);
352 
353     BindNativeFunction(env, exportObj, "createBundleContext", moduleName,
354         JsApplication::CreateBundleContext);
355     return CreateJsUndefined(env);
356 }
357 } // namespace AbilityRuntime
358 } // namespace OHOS