• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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