• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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_context_utils.h"
17 
18 #include "ability_runtime_error_util.h"
19 #include "application_context.h"
20 #include "application_context_manager.h"
21 #include "hilog_tag_wrapper.h"
22 #include "ipc_skeleton.h"
23 #include "js_application_context_utils.h"
24 #include "js_data_struct_converter.h"
25 #include "js_resource_manager_utils.h"
26 #include "js_runtime_utils.h"
27 #include "tokenid_kit.h"
28 #include "js_error_utils.h"
29 
30 namespace OHOS {
31 namespace AbilityRuntime {
32 namespace {
33 constexpr char BASE_CONTEXT_NAME[] = "__base_context_ptr__";
34 
35 constexpr size_t ARGC_ONE = 1;
36 constexpr size_t ARGC_TWO = 2;
37 constexpr size_t INDEX_ONE = 1;
38 
39 class JsBaseContext {
40 public:
JsBaseContext(std::weak_ptr<Context> && context)41     explicit JsBaseContext(std::weak_ptr<Context>&& context) : context_(std::move(context)) {}
42     virtual ~JsBaseContext() = default;
43 
44     static void Finalizer(napi_env env, void* data, void* hint);
45     static napi_value CreateBundleContext(napi_env env, napi_callback_info info);
46     static napi_value GetApplicationContext(napi_env env, napi_callback_info info);
47     static napi_value SwitchArea(napi_env env, napi_callback_info info);
48     static napi_value GetArea(napi_env env, napi_callback_info info);
49     static napi_value CreateModuleContext(napi_env env, napi_callback_info info);
50     static napi_value CreateSystemHspModuleResourceManager(napi_env env, napi_callback_info info);
51     static napi_value CreateModuleResourceManager(napi_env env, napi_callback_info info);
52     static napi_value CreateDisplayContext(napi_env env, napi_callback_info info);
53 
54     napi_value OnGetCacheDir(napi_env env, NapiCallbackInfo& info);
55     napi_value OnGetTempDir(napi_env env, NapiCallbackInfo& info);
56     napi_value OnGetResourceDir(napi_env env, NapiCallbackInfo& info);
57     napi_value OnGetFilesDir(napi_env env, NapiCallbackInfo& info);
58     napi_value OnGetDistributedFilesDir(napi_env env, NapiCallbackInfo& info);
59     napi_value OnGetDatabaseDir(napi_env env, NapiCallbackInfo& info);
60     napi_value OnGetPreferencesDir(napi_env env, NapiCallbackInfo& info);
61     napi_value OnGetGroupDir(napi_env env, NapiCallbackInfo& info);
62     napi_value OnGetBundleCodeDir(napi_env env, NapiCallbackInfo& info);
63     napi_value OnGetCloudFileDir(napi_env env, NapiCallbackInfo& info);
64 
65     static napi_value GetCacheDir(napi_env env, napi_callback_info info);
66     static napi_value GetTempDir(napi_env env, napi_callback_info info);
67     static napi_value GetResourceDir(napi_env env, napi_callback_info info);
68     static napi_value GetFilesDir(napi_env env, napi_callback_info info);
69     static napi_value GetDistributedFilesDir(napi_env env, napi_callback_info info);
70     static napi_value GetDatabaseDir(napi_env env, napi_callback_info info);
71     static napi_value GetPreferencesDir(napi_env env, napi_callback_info info);
72     static napi_value GetGroupDir(napi_env env, napi_callback_info info);
73     static napi_value GetBundleCodeDir(napi_env env, napi_callback_info info);
74     static napi_value GetCloudFileDir(napi_env env, napi_callback_info info);
75 
76 protected:
77     std::weak_ptr<Context> context_;
78 
79 private:
80     napi_value OnCreateBundleContext(napi_env env, NapiCallbackInfo& info);
81     napi_value CreateJsBundleContext(napi_env env, const std::shared_ptr<Context>& bundleContext);
82     napi_value OnGetApplicationContext(napi_env env, NapiCallbackInfo& info);
83     napi_value CreateJSApplicationContext(napi_env env, const std::shared_ptr<ApplicationContext> applicationContext);
84     napi_value OnSwitchArea(napi_env env, NapiCallbackInfo& info);
85     napi_value OnGetArea(napi_env env, NapiCallbackInfo& info);
86     napi_value OnCreateModuleContext(napi_env env, NapiCallbackInfo& info);
87     napi_value CreateJsModuleContext(napi_env env, const std::shared_ptr<Context>& moduleContext);
88     napi_value OnCreateSystemHspModuleResourceManager(napi_env env, NapiCallbackInfo& info);
89     napi_value OnCreateModuleResourceManager(napi_env env, NapiCallbackInfo& info);
90     napi_value OnCreateDisplayContext(napi_env env, NapiCallbackInfo &info);
91     napi_value CreateJsContext(napi_env env, const std::shared_ptr<Context> &context);
92     bool CheckCallerIsSystemApp();
93 };
94 
Finalizer(napi_env env,void * data,void * hint)95 void JsBaseContext::Finalizer(napi_env env, void* data, void* hint)
96 {
97     TAG_LOGD(AAFwkTag::APPKIT, "called");
98     std::unique_ptr<JsBaseContext>(static_cast<JsBaseContext*>(data));
99 }
100 
CreateBundleContext(napi_env env,napi_callback_info info)101 napi_value JsBaseContext::CreateBundleContext(napi_env env, napi_callback_info info)
102 {
103     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnCreateBundleContext, BASE_CONTEXT_NAME);
104 }
105 
GetApplicationContext(napi_env env,napi_callback_info info)106 napi_value JsBaseContext::GetApplicationContext(napi_env env, napi_callback_info info)
107 {
108     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetApplicationContext, BASE_CONTEXT_NAME);
109 }
110 
SwitchArea(napi_env env,napi_callback_info info)111 napi_value JsBaseContext::SwitchArea(napi_env env, napi_callback_info info)
112 {
113     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnSwitchArea, BASE_CONTEXT_NAME);
114 }
115 
OnSwitchArea(napi_env env,NapiCallbackInfo & info)116 napi_value JsBaseContext::OnSwitchArea(napi_env env, NapiCallbackInfo& info)
117 {
118     if (info.argc == 0) {
119         TAG_LOGE(AAFwkTag::APPKIT, "Not enough params");
120         return CreateJsUndefined(env);
121     }
122 
123     auto context = context_.lock();
124     if (!context) {
125         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
126         return CreateJsUndefined(env);
127     }
128 
129     int mode = 0;
130     if (!ConvertFromJsValue(env, info.argv[0], mode)) {
131         TAG_LOGE(AAFwkTag::APPKIT, "Parse mode failed");
132         return CreateJsUndefined(env);
133     }
134 
135     context->SwitchArea(mode);
136 
137     napi_value object = info.thisVar;
138     if (!CheckTypeForNapiValue(env, object, napi_object)) {
139         TAG_LOGE(AAFwkTag::APPKIT, "Check type failed");
140         return CreateJsUndefined(env);
141     }
142     BindNativeProperty(env, object, "cacheDir", GetCacheDir);
143     BindNativeProperty(env, object, "tempDir", GetTempDir);
144     BindNativeProperty(env, object, "resourceDir", GetResourceDir);
145     BindNativeProperty(env, object, "filesDir", GetFilesDir);
146     BindNativeProperty(env, object, "distributedFilesDir", GetDistributedFilesDir);
147     BindNativeProperty(env, object, "databaseDir", GetDatabaseDir);
148     BindNativeProperty(env, object, "preferencesDir", GetPreferencesDir);
149     BindNativeProperty(env, object, "bundleCodeDir", GetBundleCodeDir);
150     BindNativeProperty(env, object, "cloudFileDir", GetCloudFileDir);
151     return CreateJsUndefined(env);
152 }
153 
CreateModuleContext(napi_env env,napi_callback_info info)154 napi_value JsBaseContext::CreateModuleContext(napi_env env, napi_callback_info info)
155 {
156     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnCreateModuleContext, BASE_CONTEXT_NAME);
157 }
158 
OnCreateModuleContext(napi_env env,NapiCallbackInfo & info)159 napi_value JsBaseContext::OnCreateModuleContext(napi_env env, NapiCallbackInfo& info)
160 {
161     auto context = context_.lock();
162     if (!context) {
163         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
164         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
165         return CreateJsUndefined(env);
166     }
167 
168     std::shared_ptr<Context> moduleContext = nullptr;
169     std::string moduleName;
170 
171     if (!ConvertFromJsValue(env, info.argv[1], moduleName)) {
172         TAG_LOGD(AAFwkTag::APPKIT, "Parse inner module name");
173         if (!ConvertFromJsValue(env, info.argv[0], moduleName)) {
174             TAG_LOGE(AAFwkTag::APPKIT, "Parse moduleName failed");
175             ThrowInvalidParamError(env, "Parse param moduleName failed, moduleName must be string.");
176             return CreateJsUndefined(env);
177         }
178         moduleContext = context->CreateModuleContext(moduleName);
179     } else {
180         std::string bundleName;
181         if (!ConvertFromJsValue(env, info.argv[0], bundleName)) {
182             TAG_LOGE(AAFwkTag::APPKIT, "Parse bundleName failed");
183             ThrowInvalidParamError(env, "Parse param bundleName failed, bundleName must be string.");
184             return CreateJsUndefined(env);
185         }
186         if (!CheckCallerIsSystemApp()) {
187             TAG_LOGE(AAFwkTag::APPKIT, "This application is not system-app, can not use system-api");
188             AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_NOT_SYSTEM_APP);
189             return CreateJsUndefined(env);
190         }
191         TAG_LOGD(AAFwkTag::APPKIT, "Parse outer module name");
192         moduleContext = context->CreateModuleContext(bundleName, moduleName);
193     }
194 
195     if (!moduleContext) {
196         TAG_LOGE(AAFwkTag::APPKIT, "failed to create module context");
197         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
198         return CreateJsUndefined(env);
199     }
200     return CreateJsModuleContext(env, moduleContext);
201 }
202 
CreateJsModuleContext(napi_env env,const std::shared_ptr<Context> & moduleContext)203 napi_value JsBaseContext::CreateJsModuleContext(napi_env env, const std::shared_ptr<Context>& moduleContext)
204 {
205     napi_value value = CreateJsBaseContext(env, moduleContext, true);
206     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &value, 1);
207     if (systemModule == nullptr) {
208         TAG_LOGW(AAFwkTag::APPKIT, "invalid systemModule");
209         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
210         return CreateJsUndefined(env);
211     }
212     napi_value object = systemModule->GetNapiValue();
213     if (!CheckTypeForNapiValue(env, object, napi_object)) {
214         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
215         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
216         return CreateJsUndefined(env);
217     }
218     auto workContext = new (std::nothrow) std::weak_ptr<Context>(moduleContext);
219     napi_coerce_to_native_binding_object(env, object, DetachCallbackFunc, AttachBaseContext, workContext, nullptr);
220     auto res = napi_wrap(env, object, workContext,
221         [](napi_env, void *data, void *) {
222             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr module context is called");
223             delete static_cast<std::weak_ptr<Context> *>(data);
224         },
225         nullptr, nullptr);
226     if (res != napi_ok && workContext != nullptr) {
227         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap failed:%{public}d", res);
228         delete workContext;
229         return CreateJsUndefined(env);
230     }
231     return object;
232 }
233 
CreateSystemHspModuleResourceManager(napi_env env,napi_callback_info info)234 napi_value JsBaseContext::CreateSystemHspModuleResourceManager(napi_env env, napi_callback_info info)
235 {
236     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext,
237         OnCreateSystemHspModuleResourceManager, BASE_CONTEXT_NAME);
238 }
239 
OnCreateSystemHspModuleResourceManager(napi_env env,NapiCallbackInfo & info)240 napi_value JsBaseContext::OnCreateSystemHspModuleResourceManager(napi_env env, NapiCallbackInfo& info)
241 {
242     auto context = context_.lock();
243     if (!context) {
244         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
245         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
246         return CreateJsUndefined(env);
247     }
248 
249     std::string bundleName = "";
250     if (!ConvertFromJsValue(env, info.argv[0], bundleName)) {
251         TAG_LOGE(AAFwkTag::APPKIT, "Parse bundleName failed");
252         ThrowInvalidParamError(env, "Parse param bundleName failed, bundleName must be string.");
253         return CreateJsUndefined(env);
254     }
255     std::string moduleName = "";
256     if (!ConvertFromJsValue(env, info.argv[1], moduleName)) {
257         TAG_LOGE(AAFwkTag::APPKIT, "Parse moduleName failed");
258         ThrowInvalidParamError(env, "Parse param moduleName failed, moduleName must be string.");
259         return CreateJsUndefined(env);
260     }
261 
262     std::shared_ptr<Global::Resource::ResourceManager> resourceManager = nullptr;
263     int32_t retCode = context->CreateSystemHspModuleResourceManager(bundleName, moduleName, resourceManager);
264     if (resourceManager == nullptr && retCode == ERR_ABILITY_RUNTIME_EXTERNAL_NOT_SYSTEM_HSP) {
265         TAG_LOGE(AAFwkTag::APPKIT, "Failed to create resourceManager");
266         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_NOT_SYSTEM_HSP);
267         return CreateJsUndefined(env);
268     }
269     if (resourceManager == nullptr) {
270         TAG_LOGE(AAFwkTag::APPKIT, "Failed to create resourceManager");
271         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
272         return CreateJsUndefined(env);
273     }
274 
275     return CreateJsResourceManager(env, resourceManager, nullptr);
276 }
277 
CreateModuleResourceManager(napi_env env,napi_callback_info info)278 napi_value JsBaseContext::CreateModuleResourceManager(napi_env env, napi_callback_info info)
279 {
280     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnCreateModuleResourceManager, BASE_CONTEXT_NAME);
281 }
282 
OnCreateModuleResourceManager(napi_env env,NapiCallbackInfo & info)283 napi_value JsBaseContext::OnCreateModuleResourceManager(napi_env env, NapiCallbackInfo& info)
284 {
285     auto context = context_.lock();
286     if (!context) {
287         TAG_LOGW(AAFwkTag::APPKIT, "applicationContext is already released");
288         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
289         return CreateJsUndefined(env);
290     }
291 
292     std::string bundleName;
293     if (!ConvertFromJsValue(env, info.argv[0], bundleName)) {
294         TAG_LOGE(AAFwkTag::APPKIT, "Parse bundleName failed");
295         ThrowInvalidParamError(env, "Parse param bundleName failed, bundleName must be string.");
296         return CreateJsUndefined(env);
297     }
298     std::string moduleName;
299     if (!ConvertFromJsValue(env, info.argv[1], moduleName)) {
300         TAG_LOGE(AAFwkTag::APPKIT, "Parse moduleName failed");
301         ThrowInvalidParamError(env, "Parse param moduleName failed, moduleName must be string.");
302         return CreateJsUndefined(env);
303     }
304     if (!CheckCallerIsSystemApp()) {
305         TAG_LOGE(AAFwkTag::APPKIT, "This application is not system-app, can not use system-api");
306         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_NOT_SYSTEM_APP);
307         return CreateJsUndefined(env);
308     }
309     auto resourceManager = context->CreateModuleResourceManager(bundleName, moduleName);
310     if (resourceManager == nullptr) {
311         TAG_LOGE(AAFwkTag::APPKIT, "Failed to create resourceManager");
312         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
313         return CreateJsUndefined(env);
314     }
315     auto jsResourceManager = CreateJsResourceManager(env, resourceManager, nullptr);
316     return jsResourceManager;
317 }
318 
GetArea(napi_env env,napi_callback_info info)319 napi_value JsBaseContext::GetArea(napi_env env, napi_callback_info info)
320 {
321     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetArea, BASE_CONTEXT_NAME);
322 }
323 
OnGetArea(napi_env env,NapiCallbackInfo & info)324 napi_value JsBaseContext::OnGetArea(napi_env env, NapiCallbackInfo& info)
325 {
326     auto context = context_.lock();
327     if (!context) {
328         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
329         return CreateJsUndefined(env);
330     }
331     int area = context->GetArea();
332     return CreateJsValue(env, area);
333 }
334 
GetCacheDir(napi_env env,napi_callback_info info)335 napi_value JsBaseContext::GetCacheDir(napi_env env, napi_callback_info info)
336 {
337     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetCacheDir, BASE_CONTEXT_NAME);
338 }
339 
OnGetCacheDir(napi_env env,NapiCallbackInfo & info)340 napi_value JsBaseContext::OnGetCacheDir(napi_env env, NapiCallbackInfo& info)
341 {
342     auto context = context_.lock();
343     if (!context) {
344         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
345         return CreateJsUndefined(env);
346     }
347     std::string path = context->GetCacheDir();
348     return CreateJsValue(env, path);
349 }
350 
GetTempDir(napi_env env,napi_callback_info info)351 napi_value JsBaseContext::GetTempDir(napi_env env, napi_callback_info info)
352 {
353     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetTempDir, BASE_CONTEXT_NAME);
354 }
355 
OnGetTempDir(napi_env env,NapiCallbackInfo & info)356 napi_value JsBaseContext::OnGetTempDir(napi_env env, NapiCallbackInfo& info)
357 {
358     auto context = context_.lock();
359     if (!context) {
360         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
361         return CreateJsUndefined(env);
362     }
363     std::string path = context->GetTempDir();
364     return CreateJsValue(env, path);
365 }
366 
GetResourceDir(napi_env env,napi_callback_info info)367 napi_value JsBaseContext::GetResourceDir(napi_env env, napi_callback_info info)
368 {
369     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetResourceDir, BASE_CONTEXT_NAME);
370 }
371 
OnGetResourceDir(napi_env env,NapiCallbackInfo & info)372 napi_value JsBaseContext::OnGetResourceDir(napi_env env, NapiCallbackInfo& info)
373 {
374     auto context = context_.lock();
375     if (!context) {
376         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
377         return CreateJsUndefined(env);
378     }
379     std::string path = context->GetResourceDir();
380     return CreateJsValue(env, path);
381 }
382 
GetFilesDir(napi_env env,napi_callback_info info)383 napi_value JsBaseContext::GetFilesDir(napi_env env, napi_callback_info info)
384 {
385     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetFilesDir, BASE_CONTEXT_NAME);
386 }
387 
OnGetFilesDir(napi_env env,NapiCallbackInfo & info)388 napi_value JsBaseContext::OnGetFilesDir(napi_env env, NapiCallbackInfo& info)
389 {
390     auto context = context_.lock();
391     if (!context) {
392         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
393         return CreateJsUndefined(env);
394     }
395     std::string path = context->GetFilesDir();
396     return CreateJsValue(env, path);
397 }
398 
GetDistributedFilesDir(napi_env env,napi_callback_info info)399 napi_value JsBaseContext::GetDistributedFilesDir(napi_env env, napi_callback_info info)
400 {
401     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetDistributedFilesDir, BASE_CONTEXT_NAME);
402 }
403 
OnGetDistributedFilesDir(napi_env env,NapiCallbackInfo & info)404 napi_value JsBaseContext::OnGetDistributedFilesDir(napi_env env, NapiCallbackInfo& info)
405 {
406     auto context = context_.lock();
407     if (!context) {
408         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
409         return CreateJsUndefined(env);
410     }
411     std::string path = context->GetDistributedFilesDir();
412     return CreateJsValue(env, path);
413 }
414 
GetDatabaseDir(napi_env env,napi_callback_info info)415 napi_value JsBaseContext::GetDatabaseDir(napi_env env, napi_callback_info info)
416 {
417     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetDatabaseDir, BASE_CONTEXT_NAME);
418 }
419 
OnGetDatabaseDir(napi_env env,NapiCallbackInfo & info)420 napi_value JsBaseContext::OnGetDatabaseDir(napi_env env, NapiCallbackInfo& info)
421 {
422     auto context = context_.lock();
423     if (!context) {
424         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
425         return CreateJsUndefined(env);
426     }
427     std::string path = context->GetDatabaseDir();
428     return CreateJsValue(env, path);
429 }
430 
GetPreferencesDir(napi_env env,napi_callback_info info)431 napi_value JsBaseContext::GetPreferencesDir(napi_env env, napi_callback_info info)
432 {
433     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetPreferencesDir, BASE_CONTEXT_NAME);
434 }
435 
OnGetPreferencesDir(napi_env env,NapiCallbackInfo & info)436 napi_value JsBaseContext::OnGetPreferencesDir(napi_env env, NapiCallbackInfo& info)
437 {
438     auto context = context_.lock();
439     if (!context) {
440         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
441         return CreateJsUndefined(env);
442     }
443     std::string path = context->GetPreferencesDir();
444     return CreateJsValue(env, path);
445 }
446 
GetGroupDir(napi_env env,napi_callback_info info)447 napi_value JsBaseContext::GetGroupDir(napi_env env, napi_callback_info info)
448 {
449     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetGroupDir, BASE_CONTEXT_NAME);
450 }
451 
OnGetGroupDir(napi_env env,NapiCallbackInfo & info)452 napi_value JsBaseContext::OnGetGroupDir(napi_env env, NapiCallbackInfo& info)
453 {
454     if (info.argc != ARGC_ONE && info.argc != ARGC_TWO) {
455         TAG_LOGE(AAFwkTag::APPKIT, "Not enough params");
456         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
457         return CreateJsUndefined(env);
458     }
459 
460     std::string groupId;
461     if (!ConvertFromJsValue(env, info.argv[0], groupId)) {
462         TAG_LOGE(AAFwkTag::APPKIT, "Parse groupId failed");
463         ThrowInvalidParamError(env, "Parse param groupId failed, groupId must be string.");
464         return CreateJsUndefined(env);
465     }
466 
467     auto complete = [context = context_, groupId]
468         (napi_env env, NapiAsyncTask& task, int32_t status) {
469         auto completeContext = context.lock();
470         if (!completeContext) {
471             task.Reject(env, CreateJsError(env, ERR_ABILITY_RUNTIME_EXTERNAL_CONTEXT_NOT_EXIST,
472                 "completeContext if already released."));
473             return;
474         }
475         std::string path = completeContext->GetGroupDir(groupId);
476         task.ResolveWithNoError(env, CreateJsValue(env, path));
477     };
478 
479     napi_value lastParam = (info.argc == ARGC_TWO) ? info.argv[INDEX_ONE] : nullptr;
480     napi_value result = nullptr;
481     NapiAsyncTask::ScheduleHighQos("JsBaseContext::OnGetGroupDir",
482         env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
483     return result;
484 }
485 
GetBundleCodeDir(napi_env env,napi_callback_info info)486 napi_value JsBaseContext::GetBundleCodeDir(napi_env env, napi_callback_info info)
487 {
488     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetBundleCodeDir, BASE_CONTEXT_NAME);
489 }
490 
OnGetBundleCodeDir(napi_env env,NapiCallbackInfo & info)491 napi_value JsBaseContext::OnGetBundleCodeDir(napi_env env, NapiCallbackInfo& info)
492 {
493     auto context = context_.lock();
494     if (!context) {
495         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
496         return CreateJsUndefined(env);
497     }
498     std::string path = context->GetBundleCodeDir();
499     return CreateJsValue(env, path);
500 }
501 
GetCloudFileDir(napi_env env,napi_callback_info info)502 napi_value JsBaseContext::GetCloudFileDir(napi_env env, napi_callback_info info)
503 {
504     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetCloudFileDir, BASE_CONTEXT_NAME);
505 }
506 
OnGetCloudFileDir(napi_env env,NapiCallbackInfo & info)507 napi_value JsBaseContext::OnGetCloudFileDir(napi_env env, NapiCallbackInfo& info)
508 {
509     auto context = context_.lock();
510     if (!context) {
511         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
512         return CreateJsUndefined(env);
513     }
514     std::string path = context->GetCloudFileDir();
515     return CreateJsValue(env, path);
516 }
517 
OnCreateBundleContext(napi_env env,NapiCallbackInfo & info)518 napi_value JsBaseContext::OnCreateBundleContext(napi_env env, NapiCallbackInfo& info)
519 {
520     if (!CheckCallerIsSystemApp()) {
521         TAG_LOGE(AAFwkTag::APPKIT, "This application is not system-app, can not use system-api");
522         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_NOT_SYSTEM_APP);
523         return CreateJsUndefined(env);
524     }
525 
526     if (info.argc == 0) {
527         TAG_LOGE(AAFwkTag::APPKIT, "Not enough params");
528         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
529         return CreateJsUndefined(env);
530     }
531 
532     auto context = context_.lock();
533     if (!context) {
534         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
535         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
536         return CreateJsUndefined(env);
537     }
538 
539     std::string bundleName;
540     if (!ConvertFromJsValue(env, info.argv[0], bundleName)) {
541         TAG_LOGE(AAFwkTag::APPKIT, "Parse bundleName failed");
542         ThrowInvalidParamError(env, "Parse param bundleName failed, bundleName must be string.");
543         return CreateJsUndefined(env);
544     }
545 
546     auto bundleContext = context->CreateBundleContext(bundleName);
547     if (!bundleContext) {
548         TAG_LOGE(AAFwkTag::APPKIT, "bundleContext is nullptr");
549         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
550         return CreateJsUndefined(env);
551     }
552     return CreateJsBundleContext(env, bundleContext);
553 }
554 
CreateJsBundleContext(napi_env env,const std::shared_ptr<Context> & bundleContext)555 napi_value JsBaseContext::CreateJsBundleContext(napi_env env, const std::shared_ptr<Context>& bundleContext)
556 {
557     napi_value value = CreateJsBaseContext(env, bundleContext, true);
558     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &value, 1);
559     if (systemModule == nullptr) {
560         TAG_LOGW(AAFwkTag::APPKIT, "OnCreateBundleContext, invalid systemModule");
561         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
562         return CreateJsUndefined(env);
563     }
564     napi_value object = systemModule->GetNapiValue();
565     if (!CheckTypeForNapiValue(env, object, napi_object)) {
566         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
567         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
568         return CreateJsUndefined(env);
569     }
570     auto workContext = new (std::nothrow) std::weak_ptr<Context>(bundleContext);
571     napi_coerce_to_native_binding_object(env, object, DetachCallbackFunc, AttachBaseContext, workContext, nullptr);
572     auto res = napi_wrap(env, object, workContext,
573         [](napi_env, void *data, void *) {
574             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr bundle context is called");
575             delete static_cast<std::weak_ptr<Context> *>(data);
576         },
577         nullptr, nullptr);
578     if (res != napi_ok && workContext != nullptr) {
579         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap failed:%{public}d", res);
580         delete workContext;
581         return CreateJsUndefined(env);
582     }
583     return object;
584 }
585 
OnGetApplicationContext(napi_env env,NapiCallbackInfo & info)586 napi_value JsBaseContext::OnGetApplicationContext(napi_env env, NapiCallbackInfo& info)
587 {
588     auto context = context_.lock();
589     if (!context) {
590         TAG_LOGW(AAFwkTag::APPKIT, "context is already released");
591         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
592         return CreateJsUndefined(env);
593     }
594 
595     auto applicationContext = Context::GetApplicationContext();
596     if (applicationContext == nullptr) {
597         TAG_LOGW(AAFwkTag::APPKIT, "applicationContext is nullptr");
598         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
599         return CreateJsUndefined(env);
600     }
601 
602     if (!applicationContext->GetApplicationInfoUpdateFlag()) {
603         std::shared_ptr<NativeReference> applicationContextObj =
604             ApplicationContextManager::GetApplicationContextManager().GetGlobalObject(env);
605         if (applicationContextObj != nullptr) {
606             napi_value objValue = applicationContextObj->GetNapiValue();
607             return objValue;
608         }
609     }
610     return CreateJSApplicationContext(env, applicationContext);
611 }
612 
CreateDisplayContext(napi_env env,napi_callback_info info)613 napi_value JsBaseContext::CreateDisplayContext(napi_env env, napi_callback_info info)
614 {
615     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnCreateDisplayContext, BASE_CONTEXT_NAME);
616 }
617 
OnCreateDisplayContext(napi_env env,NapiCallbackInfo & info)618 napi_value JsBaseContext::OnCreateDisplayContext(napi_env env, NapiCallbackInfo &info)
619 {
620 #ifdef SUPPORT_GRAPHICS
621     if (info.argc == 0) {
622         TAG_LOGE(AAFwkTag::APPKIT, "not enough params");
623         ThrowTooFewParametersError(env);
624         return CreateJsUndefined(env);
625     }
626 
627     auto context = context_.lock();
628     if (context == nullptr) {
629         TAG_LOGE(AAFwkTag::APPKIT, "context is already released");
630         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
631         return CreateJsUndefined(env);
632     }
633 
634     int64_t displayId = -1;
635     if (!ConvertFromJsValue(env, info.argv[0], displayId)) {
636         TAG_LOGE(AAFwkTag::APPKIT, "parse displayId failed");
637         ThrowInvalidParamError(env, "parse param displayId failed, displayId must be number.");
638         return CreateJsUndefined(env);
639     }
640     if (displayId < 0) {
641         TAG_LOGE(AAFwkTag::APPKIT, "displayId is invalid, less than 0");
642         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
643         return CreateJsUndefined(env);
644     }
645     uint64_t validDisplayId = static_cast<uint64_t>(displayId);
646 
647     auto displayContext = context->CreateDisplayContext(validDisplayId);
648     if (displayContext == nullptr) {
649         TAG_LOGE(AAFwkTag::APPKIT, "failed to create displayContext");
650         return CreateJsUndefined(env);
651     }
652     return CreateJsContext(env, displayContext);
653 #else
654     return CreateJsUndefined(env);
655 #endif
656 }
657 
CreateJsContext(napi_env env,const std::shared_ptr<Context> & context)658 napi_value JsBaseContext::CreateJsContext(napi_env env, const std::shared_ptr<Context> &context)
659 {
660     napi_value value = CreateJsBaseContext(env, context, true);
661     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &value, 1);
662     if (systemModule == nullptr) {
663         TAG_LOGE(AAFwkTag::APPKIT, "invalid systemModule");
664         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
665         return CreateJsUndefined(env);
666     }
667     napi_value object = systemModule->GetNapiValue();
668     if (!CheckTypeForNapiValue(env, object, napi_object)) {
669         TAG_LOGE(AAFwkTag::APPKIT, "failed to get object");
670         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
671         return CreateJsUndefined(env);
672     }
673     auto workContext = new (std::nothrow) std::weak_ptr<Context>(context);
674     auto status = napi_coerce_to_native_binding_object(env, object, DetachCallbackFunc, AttachBaseContext,
675         workContext, nullptr);
676     if (status != napi_ok) {
677         TAG_LOGE(AAFwkTag::APPKIT, "coerce context failed: %{public}d", status);
678         delete workContext;
679         return CreateJsUndefined(env);
680     }
681     auto res = napi_wrap(env, object, workContext,
682         [](napi_env, void *data, void *) {
683             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr module context is called");
684             delete static_cast<std::weak_ptr<Context> *>(data);
685         },
686         nullptr, nullptr);
687     if (res != napi_ok && workContext != nullptr) {
688         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap failed:%{public}d", res);
689         delete workContext;
690         return CreateJsUndefined(env);
691     }
692     return object;
693 }
694 
CreateJSApplicationContext(napi_env env,const std::shared_ptr<ApplicationContext> applicationContext)695 napi_value JsBaseContext::CreateJSApplicationContext(napi_env env,
696     const std::shared_ptr<ApplicationContext> applicationContext)
697 {
698     napi_value value = JsApplicationContextUtils::CreateJsApplicationContext(env);
699     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.ApplicationContext", &value, 1);
700     if (systemModule == nullptr) {
701         TAG_LOGW(AAFwkTag::APPKIT, "OnGetApplicationContext, invalid systemModule");
702         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
703         return CreateJsUndefined(env);
704     }
705     napi_value object = systemModule->GetNapiValue();
706     if (!CheckTypeForNapiValue(env, object, napi_object)) {
707         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
708         AbilityRuntimeErrorUtil::Throw(env, ERR_ABILITY_RUNTIME_EXTERNAL_INVALID_PARAMETER);
709         return CreateJsUndefined(env);
710     }
711     auto workContext = new (std::nothrow) std::weak_ptr<ApplicationContext>(applicationContext);
712     napi_coerce_to_native_binding_object(
713         env, object, DetachCallbackFunc, AttachApplicationContext, workContext, nullptr);
714     auto res = napi_wrap(env, object, workContext,
715         [](napi_env, void *data, void *) {
716             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr application context is called");
717             delete static_cast<std::weak_ptr<ApplicationContext> *>(data);
718             data = nullptr;
719         },
720         nullptr, nullptr);
721     if (res != napi_ok && workContext != nullptr) {
722         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap failed:%{public}d", res);
723         delete workContext;
724         return CreateJsUndefined(env);
725     }
726     napi_ref ref = nullptr;
727     napi_create_reference(env, object, 1, &ref);
728     ApplicationContextManager::GetApplicationContextManager()
729         .AddGlobalObject(env, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
730     applicationContext->SetApplicationInfoUpdateFlag(false);
731     return object;
732 }
733 
CheckCallerIsSystemApp()734 bool JsBaseContext::CheckCallerIsSystemApp()
735 {
736     auto selfToken = IPCSkeleton::GetSelfTokenID();
737     if (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken)) {
738         return false;
739     }
740     return true;
741 }
742 } // namespace
743 
AttachBaseContext(napi_env env,void * value,void * hint)744 napi_value AttachBaseContext(napi_env env, void* value, void* hint)
745 {
746     TAG_LOGD(AAFwkTag::APPKIT, "called");
747     if (value == nullptr || env == nullptr) {
748         TAG_LOGW(AAFwkTag::APPKIT, "invalid parameter");
749         return nullptr;
750     }
751     auto ptr = reinterpret_cast<std::weak_ptr<Context>*>(value)->lock();
752     if (ptr == nullptr) {
753         TAG_LOGW(AAFwkTag::APPKIT, "invalid context");
754         return nullptr;
755     }
756     napi_value object = CreateJsBaseContext(env, ptr, true);
757     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.Context", &object, 1);
758     if (systemModule == nullptr) {
759         TAG_LOGW(AAFwkTag::APPKIT, "AttachBaseContext, invalid systemModule");
760         return nullptr;
761     }
762 
763     napi_value contextObj = systemModule->GetNapiValue();
764     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
765         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
766         return nullptr;
767     }
768     napi_coerce_to_native_binding_object(env, contextObj, DetachCallbackFunc, AttachBaseContext, value, nullptr);
769     auto workContext = new (std::nothrow) std::weak_ptr<Context>(ptr);
770     auto res = napi_wrap(env, contextObj, workContext,
771         [](napi_env, void *data, void *) {
772             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr base context is called");
773             delete static_cast<std::weak_ptr<Context> *>(data);
774         },
775         nullptr, nullptr);
776     if (res != napi_ok && workContext != nullptr) {
777         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap failed:%{public}d", res);
778         delete workContext;
779         return nullptr;
780     }
781     return contextObj;
782 }
783 
AttachApplicationContext(napi_env env,void * value,void * hint)784 napi_value AttachApplicationContext(napi_env env, void* value, void* hint)
785 {
786     TAG_LOGD(AAFwkTag::APPKIT, "called");
787     if (value == nullptr || env == nullptr) {
788         TAG_LOGW(AAFwkTag::APPKIT, "invalid parameter");
789         return nullptr;
790     }
791     auto ptr = reinterpret_cast<std::weak_ptr<ApplicationContext>*>(value)->lock();
792     if (ptr == nullptr) {
793         TAG_LOGW(AAFwkTag::APPKIT, "invalid context");
794         return nullptr;
795     }
796     napi_value object = JsApplicationContextUtils::CreateJsApplicationContext(env);
797     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.ApplicationContext", &object, 1);
798     if (systemModule == nullptr) {
799         TAG_LOGW(AAFwkTag::APPKIT, "invalid systemModule");
800         return nullptr;
801     }
802     auto contextObj = systemModule->GetNapiValue();
803     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
804         TAG_LOGE(AAFwkTag::APPKIT, "Failed to get object");
805         return nullptr;
806     }
807     napi_coerce_to_native_binding_object(
808         env, contextObj, DetachCallbackFunc, AttachApplicationContext, value, nullptr);
809     auto workContext = new (std::nothrow) std::weak_ptr<ApplicationContext>(ptr);
810     auto res = napi_wrap(env, contextObj, workContext,
811         [](napi_env, void *data, void *) {
812             TAG_LOGD(AAFwkTag::APPKIT, "Finalizer for weak_ptr application context is called");
813             delete static_cast<std::weak_ptr<ApplicationContext> *>(data);
814             data = nullptr;
815         },
816         nullptr, nullptr);
817     if (res != napi_ok && workContext != nullptr) {
818         TAG_LOGE(AAFwkTag::APPKIT, "napi_wrap failed:%{public}d", res);
819         delete workContext;
820         return nullptr;
821     }
822     return contextObj;
823 }
824 
BindPropertyAndFunction(napi_env env,napi_value object,const char * moduleName)825 void BindPropertyAndFunction(napi_env env, napi_value object, const char* moduleName)
826 {
827     BindNativeProperty(env, object, "cacheDir", JsBaseContext::GetCacheDir);
828     BindNativeProperty(env, object, "tempDir", JsBaseContext::GetTempDir);
829     BindNativeProperty(env, object, "resourceDir", JsBaseContext::GetResourceDir);
830     BindNativeProperty(env, object, "filesDir", JsBaseContext::GetFilesDir);
831     BindNativeProperty(env, object, "distributedFilesDir", JsBaseContext::GetDistributedFilesDir);
832     BindNativeProperty(env, object, "databaseDir", JsBaseContext::GetDatabaseDir);
833     BindNativeProperty(env, object, "preferencesDir", JsBaseContext::GetPreferencesDir);
834     BindNativeProperty(env, object, "bundleCodeDir", JsBaseContext::GetBundleCodeDir);
835     BindNativeProperty(env, object, "cloudFileDir", JsBaseContext::GetCloudFileDir);
836     BindNativeProperty(env, object, "area", JsBaseContext::GetArea);
837 
838     BindNativeFunction(env, object, "createBundleContext", moduleName, JsBaseContext::CreateBundleContext);
839     BindNativeFunction(env, object, "getApplicationContext", moduleName, JsBaseContext::GetApplicationContext);
840     BindNativeFunction(env, object, "switchArea", moduleName, JsBaseContext::SwitchArea);
841     BindNativeFunction(env, object, "getArea", moduleName, JsBaseContext::GetArea);
842     BindNativeFunction(env, object, "createModuleContext", moduleName, JsBaseContext::CreateModuleContext);
843     BindNativeFunction(env, object, "createSystemHspModuleResourceManager", moduleName,
844         JsBaseContext::CreateSystemHspModuleResourceManager);
845     BindNativeFunction(env, object, "createModuleResourceManager", moduleName,
846         JsBaseContext::CreateModuleResourceManager);
847     BindNativeFunction(env, object, "getGroupDir", moduleName, JsBaseContext::GetGroupDir);
848     BindNativeFunction(env, object, "createDisplayContext", moduleName, JsBaseContext::CreateDisplayContext);
849 }
850 
CreateJsBaseContext(napi_env env,std::shared_ptr<Context> context,bool keepContext)851 napi_value CreateJsBaseContext(napi_env env, std::shared_ptr<Context> context, bool keepContext)
852 {
853     napi_value object = nullptr;
854     napi_create_object(env, &object);
855     if (object == nullptr) {
856         TAG_LOGW(AAFwkTag::APPKIT, "invalid object");
857         return nullptr;
858     }
859     if (context == nullptr) {
860         TAG_LOGE(AAFwkTag::APPKIT, "context object");
861         return nullptr;
862     }
863     auto jsContext = std::make_unique<JsBaseContext>(context);
864     SetNamedNativePointer(env, object, BASE_CONTEXT_NAME, jsContext.release(), JsBaseContext::Finalizer);
865 
866     auto appInfo = context->GetApplicationInfo();
867     if (appInfo != nullptr) {
868         napi_set_named_property(env, object, "applicationInfo", CreateJsApplicationInfo(env, *appInfo));
869     }
870     auto hapModuleInfo = context->GetHapModuleInfo();
871     if (hapModuleInfo != nullptr) {
872         napi_set_named_property(env, object, "currentHapModuleInfo", CreateJsHapModuleInfo(env, *hapModuleInfo));
873     }
874     auto resourceManager = context->GetResourceManager();
875     if (resourceManager != nullptr) {
876         auto jsResourceManager = CreateJsResourceManager(env, resourceManager, context);
877         if (jsResourceManager != nullptr) {
878             napi_set_named_property(env, object, "resourceManager", jsResourceManager);
879         } else {
880             TAG_LOGE(AAFwkTag::APPKIT, "jsResourceManager is nullptr");
881         }
882     }
883 
884     const char *moduleName = "JsBaseContext";
885     BindPropertyAndFunction(env, object, moduleName);
886     return object;
887 }
888 }  // namespace AbilityRuntime
889 }  // namespace OHOS
890