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