1 /*
2 * Copyright (c) 2021 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 "hilog_wrapper.h"
19 #include "js_data_struct_converter.h"
20 #include "js_hap_module_info_utils.h"
21 #include "js_resource_manager_utils.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(NativeEngine* engine, void* data, void* hint);
35 static NativeValue* CreateBundleContext(NativeEngine* engine, NativeCallbackInfo* info);
36 static NativeValue* GetApplicationContext(NativeEngine* engine, NativeCallbackInfo* info);
37 static NativeValue* SwitchArea(NativeEngine* engine, NativeCallbackInfo* info);
38
39 NativeValue* OnGetCacheDir(NativeEngine& engine, NativeCallbackInfo& info);
40 NativeValue* OnGetTempDir(NativeEngine& engine, NativeCallbackInfo& info);
41 NativeValue* OnGetFilesDir(NativeEngine& engine, NativeCallbackInfo& info);
42 NativeValue* OnGetDistributedFilesDir(NativeEngine& engine, NativeCallbackInfo& info);
43 NativeValue* OnGetDatabaseDir(NativeEngine& engine, NativeCallbackInfo& info);
44 NativeValue* OnGetStorageDir(NativeEngine& engine, NativeCallbackInfo& info);
45 NativeValue* OnGetBundleCodeDir(NativeEngine& engine, NativeCallbackInfo& info);
46
47 static NativeValue* GetCacheDir(NativeEngine* engine, NativeCallbackInfo* info);
48 static NativeValue* GetTempDir(NativeEngine* engine, NativeCallbackInfo* info);
49 static NativeValue* GetFilesDir(NativeEngine* engine, NativeCallbackInfo* info);
50 static NativeValue* GetDistributedFilesDir(NativeEngine* engine, NativeCallbackInfo* info);
51 static NativeValue* GetDatabaseDir(NativeEngine* engine, NativeCallbackInfo* info);
52 static NativeValue* GetStorageDir(NativeEngine* engine, NativeCallbackInfo* info);
53 static NativeValue* GetBundleCodeDir(NativeEngine* engine, NativeCallbackInfo* info);
54
KeepContext(std::shared_ptr<Context> context)55 void KeepContext(std::shared_ptr<Context> context)
56 {
57 keepContext_ = context;
58 }
59
60 private:
61 NativeValue* OnCreateBundleContext(NativeEngine& engine, NativeCallbackInfo& info);
62 NativeValue* OnGetApplicationContext(NativeEngine& engine, NativeCallbackInfo& info);
63 NativeValue* OnSwitchArea(NativeEngine& engine, NativeCallbackInfo& info);
64
65 std::shared_ptr<Context> keepContext_;
66
67 protected:
68 std::weak_ptr<Context> context_;
69 };
70
Finalizer(NativeEngine * engine,void * data,void * hint)71 void JsBaseContext::Finalizer(NativeEngine* engine, void* data, void* hint)
72 {
73 HILOG_INFO("JsBaseContext::Finalizer is called");
74 std::unique_ptr<JsBaseContext>(static_cast<JsBaseContext*>(data));
75 }
76
CreateBundleContext(NativeEngine * engine,NativeCallbackInfo * info)77 NativeValue* JsBaseContext::CreateBundleContext(NativeEngine* engine, NativeCallbackInfo* info)
78 {
79 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
80 return me != nullptr ? me->OnCreateBundleContext(*engine, *info) : nullptr;
81 }
82
GetApplicationContext(NativeEngine * engine,NativeCallbackInfo * info)83 NativeValue* JsBaseContext::GetApplicationContext(NativeEngine* engine, NativeCallbackInfo* info)
84 {
85 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
86 return me != nullptr ? me->OnGetApplicationContext(*engine, *info) : nullptr;
87 }
88
SwitchArea(NativeEngine * engine,NativeCallbackInfo * info)89 NativeValue* JsBaseContext::SwitchArea(NativeEngine* engine, NativeCallbackInfo* info)
90 {
91 HILOG_INFO("JsBaseContext::SwitchArea is called");
92 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
93 return me != nullptr ? me->OnSwitchArea(*engine, *info) : nullptr;
94 }
95
OnSwitchArea(NativeEngine & engine,NativeCallbackInfo & info)96 NativeValue* JsBaseContext::OnSwitchArea(NativeEngine& engine, NativeCallbackInfo& info)
97 {
98 if (info.argc == 0) {
99 HILOG_ERROR("Not enough params");
100 return engine.CreateUndefined();
101 }
102
103 auto context = context_.lock();
104 if (!context) {
105 HILOG_WARN("context is already released");
106 return engine.CreateUndefined();
107 }
108
109 int mode;
110 if (!ConvertFromJsValue(engine, info.argv[0], mode)) {
111 HILOG_ERROR("Parse mode failed");
112 return engine.CreateUndefined();
113 }
114
115 context->SwitchArea(mode);
116
117 NativeValue* thisVar = info.thisVar;
118 NativeObject* object = ConvertNativeValueTo<NativeObject>(thisVar);
119 BindNativeProperty(*object, "cacheDir", GetCacheDir);
120 BindNativeProperty(*object, "tempDir", GetTempDir);
121 BindNativeProperty(*object, "filesDir", GetFilesDir);
122 BindNativeProperty(*object, "distributedFilesDir", GetDistributedFilesDir);
123 BindNativeProperty(*object, "databaseDir", GetDatabaseDir);
124 BindNativeProperty(*object, "storageDir", GetStorageDir);
125 BindNativeProperty(*object, "bundleCodeDir", GetBundleCodeDir);
126 return engine.CreateUndefined();
127 }
128
GetCacheDir(NativeEngine * engine,NativeCallbackInfo * info)129 NativeValue* JsBaseContext::GetCacheDir(NativeEngine* engine, NativeCallbackInfo* info)
130 {
131 HILOG_INFO("JsBaseContext::SwitchArea is called");
132 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
133 return me != nullptr ? me->OnGetCacheDir(*engine, *info) : nullptr;
134 }
135
OnGetCacheDir(NativeEngine & engine,NativeCallbackInfo & info)136 NativeValue* JsBaseContext::OnGetCacheDir(NativeEngine& engine, NativeCallbackInfo& info)
137 {
138 auto context = context_.lock();
139 if (!context) {
140 HILOG_WARN("context is already released");
141 return engine.CreateUndefined();
142 }
143 std::string path = context->GetCacheDir();
144 return engine.CreateString(path.c_str(), path.length());
145 }
146
GetTempDir(NativeEngine * engine,NativeCallbackInfo * info)147 NativeValue* JsBaseContext::GetTempDir(NativeEngine* engine, NativeCallbackInfo* info)
148 {
149 HILOG_INFO("JsBaseContext::SwitchArea is called");
150 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
151 return me != nullptr ? me->OnGetTempDir(*engine, *info) : nullptr;
152 }
153
OnGetTempDir(NativeEngine & engine,NativeCallbackInfo & info)154 NativeValue* JsBaseContext::OnGetTempDir(NativeEngine& engine, NativeCallbackInfo& info)
155 {
156 auto context = context_.lock();
157 if (!context) {
158 HILOG_WARN("context is already released");
159 return engine.CreateUndefined();
160 }
161 std::string path = context->GetTempDir();
162 return engine.CreateString(path.c_str(), path.length());
163 }
164
GetFilesDir(NativeEngine * engine,NativeCallbackInfo * info)165 NativeValue* JsBaseContext::GetFilesDir(NativeEngine* engine, NativeCallbackInfo* info)
166 {
167 HILOG_INFO("JsBaseContext::SwitchArea is called");
168 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
169 return me != nullptr ? me->OnGetFilesDir(*engine, *info) : nullptr;
170 }
171
OnGetFilesDir(NativeEngine & engine,NativeCallbackInfo & info)172 NativeValue* JsBaseContext::OnGetFilesDir(NativeEngine& engine, NativeCallbackInfo& info)
173 {
174 auto context = context_.lock();
175 if (!context) {
176 HILOG_WARN("context is already released");
177 return engine.CreateUndefined();
178 }
179 std::string path = context->GetFilesDir();
180 return engine.CreateString(path.c_str(), path.length());
181 }
182
GetDistributedFilesDir(NativeEngine * engine,NativeCallbackInfo * info)183 NativeValue* JsBaseContext::GetDistributedFilesDir(NativeEngine* engine, NativeCallbackInfo* info)
184 {
185 HILOG_INFO("JsBaseContext::SwitchArea is called");
186 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
187 return me != nullptr ? me->OnGetDistributedFilesDir(*engine, *info) : nullptr;
188 }
189
OnGetDistributedFilesDir(NativeEngine & engine,NativeCallbackInfo & info)190 NativeValue* JsBaseContext::OnGetDistributedFilesDir(NativeEngine& engine, NativeCallbackInfo& info)
191 {
192 auto context = context_.lock();
193 if (!context) {
194 HILOG_WARN("context is already released");
195 return engine.CreateUndefined();
196 }
197 std::string path = context->GetDistributedFilesDir();
198 return engine.CreateString(path.c_str(), path.length());
199 }
200
GetDatabaseDir(NativeEngine * engine,NativeCallbackInfo * info)201 NativeValue* JsBaseContext::GetDatabaseDir(NativeEngine* engine, NativeCallbackInfo* info)
202 {
203 HILOG_INFO("JsBaseContext::SwitchArea is called");
204 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
205 return me != nullptr ? me->OnGetDatabaseDir(*engine, *info) : nullptr;
206 }
207
OnGetDatabaseDir(NativeEngine & engine,NativeCallbackInfo & info)208 NativeValue* JsBaseContext::OnGetDatabaseDir(NativeEngine& engine, NativeCallbackInfo& info)
209 {
210 auto context = context_.lock();
211 if (!context) {
212 HILOG_WARN("context is already released");
213 return engine.CreateUndefined();
214 }
215 std::string path = context->GetDatabaseDir();
216 return engine.CreateString(path.c_str(), path.length());
217 }
218
GetStorageDir(NativeEngine * engine,NativeCallbackInfo * info)219 NativeValue* JsBaseContext::GetStorageDir(NativeEngine* engine, NativeCallbackInfo* info)
220 {
221 HILOG_INFO("JsBaseContext::SwitchArea is called");
222 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
223 return me != nullptr ? me->OnGetStorageDir(*engine, *info) : nullptr;
224 }
225
OnGetStorageDir(NativeEngine & engine,NativeCallbackInfo & info)226 NativeValue* JsBaseContext::OnGetStorageDir(NativeEngine& engine, NativeCallbackInfo& info)
227 {
228 auto context = context_.lock();
229 if (!context) {
230 HILOG_WARN("context is already released");
231 return engine.CreateUndefined();
232 }
233 std::string path = context->GetStorageDir();
234 return engine.CreateString(path.c_str(), path.length());
235 }
236
GetBundleCodeDir(NativeEngine * engine,NativeCallbackInfo * info)237 NativeValue* JsBaseContext::GetBundleCodeDir(NativeEngine* engine, NativeCallbackInfo* info)
238 {
239 HILOG_INFO("JsBaseContext::SwitchArea is called");
240 JsBaseContext* me = CheckParamsAndGetThis<JsBaseContext>(engine, info, BASE_CONTEXT_NAME);
241 return me != nullptr ? me->OnGetBundleCodeDir(*engine, *info) : nullptr;
242 }
243
OnGetBundleCodeDir(NativeEngine & engine,NativeCallbackInfo & info)244 NativeValue* JsBaseContext::OnGetBundleCodeDir(NativeEngine& engine, NativeCallbackInfo& info)
245 {
246 auto context = context_.lock();
247 if (!context) {
248 HILOG_WARN("context is already released");
249 return engine.CreateUndefined();
250 }
251 std::string path = context->GetBundleCodeDir();
252 return engine.CreateString(path.c_str(), path.length());
253 }
254
OnCreateBundleContext(NativeEngine & engine,NativeCallbackInfo & info)255 NativeValue* JsBaseContext::OnCreateBundleContext(NativeEngine& engine, NativeCallbackInfo& info)
256 {
257 if (info.argc == 0) {
258 HILOG_ERROR("Not enough params");
259 return engine.CreateUndefined();
260 }
261
262 auto context = context_.lock();
263 if (!context) {
264 HILOG_WARN("context is already released");
265 return engine.CreateUndefined();
266 }
267
268 std::string bundleName;
269 if (!ConvertFromJsValue(engine, info.argv[0], bundleName)) {
270 HILOG_ERROR("Parse bundleName failed");
271 return engine.CreateUndefined();
272 }
273
274 auto bundleContext = context->CreateBundleContext(bundleName);
275 if (!bundleContext) {
276 HILOG_ERROR("bundleContext is nullptr");
277 return engine.CreateUndefined();
278 }
279
280 JsRuntime& jsRuntime = *static_cast<JsRuntime*>(engine.GetJsEngine());
281 NativeValue* value = CreateJsBaseContext(engine, bundleContext, true);
282 return jsRuntime.LoadSystemModule("application.Context", &value, 1)->Get();
283 }
284
OnGetApplicationContext(NativeEngine & engine,NativeCallbackInfo & info)285 NativeValue* JsBaseContext::OnGetApplicationContext(NativeEngine& engine, NativeCallbackInfo& info)
286 {
287 auto context = context_.lock();
288 if (!context) {
289 HILOG_WARN("context is already released");
290 return engine.CreateUndefined();
291 }
292
293 auto appContext = context->GetApplicationContext();
294 if (!appContext) {
295 HILOG_ERROR("appContext is nullptr");
296 return engine.CreateUndefined();
297 }
298
299 JsRuntime& jsRuntime = *static_cast<JsRuntime*>(engine.GetJsEngine());
300 NativeValue* value = CreateJsBaseContext(engine, appContext, true);
301 return jsRuntime.LoadSystemModule("application.Context", &value, 1)->Get();
302 }
303 } // namespace
304
CreateJsBaseContext(NativeEngine & engine,std::shared_ptr<Context> context,bool keepContext)305 NativeValue* CreateJsBaseContext(NativeEngine& engine, std::shared_ptr<Context> context, bool keepContext)
306 {
307 NativeValue* objValue = engine.CreateObject();
308 NativeObject* object = ConvertNativeValueTo<NativeObject>(objValue);
309
310 auto jsContext = std::make_unique<JsBaseContext>(context);
311 if (keepContext) {
312 jsContext->KeepContext(context);
313 }
314 SetNamedNativePointer(engine, *object, BASE_CONTEXT_NAME, jsContext.release(), JsBaseContext::Finalizer);
315
316 auto appInfo = context->GetApplicationInfo();
317 if (appInfo != nullptr) {
318 object->SetProperty("applicationInfo", CreateJsApplicationInfo(engine, *appInfo));
319 }
320 auto hapModuleInfo = context->GetHapModuleInfo();
321 if (hapModuleInfo != nullptr) {
322 object->SetProperty("currentHapModuleInfo", CreateJsHapModuleInfo(engine, *hapModuleInfo));
323 }
324 auto resourceManager = context->GetResourceManager();
325 if (resourceManager != nullptr) {
326 object->SetProperty("resourceManager", CreateJsResourceManager(engine, resourceManager));
327 }
328
329 BindNativeProperty(*object, "cacheDir", JsBaseContext::GetCacheDir);
330 BindNativeProperty(*object, "tempDir", JsBaseContext::GetTempDir);
331 BindNativeProperty(*object, "filesDir", JsBaseContext::GetFilesDir);
332 BindNativeProperty(*object, "distributedFilesDir", JsBaseContext::GetDistributedFilesDir);
333 BindNativeProperty(*object, "databaseDir", JsBaseContext::GetDatabaseDir);
334 BindNativeProperty(*object, "storageDir", JsBaseContext::GetStorageDir);
335 BindNativeProperty(*object, "bundleCodeDir", JsBaseContext::GetBundleCodeDir);
336 BindNativeFunction(engine, *object, "createBundleContext", JsBaseContext::CreateBundleContext);
337 BindNativeFunction(engine, *object, "getApplicationContext", JsBaseContext::GetApplicationContext);
338 BindNativeFunction(engine, *object, "switchArea", JsBaseContext::SwitchArea);
339
340 return objValue;
341 }
342 } // namespace AbilityRuntime
343 } // namespace OHOS
344