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