1 /*
2 * Copyright (c) 2022 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 #if !defined(__IDE_PREVIEW__)
17 #include "resource_manager_addon.h"
18 #include "ability.h"
19 #include "hisysevent_adapter.h"
20 #include "hitrace_meter.h"
21 #include "js_runtime_utils.h"
22 #endif
23
24 #include "hilog/log.h"
25 #include "napi/native_api.h"
26 #include "napi/native_common.h"
27 #include "res_common.h"
28 #include "resource_manager_napi_async_impl.h"
29
30 namespace OHOS {
31 namespace Global {
32 namespace Resource {
33 #if !defined(__IDE_PREVIEW__)
34 #define GET_PARAMS(env, info, num) \
35 size_t argc = num; \
36 napi_value argv[num] = {nullptr}; \
37 napi_value thisVar = nullptr; \
38 void *data = nullptr; \
39 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
40
41 using namespace OHOS::AppExecFwk;
42
ExecuteGetResMgr(napi_env env,void * data)43 static void ExecuteGetResMgr(napi_env env, void* data)
44 {
45 if (data == nullptr) {
46 return;
47 }
48 ResMgrDataContext *asyncContext = static_cast<ResMgrDataContext*>(data);
49
50 asyncContext->createValueFunc_ = [](napi_env env, ResMgrDataContext &context) -> napi_value {
51 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_GLOBAL_RESMGR, "Create ResourceManager");
52 napi_value result = ResourceManagerAddon::Create(env, context.bundleName_, context.resMgr_, nullptr);
53 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_GLOBAL_RESMGR);
54 if (result == nullptr) {
55 context.SetErrorMsg("Failed to get ResourceManagerAddon");
56 ReportInitResourceManagerFail(context.bundleName_, "failed to get ResourceManagerAddon");
57 return nullptr;
58 }
59 return result;
60 };
61 }
62
GetGlobalAbility(napi_env env)63 Ability* GetGlobalAbility(napi_env env)
64 {
65 napi_value global;
66 napi_status status = napi_get_global(env, &global);
67 if (status != napi_ok) {
68 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get global");
69 return nullptr;
70 }
71
72 napi_value abilityObj;
73 status = napi_get_named_property(env, global, "ability", &abilityObj);
74 if (status != napi_ok || abilityObj == nullptr) {
75 RESMGR_HILOGI(RESMGR_JS_TAG, "Failed to get ability property");
76 return nullptr;
77 }
78
79 Ability* ability = nullptr;
80 status = napi_get_value_external(env, abilityObj, (void **)&ability);
81 if (status == napi_ok && ability != nullptr) {
82 return ability;
83 }
84
85 return nullptr;
86 }
87
InitAsyncContext(napi_env env,const std::string & bundleName,Ability * ability,const std::shared_ptr<AbilityRuntime::Context> & context,ResMgrDataContext & asyncContext)88 static bool InitAsyncContext(napi_env env, const std::string &bundleName, Ability* ability,
89 const std::shared_ptr<AbilityRuntime::Context>& context, ResMgrDataContext &asyncContext)
90 {
91 std::shared_ptr<ResourceManager> resMgr;
92 if (ability != nullptr) {
93 if (bundleName.empty()) {
94 resMgr = ability->GetResourceManager();
95 } else {
96 std::shared_ptr<Context> bundleContext = ability->CreateBundleContext(bundleName, 0);
97 if (bundleContext != nullptr) {
98 resMgr = bundleContext->GetResourceManager();
99 }
100 }
101 } else if (context != nullptr) {
102 if (bundleName.empty()) {
103 resMgr = context->GetResourceManager();
104 } else {
105 std::shared_ptr<OHOS::AbilityRuntime::Context> bundleContext = context->CreateBundleContext(bundleName);
106 if (bundleContext != nullptr) {
107 resMgr = bundleContext->GetResourceManager();
108 }
109 }
110 }
111 asyncContext.resMgr_ = resMgr;
112 asyncContext.bundleName_ = bundleName;
113 return resMgr != nullptr;
114 }
115
getResult(napi_env env,std::unique_ptr<ResMgrDataContext> & asyncContext,std::string & bundleName,const std::shared_ptr<AbilityRuntime::Context> & abilityRuntimeContext)116 static napi_value getResult(napi_env env, std::unique_ptr<ResMgrDataContext> &asyncContext,
117 std::string &bundleName, const std::shared_ptr<AbilityRuntime::Context> &abilityRuntimeContext)
118 {
119 napi_value result = nullptr;
120 if (asyncContext->callbackRef_ == nullptr) {
121 napi_create_promise(env, &asyncContext->deferred_, &result);
122 } else {
123 napi_get_undefined(env, &result);
124 }
125
126 if (!InitAsyncContext(env, bundleName, GetGlobalAbility(env), abilityRuntimeContext, *asyncContext)) {
127 RESMGR_HILOGE(RESMGR_JS_TAG, "init async context failed");
128 ReportInitResourceManagerFail(bundleName, "failed to init async context");
129 return nullptr;
130 }
131
132 napi_value resource = nullptr;
133 napi_create_string_utf8(env, "getResourceManager", NAPI_AUTO_LENGTH, &resource);
134 napi_status status = napi_create_async_work(env, nullptr, resource, ExecuteGetResMgr,
135 ResourceManagerNapiAsyncImpl::Complete, static_cast<void*>(asyncContext.get()), &asyncContext->work_);
136 if (status != napi_ok) {
137 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to create async work for getResourceManager %{public}d", status);
138 return result;
139 }
140 status = napi_queue_async_work_with_qos(env, asyncContext->work_, napi_qos_user_initiated);
141 if (status != napi_ok) {
142 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to queue async work for getResourceManager %{public}d", status);
143 return result;
144 }
145 asyncContext.release();
146 return result;
147 }
148
GetResourceManager(napi_env env,napi_callback_info info)149 static napi_value GetResourceManager(napi_env env, napi_callback_info info)
150 {
151 GET_PARAMS(env, info, 3);
152
153 std::unique_ptr<ResMgrDataContext> asyncContext = std::make_unique<ResMgrDataContext>();
154 std::shared_ptr<AbilityRuntime::Context> abilityRuntimeContext;
155 std::string bundleName;
156 for (size_t i = 0; i < argc; i++) {
157 napi_valuetype valueType;
158 napi_typeof(env, argv[i], &valueType);
159 if (i == 0 && valueType == napi_object) {
160 using WeakContextPtr = std::weak_ptr<AbilityRuntime::Context> *;
161 WeakContextPtr objContext;
162 napi_status status = napi_unwrap(env, argv[0], reinterpret_cast<void **>(&objContext));
163 if (status != napi_ok || objContext == nullptr) {
164 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get objContext");
165 return nullptr;
166 }
167 auto context = objContext->lock();
168 if (context == nullptr) {
169 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get context");
170 return nullptr;
171 }
172 abilityRuntimeContext = context;
173 } else if ((i == 0 || i == 1) && valueType == napi_string) {
174 size_t len = 0;
175 napi_status status = napi_get_value_string_utf8(env, argv[i], nullptr, 0, &len);
176 if (status != napi_ok) {
177 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get bundle name length");
178 return nullptr;
179 }
180 std::vector<char> buf(len + 1);
181 status = napi_get_value_string_utf8(env, argv[i], buf.data(), len + 1, &len);
182 if (status != napi_ok) {
183 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get bundle name");
184 return nullptr;
185 }
186 bundleName = buf.data();
187 } else if ((i == 0 || i == 1 || i == 2) && valueType == napi_function) { // 2 means the third parameter
188 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef_);
189 break;
190 } else {
191 // self resourcemanager with promise
192 }
193 }
194
195 napi_value result = getResult(env, asyncContext, bundleName, abilityRuntimeContext);
196 return result;
197 }
198 #endif
199
GetSystemResourceManager(napi_env env,napi_callback_info info)200 static napi_value GetSystemResourceManager(napi_env env, napi_callback_info info)
201 {
202 return ResourceManagerAddon::GetSystemResMgr(env);
203 }
204
GetSysResourceManager(napi_env env,napi_callback_info info)205 static napi_value GetSysResourceManager(napi_env env, napi_callback_info info)
206 {
207 return ResourceManagerAddon::GetSysResourceManager(env);
208 }
209
SetEnumItem(napi_env env,napi_value object,const char * name,int32_t value)210 static napi_status SetEnumItem(napi_env env, napi_value object, const char* name, int32_t value)
211 {
212 napi_status status;
213 napi_value itemName;
214 napi_value itemValue;
215
216 NAPI_CALL_BASE(env, status = napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &itemName), status);
217 NAPI_CALL_BASE(env, status = napi_create_int32(env, value, &itemValue), status);
218
219 NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemName, itemValue), status);
220 NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemValue, itemName), status);
221
222 return napi_ok;
223 }
224
InitDirectionObject(napi_env env)225 static napi_value InitDirectionObject(napi_env env)
226 {
227 napi_value object;
228 NAPI_CALL(env, napi_create_object(env, &object));
229
230 NAPI_CALL(env, SetEnumItem(env, object, "DIRECTION_VERTICAL", DIRECTION_VERTICAL));
231 NAPI_CALL(env, SetEnumItem(env, object, "DIRECTION_HORIZONTAL", DIRECTION_HORIZONTAL));
232 return object;
233 }
234
InitDeviceTypeObject(napi_env env)235 static napi_value InitDeviceTypeObject(napi_env env)
236 {
237 napi_value object;
238 NAPI_CALL(env, napi_create_object(env, &object));
239
240 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_PHONE", DEVICE_PHONE));
241 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_TABLET", DEVICE_TABLET));
242 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_CAR", DEVICE_CAR));
243 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_PC", DEVICE_PAD));
244 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_TV", DEVICE_TV));
245 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_WEARABLE", DEVICE_WEARABLE));
246 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_2IN1", DEVICE_TWOINONE));
247 return object;
248 }
249
InitScreenDensityObject(napi_env env)250 static napi_value InitScreenDensityObject(napi_env env)
251 {
252 napi_value object;
253 NAPI_CALL(env, napi_create_object(env, &object));
254
255 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_SDPI", SCREEN_DENSITY_SDPI));
256 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_MDPI", SCREEN_DENSITY_MDPI));
257 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_LDPI", SCREEN_DENSITY_LDPI));
258 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_XLDPI", SCREEN_DENSITY_XLDPI));
259 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_XXLDPI", SCREEN_DENSITY_XXLDPI));
260 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_XXXLDPI", SCREEN_DENSITY_XXXLDPI));
261 return object;
262 }
263
InitColorModeObject(napi_env env)264 static napi_value InitColorModeObject(napi_env env)
265 {
266 napi_value object;
267 NAPI_CALL(env, napi_create_object(env, &object));
268
269 NAPI_CALL(env, SetEnumItem(env, object, "DARK", DARK));
270 NAPI_CALL(env, SetEnumItem(env, object, "LIGHT", LIGHT));
271 return object;
272 }
273
ResMgrInit(napi_env env,napi_value exports)274 static napi_value ResMgrInit(napi_env env, napi_value exports)
275 {
276 #if !defined(__IDE_PREVIEW__)
277 StartTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_GLOBAL_RESMGR, "GetResourceManager");
278 napi_property_descriptor creatorProp[] = {
279 DECLARE_NAPI_FUNCTION("getResourceManager", GetResourceManager),
280 DECLARE_NAPI_FUNCTION("getSystemResourceManager", GetSystemResourceManager),
281 DECLARE_NAPI_FUNCTION("getSysResourceManager", GetSysResourceManager),
282 };
283 #else
284 napi_property_descriptor creatorProp[] = {
285 DECLARE_NAPI_FUNCTION("getSystemResourceManager", GetSystemResourceManager),
286 DECLARE_NAPI_FUNCTION("getSysResourceManager", GetSysResourceManager),
287 };
288 #endif
289 napi_status status = napi_define_properties(env, exports, sizeof(creatorProp) / sizeof(creatorProp[0]),
290 creatorProp);
291 #if !defined(__IDE_PREVIEW__)
292 FinishTraceEx(HITRACE_LEVEL_INFO, HITRACE_TAG_GLOBAL_RESMGR);
293 #endif
294 if (status != napi_ok) {
295 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to set getResourceManager at init");
296 return nullptr;
297 }
298
299 napi_property_descriptor static_prop[] = {
300 DECLARE_NAPI_PROPERTY("Direction", InitDirectionObject(env)),
301 DECLARE_NAPI_PROPERTY("DeviceType", InitDeviceTypeObject(env)),
302 DECLARE_NAPI_PROPERTY("ScreenDensity", InitScreenDensityObject(env)),
303 DECLARE_NAPI_PROPERTY("ColorMode", InitColorModeObject(env)),
304 };
305
306 status = napi_define_properties(env, exports, sizeof(static_prop) / sizeof(static_prop[0]), static_prop);
307 if (status != napi_ok) {
308 RESMGR_HILOGE(RESMGR_JS_TAG, "failed to define properties for exports");
309 return nullptr;
310 }
311
312 return exports;
313 }
314
315 static napi_module g_resourceManagerModule = {
316 .nm_version = 1,
317 .nm_flags = 0,
318 .nm_filename = nullptr,
319 .nm_register_func = ResMgrInit,
320 .nm_modname = "resourceManager",
321 .nm_priv = ((void*)0),
322 .reserved = {0}
323 };
324
ResMgrRegister()325 extern "C" __attribute__((constructor)) void ResMgrRegister()
326 {
327 napi_module_register(&g_resourceManagerModule);
328 }
329 } // namespace Resource
330 } // namespace Global
331 } // namespace OHOS