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