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