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