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 #include "resource_manager_addon.h"
17
18 #include "ability.h"
19 #include "foundation/ability/ability_runtime/interfaces/kits/native/appkit/ability_runtime/context/context.h"
20 #include "hilog/log.h"
21 #include "hisysevent_adapter.h"
22 #include "hitrace_meter.h"
23 #include "js_runtime_utils.h"
24
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 #define GET_PARAMS(env, info, num) \
34 size_t argc = num; \
35 napi_value argv[num] = {nullptr}; \
36 napi_value thisVar = nullptr; \
37 void *data = nullptr; \
38 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
39
40 using namespace OHOS::AppExecFwk;
41
ExecuteGetResMgr(napi_env env,void * data)42 static void ExecuteGetResMgr(napi_env env, void* data)
43 {
44 if (data == nullptr) {
45 return;
46 }
47 ResMgrDataContext *asyncContext = static_cast<ResMgrDataContext*>(data);
48
49 asyncContext->createValueFunc_ = [](napi_env env, ResMgrDataContext &context) -> napi_value {
50 std::string traceVal = "Create ResourceManager";
51 StartTrace(HITRACE_TAG_GLOBAL_RESMGR, traceVal);
52 napi_value result = ResourceManagerAddon::Create(env, context.bundleName_, context.resMgr_, nullptr);
53 FinishTrace(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
GetSystemResourceManager(napi_env env,napi_callback_info info)199 static napi_value GetSystemResourceManager(napi_env env, napi_callback_info info)
200 {
201 return ResourceManagerAddon::GetSystemResMgr(env);
202 }
203
SetEnumItem(napi_env env,napi_value object,const char * name,int32_t value)204 static napi_status SetEnumItem(napi_env env, napi_value object, const char* name, int32_t value)
205 {
206 napi_status status;
207 napi_value itemName;
208 napi_value itemValue;
209
210 NAPI_CALL_BASE(env, status = napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &itemName), status);
211 NAPI_CALL_BASE(env, status = napi_create_int32(env, value, &itemValue), status);
212
213 NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemName, itemValue), status);
214 NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemValue, itemName), status);
215
216 return napi_ok;
217 }
218
InitDirectionObject(napi_env env)219 static napi_value InitDirectionObject(napi_env env)
220 {
221 napi_value object;
222 NAPI_CALL(env, napi_create_object(env, &object));
223
224 NAPI_CALL(env, SetEnumItem(env, object, "DIRECTION_VERTICAL", DIRECTION_VERTICAL));
225 NAPI_CALL(env, SetEnumItem(env, object, "DIRECTION_HORIZONTAL", DIRECTION_HORIZONTAL));
226 return object;
227 }
228
InitDeviceTypeObject(napi_env env)229 static napi_value InitDeviceTypeObject(napi_env env)
230 {
231 napi_value object;
232 NAPI_CALL(env, napi_create_object(env, &object));
233
234 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_PHONE", DEVICE_PHONE));
235 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_TABLET", DEVICE_TABLET));
236 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_CAR", DEVICE_CAR));
237 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_PC", DEVICE_PAD));
238 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_TV", DEVICE_TV));
239 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_WEARABLE", DEVICE_WEARABLE));
240 NAPI_CALL(env, SetEnumItem(env, object, "DEVICE_TYPE_2IN1", DEVICE_TWOINONE));
241 return object;
242 }
243
InitScreenDensityObject(napi_env env)244 static napi_value InitScreenDensityObject(napi_env env)
245 {
246 napi_value object;
247 NAPI_CALL(env, napi_create_object(env, &object));
248
249 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_SDPI", SCREEN_DENSITY_SDPI));
250 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_MDPI", SCREEN_DENSITY_MDPI));
251 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_LDPI", SCREEN_DENSITY_LDPI));
252 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_XLDPI", SCREEN_DENSITY_XLDPI));
253 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_XXLDPI", SCREEN_DENSITY_XXLDPI));
254 NAPI_CALL(env, SetEnumItem(env, object, "SCREEN_XXXLDPI", SCREEN_DENSITY_XXXLDPI));
255 return object;
256 }
257
InitColorModeObject(napi_env env)258 static napi_value InitColorModeObject(napi_env env)
259 {
260 napi_value object;
261 NAPI_CALL(env, napi_create_object(env, &object));
262
263 NAPI_CALL(env, SetEnumItem(env, object, "DARK", DARK));
264 NAPI_CALL(env, SetEnumItem(env, object, "LIGHT", LIGHT));
265 return object;
266 }
267
ResMgrInit(napi_env env,napi_value exports)268 static napi_value ResMgrInit(napi_env env, napi_value exports)
269 {
270 std::string traceVal = "GetResourceManager";
271 StartTrace(HITRACE_TAG_GLOBAL_RESMGR, traceVal);
272 napi_property_descriptor creatorProp[] = {
273 DECLARE_NAPI_FUNCTION("getResourceManager", GetResourceManager),
274 DECLARE_NAPI_FUNCTION("getSystemResourceManager", GetSystemResourceManager),
275 };
276 napi_status status = napi_define_properties(env, exports, sizeof(creatorProp) / sizeof(creatorProp[0]),
277 creatorProp);
278 FinishTrace(HITRACE_TAG_GLOBAL_RESMGR);
279 if (status != napi_ok) {
280 RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to set getResourceManager at init");
281 return nullptr;
282 }
283
284 napi_property_descriptor static_prop[] = {
285 DECLARE_NAPI_PROPERTY("Direction", InitDirectionObject(env)),
286 DECLARE_NAPI_PROPERTY("DeviceType", InitDeviceTypeObject(env)),
287 DECLARE_NAPI_PROPERTY("ScreenDensity", InitScreenDensityObject(env)),
288 DECLARE_NAPI_PROPERTY("ColorMode", InitColorModeObject(env)),
289 };
290
291 status = napi_define_properties(env, exports, sizeof(static_prop) / sizeof(static_prop[0]), static_prop);
292 if (status != napi_ok) {
293 RESMGR_HILOGE(RESMGR_JS_TAG, "failed to define properties for exports");
294 return nullptr;
295 }
296
297 return exports;
298 }
299
300 static napi_module g_resourceManagerModule = {
301 .nm_version = 1,
302 .nm_flags = 0,
303 .nm_filename = nullptr,
304 .nm_register_func = ResMgrInit,
305 .nm_modname = "resourceManager",
306 .nm_priv = ((void*)0),
307 .reserved = {0}
308 };
309
ResMgrRegister()310 extern "C" __attribute__((constructor)) void ResMgrRegister()
311 {
312 napi_module_register(&g_resourceManagerModule);
313 }
314 } // namespace Resource
315 } // namespace Global
316 } // namespace OHOS