1 /*
2  * Copyright (c) 2023-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 <iostream>
19 #include "hilog_tag_wrapper.h"
20 #include "js_application_context_utils.h"
21 #include "js_data_converter.h"
22 #include "js_runtime_utils.h"
23 
24 namespace OHOS {
25 namespace AbilityRuntime {
26 namespace {
27 constexpr char BASE_CONTEXT_NAME[] = "__base_context_ptr__";
28 
29 class JsBaseContext {
30 public:
JsBaseContext(std::weak_ptr<Context> && context)31     explicit JsBaseContext(std::weak_ptr<Context> &&context) : context_(std::move(context)) {}
32     virtual ~JsBaseContext() = default;
33 
34     static void Finalizer(napi_env env, void *data, void *hint);
35     static napi_value CreateBundleContext(napi_env env, napi_callback_info info);
36     static napi_value GetApplicationContext(napi_env env, napi_callback_info info);
37     static napi_value SwitchArea(napi_env env, napi_callback_info info);
38     static napi_value GetArea(napi_env env, napi_callback_info info);
39     static napi_value CreateModuleContext(napi_env env, napi_callback_info info);
40     static napi_value CreateModuleResourceManager(napi_env env, napi_callback_info info);
41 
42     static napi_value GetCacheDir(napi_env env, napi_callback_info info);
43     static napi_value GetTempDir(napi_env env, napi_callback_info info);
44     static napi_value GetResourceDir(napi_env env, napi_callback_info info);
45     static napi_value GetFilesDir(napi_env env, napi_callback_info info);
46     static napi_value GetDistributedFilesDir(napi_env env, napi_callback_info info);
47     static napi_value GetDatabaseDir(napi_env env, napi_callback_info info);
48     static napi_value GetPreferencesDir(napi_env env, napi_callback_info info);
49     static napi_value GetBundleCodeDir(napi_env env, napi_callback_info info);
50     static napi_value GetCloudFileDir(napi_env env, napi_callback_info info);
51 
52     napi_value OnGetCacheDir(napi_env env, NapiCallbackInfo &info);
53     napi_value OnGetTempDir(napi_env env, NapiCallbackInfo &info);
54     napi_value OnGetResourceDir(napi_env env, NapiCallbackInfo &info);
55     napi_value OnGetFilesDir(napi_env env, NapiCallbackInfo &info);
56     napi_value OnGetDistributedFilesDir(napi_env env, NapiCallbackInfo &info);
57     napi_value OnGetDatabaseDir(napi_env env, NapiCallbackInfo &info);
58     napi_value OnGetPreferencesDir(napi_env env, NapiCallbackInfo &info);
59     napi_value OnGetBundleCodeDir(napi_env env, NapiCallbackInfo &info);
60     napi_value OnGetCloudFileDir(napi_env env, NapiCallbackInfo &info);
61     napi_value OnSwitchArea(napi_env env, NapiCallbackInfo &info);
62     napi_value OnGetArea(napi_env env, NapiCallbackInfo &info);
63     napi_value OnGetApplicationContext(napi_env env, NapiCallbackInfo &info);
64 
65 protected:
66     std::weak_ptr<Context> context_;
67 };
68 
Finalizer(napi_env env,void * data,void * hint)69 void JsBaseContext::Finalizer(napi_env env, void *data, void *hint)
70 {
71     TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
72     std::unique_ptr<JsBaseContext>(static_cast<JsBaseContext*>(data));
73 }
74 
CreateBundleContext(napi_env env,napi_callback_info info)75 napi_value JsBaseContext::CreateBundleContext(napi_env env, napi_callback_info info)
76 {
77     return nullptr;
78 }
79 
GetApplicationContext(napi_env env,napi_callback_info info)80 napi_value JsBaseContext::GetApplicationContext(napi_env env, napi_callback_info info)
81 {
82     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetApplicationContext, BASE_CONTEXT_NAME);
83 }
84 
SwitchArea(napi_env env,napi_callback_info info)85 napi_value JsBaseContext::SwitchArea(napi_env env, napi_callback_info info)
86 {
87     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnSwitchArea, BASE_CONTEXT_NAME);
88 }
89 
OnSwitchArea(napi_env env,NapiCallbackInfo & info)90 napi_value JsBaseContext::OnSwitchArea(napi_env env, NapiCallbackInfo &info)
91 {
92     if (info.argc == 0) {
93         TAG_LOGE(AAFwkTag::ABILITY_SIM, "invalid argc");
94         return CreateJsUndefined(env);
95     }
96 
97     auto context = context_.lock();
98     if (!context) {
99         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
100         return CreateJsUndefined(env);
101     }
102 
103     int mode = 0;
104     if (!ConvertFromJsValue(env, info.argv[0], mode)) {
105         TAG_LOGE(AAFwkTag::ABILITY_SIM, "Parse mode failed");
106         return CreateJsUndefined(env);
107     }
108 
109     context->SwitchArea(mode);
110 
111     napi_value object = info.thisVar;
112     if (object == nullptr) {
113         TAG_LOGE(AAFwkTag::ABILITY_SIM, "null object");
114         return CreateJsUndefined(env);
115     }
116     BindNativeProperty(env, object, "cacheDir", GetCacheDir);
117     BindNativeProperty(env, object, "tempDir", GetTempDir);
118     BindNativeProperty(env, object, "resourceDir", GetResourceDir);
119     BindNativeProperty(env, object, "filesDir", GetFilesDir);
120     BindNativeProperty(env, object, "distributedFilesDir", GetDistributedFilesDir);
121     BindNativeProperty(env, object, "databaseDir", GetDatabaseDir);
122     BindNativeProperty(env, object, "preferencesDir", GetPreferencesDir);
123     BindNativeProperty(env, object, "bundleCodeDir", GetBundleCodeDir);
124     BindNativeProperty(env, object, "cloudFileDir", GetCloudFileDir);
125     return CreateJsUndefined(env);
126 }
127 
CreateModuleContext(napi_env env,napi_callback_info info)128 napi_value JsBaseContext::CreateModuleContext(napi_env env, napi_callback_info info)
129 {
130     return nullptr;
131 }
132 
CreateModuleResourceManager(napi_env env,napi_callback_info info)133 napi_value JsBaseContext::CreateModuleResourceManager(napi_env env, napi_callback_info info)
134 {
135     return nullptr;
136 }
137 
GetArea(napi_env env,napi_callback_info info)138 napi_value JsBaseContext::GetArea(napi_env env, napi_callback_info info)
139 {
140     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetArea, BASE_CONTEXT_NAME);
141 }
142 
OnGetArea(napi_env env,NapiCallbackInfo & info)143 napi_value JsBaseContext::OnGetArea(napi_env env, NapiCallbackInfo &info)
144 {
145     auto context = context_.lock();
146     if (!context) {
147         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
148         return CreateJsUndefined(env);
149     }
150     int area = context->GetArea();
151     return CreateJsValue(env, area);
152 }
153 
GetCacheDir(napi_env env,napi_callback_info info)154 napi_value JsBaseContext::GetCacheDir(napi_env env, napi_callback_info info)
155 {
156     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetCacheDir, BASE_CONTEXT_NAME);
157 }
158 
OnGetCacheDir(napi_env env,NapiCallbackInfo & info)159 napi_value JsBaseContext::OnGetCacheDir(napi_env env, NapiCallbackInfo &info)
160 {
161     auto context = context_.lock();
162     if (!context) {
163         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
164         return CreateJsUndefined(env);
165     }
166     std::string path = context->GetCacheDir();
167     return CreateJsValue(env, path);
168 }
169 
GetTempDir(napi_env env,napi_callback_info info)170 napi_value JsBaseContext::GetTempDir(napi_env env, napi_callback_info info)
171 {
172     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetTempDir, BASE_CONTEXT_NAME);
173 }
174 
OnGetTempDir(napi_env env,NapiCallbackInfo & info)175 napi_value JsBaseContext::OnGetTempDir(napi_env env, NapiCallbackInfo &info)
176 {
177     auto context = context_.lock();
178     if (!context) {
179         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
180         return CreateJsUndefined(env);
181     }
182     std::string path = context->GetTempDir();
183     return CreateJsValue(env, path);
184 }
185 
GetResourceDir(napi_env env,napi_callback_info info)186 napi_value JsBaseContext::GetResourceDir(napi_env env, napi_callback_info info)
187 {
188     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetResourceDir, BASE_CONTEXT_NAME);
189 }
190 
OnGetResourceDir(napi_env env,NapiCallbackInfo & info)191 napi_value JsBaseContext::OnGetResourceDir(napi_env env, NapiCallbackInfo &info)
192 {
193     auto context = context_.lock();
194     if (!context) {
195         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
196         return CreateJsUndefined(env);
197     }
198     std::string path = context->GetResourceDir();
199     return CreateJsValue(env, path);
200 }
201 
GetFilesDir(napi_env env,napi_callback_info info)202 napi_value JsBaseContext::GetFilesDir(napi_env env, napi_callback_info info)
203 {
204     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetFilesDir, BASE_CONTEXT_NAME);
205 }
206 
OnGetFilesDir(napi_env env,NapiCallbackInfo & info)207 napi_value JsBaseContext::OnGetFilesDir(napi_env env, NapiCallbackInfo &info)
208 {
209     auto context = context_.lock();
210     if (!context) {
211         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
212         return CreateJsUndefined(env);
213     }
214     std::string path = context->GetFilesDir();
215     return CreateJsValue(env, path);
216 }
217 
GetDistributedFilesDir(napi_env env,napi_callback_info info)218 napi_value JsBaseContext::GetDistributedFilesDir(napi_env env, napi_callback_info info)
219 {
220     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetDistributedFilesDir, BASE_CONTEXT_NAME);
221 }
222 
OnGetDistributedFilesDir(napi_env env,NapiCallbackInfo & info)223 napi_value JsBaseContext::OnGetDistributedFilesDir(napi_env env, NapiCallbackInfo &info)
224 {
225     auto context = context_.lock();
226     if (!context) {
227         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
228         return CreateJsUndefined(env);
229     }
230     std::string path = context->GetDistributedFilesDir();
231     return CreateJsValue(env, path);
232 }
233 
GetDatabaseDir(napi_env env,napi_callback_info info)234 napi_value JsBaseContext::GetDatabaseDir(napi_env env, napi_callback_info info)
235 {
236     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetDatabaseDir, BASE_CONTEXT_NAME);
237 }
238 
OnGetDatabaseDir(napi_env env,NapiCallbackInfo & info)239 napi_value JsBaseContext::OnGetDatabaseDir(napi_env env, NapiCallbackInfo &info)
240 {
241     auto context = context_.lock();
242     if (!context) {
243         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
244         return CreateJsUndefined(env);
245     }
246     std::string path = context->GetDatabaseDir();
247     return CreateJsValue(env, path);
248 }
249 
GetPreferencesDir(napi_env env,napi_callback_info info)250 napi_value JsBaseContext::GetPreferencesDir(napi_env env, napi_callback_info info)
251 {
252     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetPreferencesDir, BASE_CONTEXT_NAME);
253 }
254 
OnGetPreferencesDir(napi_env env,NapiCallbackInfo & info)255 napi_value JsBaseContext::OnGetPreferencesDir(napi_env env, NapiCallbackInfo &info)
256 {
257     auto context = context_.lock();
258     if (!context) {
259         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
260         return CreateJsUndefined(env);
261     }
262     std::string path = context->GetPreferencesDir();
263     return CreateJsValue(env, path);
264 }
265 
GetBundleCodeDir(napi_env env,napi_callback_info info)266 napi_value JsBaseContext::GetBundleCodeDir(napi_env env, napi_callback_info info)
267 {
268     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetBundleCodeDir, BASE_CONTEXT_NAME);
269 }
270 
OnGetBundleCodeDir(napi_env env,NapiCallbackInfo & info)271 napi_value JsBaseContext::OnGetBundleCodeDir(napi_env env, NapiCallbackInfo &info)
272 {
273     auto context = context_.lock();
274     if (!context) {
275         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
276         return CreateJsUndefined(env);
277     }
278     std::string path = context->GetBundleCodeDir();
279     return CreateJsValue(env, path);
280 }
281 
GetCloudFileDir(napi_env env,napi_callback_info info)282 napi_value JsBaseContext::GetCloudFileDir(napi_env env, napi_callback_info info)
283 {
284     GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, JsBaseContext, OnGetCloudFileDir, BASE_CONTEXT_NAME);
285 }
286 
OnGetCloudFileDir(napi_env env,NapiCallbackInfo & info)287 napi_value JsBaseContext::OnGetCloudFileDir(napi_env env, NapiCallbackInfo &info)
288 {
289     auto context = context_.lock();
290     if (!context) {
291         TAG_LOGW(AAFwkTag::ABILITY_SIM, "context released");
292         return CreateJsUndefined(env);
293     }
294     std::string path = context->GetCloudFileDir();
295     return CreateJsValue(env, path);
296 }
297 
OnGetApplicationContext(napi_env env,NapiCallbackInfo & info)298 napi_value JsBaseContext::OnGetApplicationContext(napi_env env, NapiCallbackInfo &info)
299 {
300     TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
301     napi_value value = JsApplicationContextUtils::CreateJsApplicationContext(env, context_.lock());
302     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.ApplicationContext", &value, 1);
303     if (systemModule == nullptr) {
304         return CreateJsUndefined(env);
305     }
306     auto contextObj =  systemModule->GetNapiValue();
307     return contextObj;
308 }
309 } // namespace
310 
CreateJsBaseContext(napi_env env,std::shared_ptr<Context> context,bool keepContext)311 napi_value CreateJsBaseContext(napi_env env, std::shared_ptr<Context> context, bool keepContext)
312 {
313     napi_value object = nullptr;
314     napi_create_object(env, &object);
315     if (object == nullptr) {
316         TAG_LOGW(AAFwkTag::ABILITY_SIM, "null object");
317         return object;
318     }
319 
320     auto appInfo = context->GetApplicationInfo();
321     if (appInfo != nullptr) {
322         napi_set_named_property(env, object, "applicationInfo", CreateJsApplicationInfo(env, *appInfo));
323     }
324     auto hapModuleInfo = context->GetHapModuleInfo();
325     if (hapModuleInfo != nullptr) {
326         napi_set_named_property(env, object, "currentHapModuleInfo", CreateJsHapModuleInfo(env, *hapModuleInfo));
327     }
328 
329     auto jsContext = std::make_unique<JsBaseContext>(context);
330     SetNamedNativePointer(env, object, BASE_CONTEXT_NAME, jsContext.release(), JsBaseContext::Finalizer);
331 
332     BindNativeProperty(env, object, "cacheDir", JsBaseContext::GetCacheDir);
333     BindNativeProperty(env, object, "tempDir", JsBaseContext::GetTempDir);
334     BindNativeProperty(env, object, "resourceDir", JsBaseContext::GetResourceDir);
335     BindNativeProperty(env, object, "filesDir", JsBaseContext::GetFilesDir);
336     BindNativeProperty(env, object, "distributedFilesDir", JsBaseContext::GetDistributedFilesDir);
337     BindNativeProperty(env, object, "databaseDir", JsBaseContext::GetDatabaseDir);
338     BindNativeProperty(env, object, "preferencesDir", JsBaseContext::GetPreferencesDir);
339     BindNativeProperty(env, object, "bundleCodeDir", JsBaseContext::GetBundleCodeDir);
340     BindNativeProperty(env, object, "cloudFileDir", JsBaseContext::GetCloudFileDir);
341     BindNativeProperty(env, object, "area", JsBaseContext::GetArea);
342     const char *moduleName = "JsBaseContext";
343     BindNativeFunction(env, object, "createBundleContext", moduleName, JsBaseContext::CreateBundleContext);
344     BindNativeFunction(env, object, "getApplicationContext", moduleName, JsBaseContext::GetApplicationContext);
345     BindNativeFunction(env, object, "switchArea", moduleName, JsBaseContext::SwitchArea);
346     BindNativeFunction(env, object, "getArea", moduleName, JsBaseContext::GetArea);
347     BindNativeFunction(env, object, "createModuleContext", moduleName, JsBaseContext::CreateModuleContext);
348     BindNativeFunction(env, object, "createModuleResourceManager", moduleName,
349         JsBaseContext::CreateModuleResourceManager);
350 
351     return object;
352 }
353 } // namespace AbilityRuntime
354 } // namespace OHOS
355