1 /*
2 * Copyright (c) 2021-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 "battery_stats.h"
17
18 #include <cstdio>
19 #include <cstdlib>
20 #include <string>
21 #include <vector>
22
23 #include "napi/native_api.h"
24
25 #include "battery_stats_client.h"
26 #include "stats_hilog_wrapper.h"
27
28 using namespace OHOS::PowerMgr;
29
SetValueInt32(const napi_env & env,std::string fieldStr,const int intValue,napi_value & result)30 static void SetValueInt32(const napi_env& env, std::string fieldStr, const int intValue, napi_value& result)
31 {
32 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
33 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Set int32_t value: %{public}d", intValue);
34 napi_value value;
35 napi_create_int32(env, intValue, &value);
36 napi_set_named_property(env, result, fieldStr.c_str(), value);
37 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
38 }
39
SetValueDouble(const napi_env & env,std::string fieldStr,const double doubleValue,napi_value & result)40 static void SetValueDouble(const napi_env& env, std::string fieldStr, const double doubleValue, napi_value& result)
41 {
42 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
43 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Set double value: %{public}lf", doubleValue);
44 napi_value value;
45 napi_create_double(env, doubleValue, &value);
46 napi_set_named_property(env, result, fieldStr.c_str(), value);
47 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
48 }
49
StatsInfoToJsArray(const napi_env & env,const std::vector<BatteryStats> & vecJsStatsInfo,const int idx,napi_value & arrayResult)50 static void StatsInfoToJsArray(const napi_env& env, const std::vector<BatteryStats>& vecJsStatsInfo,
51 const int idx, napi_value& arrayResult)
52 {
53 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
54 napi_value result;
55 napi_create_object(env, &result);
56
57 SetValueInt32(env, "uid", vecJsStatsInfo[idx].uid_, result);
58 SetValueInt32(env, "type", vecJsStatsInfo[idx].type_, result);
59 SetValueDouble(env, "power", vecJsStatsInfo[idx].power_, result);
60
61 napi_status status = napi_set_element(env, arrayResult, idx, result);
62 if (status != napi_ok) {
63 STATS_HILOGE(STATS_MODULE_JS_NAPI, "BatteryStats js napi set element error: %{public}d", status);
64 }
65 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
66 }
67
NativeCppStatsInfoToJsStatsInfo(const BatteryStatsInfoList & vecCppStatsInfos,std::vector<BatteryStats> & vecJsStatsInfo)68 static void NativeCppStatsInfoToJsStatsInfo(const BatteryStatsInfoList& vecCppStatsInfos,
69 std::vector<BatteryStats>& vecJsStatsInfo)
70 {
71 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
72 for (auto& e : vecCppStatsInfos) {
73 BatteryStats jsStatsInfo;
74
75 jsStatsInfo.uid_ = e->GetUid();
76 jsStatsInfo.type_ = e->GetConsumptionType();
77 jsStatsInfo.power_ = e->GetPower();
78 vecJsStatsInfo.push_back(jsStatsInfo);
79 }
80 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
81 }
82
GetBatteryStatsInfoList(std::vector<BatteryStats> & vecStatsInfo)83 static bool GetBatteryStatsInfoList(std::vector<BatteryStats>& vecStatsInfo)
84 {
85 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
86 BatteryStatsInfoList vecCppStatsInfos = BatteryStatsClient::GetInstance().GetBatteryStats();
87 if (vecCppStatsInfos.size() <= 0) {
88 STATS_HILOGE(STATS_MODULE_JS_NAPI, "Get Stats info failed");
89 return false;
90 }
91
92 STATS_HILOGD(STATS_MODULE_JS_NAPI, "StatsInfoList size: %{public}d", (int)vecCppStatsInfos.size());
93 NativeCppStatsInfoToJsStatsInfo(vecCppStatsInfos, vecStatsInfo);
94 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
95 return true;
96 }
97
BatteryStatsToNapiValue(napi_env env,std::vector<BatteryStats> & vecStatsInfo,napi_value & result)98 static void BatteryStatsToNapiValue(napi_env env, std::vector<BatteryStats>& vecStatsInfo, napi_value& result)
99 {
100 napi_status status = napi_create_array_with_length(env, vecStatsInfo.size(), &result);
101 if (status != napi_ok) {
102 STATS_HILOGE(STATS_MODULE_JS_NAPI, "BatteryStats napi_create_array_with_length error: %{public}d", status);
103 return;
104 }
105 for (size_t i = 0; i < vecStatsInfo.size(); ++i) {
106 StatsInfoToJsArray(env, vecStatsInfo, i, result);
107 }
108 }
109
StatsInfoToPromise(const napi_env & env,AsyncCallbackInfo * asCallbackInfo,napi_value & promise)110 static napi_value StatsInfoToPromise(const napi_env& env, AsyncCallbackInfo *asCallbackInfo, napi_value& promise)
111 {
112 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
113 napi_value resourceName;
114 napi_create_string_latin1(env, "getBatteryStats", NAPI_AUTO_LENGTH, &resourceName);
115
116 napi_deferred deferred;
117 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
118 asCallbackInfo->deferred = deferred;
119
120 napi_create_async_work(
121 env,
122 nullptr,
123 resourceName,
124 [](napi_env env, void *data) {
125 AsyncCallbackInfo *asCallbackInfo = (AsyncCallbackInfo *)data;
126 GetBatteryStatsInfoList(asCallbackInfo->vecStatsInfo);
127 },
128 [](napi_env env, napi_status status, void *data) {
129 AsyncCallbackInfo *asCallbackInfo = (AsyncCallbackInfo *)data;
130 napi_value result = nullptr;
131 if (!asCallbackInfo->vecStatsInfo.empty()) {
132 BatteryStatsToNapiValue(env, asCallbackInfo->vecStatsInfo, result);
133 napi_resolve_deferred(env, asCallbackInfo->deferred, result);
134 } else {
135 napi_reject_deferred(env, asCallbackInfo->deferred, result);
136 }
137 napi_delete_async_work(env, asCallbackInfo->asyncWork);
138 delete asCallbackInfo;
139 },
140 (void *)asCallbackInfo,
141 &asCallbackInfo->asyncWork);
142 napi_queue_async_work(env, asCallbackInfo->asyncWork);
143 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
144 return NULL;
145 }
146
StatsInfoToCallBack(const napi_env & env,AsyncCallbackInfo * asCallbackInfo,const size_t argc,const napi_value * argv)147 static napi_value StatsInfoToCallBack(const napi_env& env, AsyncCallbackInfo *asCallbackInfo,
148 const size_t argc, const napi_value *argv)
149 {
150 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
151 napi_value resourceName;
152 napi_create_string_latin1(env, "getBatteryStats", NAPI_AUTO_LENGTH, &resourceName);
153
154 for (size_t i = 0; i != argc; ++i) {
155 napi_valuetype valuetype;
156 NAPI_CALL(env, napi_typeof(env, argv[i], &valuetype));
157 NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Function expected.");
158 napi_create_reference(env, argv[i], 1, &asCallbackInfo->callback[i]);
159 }
160
161 napi_create_async_work(
162 env, nullptr, resourceName,
163 [](napi_env env, void* data) {
164 AsyncCallbackInfo *asCallbackInfo = (AsyncCallbackInfo *)data;
165 GetBatteryStatsInfoList(asCallbackInfo->vecStatsInfo);
166 },
167 [](napi_env env, napi_status status, void* data) {
168 AsyncCallbackInfo* asCallbackInfo = (AsyncCallbackInfo *)data;
169 napi_value undefine;
170 napi_get_undefined(env, &undefine);
171 napi_value callback;
172 napi_value result = nullptr;
173 if (!asCallbackInfo->vecStatsInfo.empty()) {
174 BatteryStatsToNapiValue(env, asCallbackInfo->vecStatsInfo, result);
175 napi_get_reference_value(env, asCallbackInfo->callback[0], &callback);
176 napi_call_function(env, nullptr, callback, 1, &result, &undefine);
177 } else {
178 if (asCallbackInfo->callback[1]) {
179 napi_get_reference_value(env, asCallbackInfo->callback[1], &callback);
180 napi_call_function(env, nullptr, callback, 1, &result, &undefine);
181 } else {
182 STATS_HILOGE(STATS_MODULE_JS_NAPI, "StatsInfoList callback func is null");
183 napi_throw_error(env, "error", "StatsInfoList callback func is null");
184 }
185 }
186
187 if (asCallbackInfo->callback[0] != nullptr) {
188 napi_delete_reference(env, asCallbackInfo->callback[0]);
189 }
190 if (asCallbackInfo->callback[1] != nullptr) {
191 napi_delete_reference(env, asCallbackInfo->callback[1]);
192 }
193 napi_delete_async_work(env, asCallbackInfo->asyncWork);
194 delete asCallbackInfo;
195 },
196 (void *)asCallbackInfo,
197 &asCallbackInfo->asyncWork);
198 NAPI_CALL(env, napi_queue_async_work(env, asCallbackInfo->asyncWork));
199 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
200 return NULL;
201 }
202
GetBatteryStats(napi_env env,napi_callback_info info)203 static napi_value GetBatteryStats(napi_env env, napi_callback_info info)
204 {
205 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
206 size_t argc = 2;
207 napi_value argv[argc];
208 napi_value thisVar = nullptr;
209 void *data = nullptr;
210 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data));
211
212 AsyncCallbackInfo *asCallbackInfo =
213 new AsyncCallbackInfo {.asyncWork = nullptr, .deferred = nullptr};
214
215 if (argc >= 1) {
216 StatsInfoToCallBack(env, asCallbackInfo, argc, argv);
217 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit_callback");
218 return NULL;
219 } else {
220 napi_value promise;
221 StatsInfoToPromise(env, asCallbackInfo, promise);
222 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit_promise");
223 return promise;
224 }
225 }
226
GetAppStatsMah(napi_env env,napi_callback_info info)227 static napi_value GetAppStatsMah(napi_env env, napi_callback_info info)
228 {
229 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
230 size_t argc = 1;
231 napi_value argv[1];
232 napi_value thisVar;
233 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
234 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
235
236 napi_valuetype type1;
237 napi_typeof(env, argv[0], &type1);
238 NAPI_ASSERT(env, type1 == napi_number, "Wrong argument type. napi_number expected.");
239
240 int32_t uid;
241 napi_get_value_int32(env, argv[0], &uid);
242
243 double appStatsMah = BatteryStatsClient::GetInstance().GetAppStatsMah(uid);
244
245 napi_value result;
246 napi_create_double(env, appStatsMah, &result);
247 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Got stats mah: %{public}lf for uid: %{public}d", appStatsMah, uid);
248 return result;
249 }
250
GetAppStatsPercent(napi_env env,napi_callback_info info)251 static napi_value GetAppStatsPercent(napi_env env, napi_callback_info info)
252 {
253 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
254 size_t argc = 1;
255 napi_value argv[1];
256 napi_value thisVar;
257 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
258 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
259
260 napi_valuetype type1;
261 napi_typeof(env, argv[0], &type1);
262 NAPI_ASSERT(env, type1 == napi_number, "Wrong argument type. napi_number expected.");
263
264 int32_t uid;
265 napi_get_value_int32(env, argv[0], &uid);
266
267 double appStatsPercent = BatteryStatsClient::GetInstance().GetAppStatsPercent(uid);
268
269 napi_value result;
270 napi_create_double(env, appStatsPercent, &result);
271 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Got stats percent: %{public}lf for uid: %{public}d", appStatsPercent, uid);
272 return result;
273 }
274
GetPartStatsMah(napi_env env,napi_callback_info info)275 static napi_value GetPartStatsMah(napi_env env, napi_callback_info info)
276 {
277 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
278 size_t argc = 1;
279 napi_value argv[1];
280 napi_value thisVar;
281 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
282 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
283
284 napi_valuetype type1;
285 napi_typeof(env, argv[0], &type1);
286 NAPI_ASSERT(env, type1 == napi_number, "Wrong argument type. napi_number expected.");
287
288 int32_t typeJs;
289 napi_get_value_int32(env, argv[0], &typeJs);
290
291 BatteryStatsInfo::ConsumptionType type = BatteryStatsInfo::ConsumptionType(typeJs);
292 double partStatsMah = BatteryStatsClient::GetInstance().GetPartStatsMah(type);
293
294 napi_value result;
295 napi_create_double(env, partStatsMah, &result);
296 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Got stats mah: %{public}lf for type: %{public}d", partStatsMah, type);
297 return result;
298 }
299
GetPartStatsPercent(napi_env env,napi_callback_info info)300 static napi_value GetPartStatsPercent(napi_env env, napi_callback_info info)
301 {
302 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
303 size_t argc = 1;
304 napi_value argv[1];
305 napi_value thisVar;
306 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
307 NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
308
309 napi_valuetype type1;
310 napi_typeof(env, argv[0], &type1);
311 NAPI_ASSERT(env, type1 == napi_number, "Wrong argument type. napi_number expected.");
312
313 int32_t typeJs;
314 napi_get_value_int32(env, argv[0], &typeJs);
315
316 BatteryStatsInfo::ConsumptionType type = BatteryStatsInfo::ConsumptionType(typeJs);
317 double partStatsPercent = BatteryStatsClient::GetInstance().GetPartStatsPercent(type);
318
319 napi_value result;
320 napi_create_double(env, partStatsPercent, &result);
321 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Got stats percent: %{public}lf for type: %{public}d", partStatsPercent, type);
322 return result;
323 }
324
EnumStatsTypeConstructor(napi_env env,napi_callback_info info)325 static napi_value EnumStatsTypeConstructor(napi_env env, napi_callback_info info)
326 {
327 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
328 napi_value thisArg = nullptr;
329 void *data = nullptr;
330 napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
331 napi_value global = nullptr;
332 napi_get_global(env, &global);
333 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
334 return thisArg;
335 }
336
CreateEnumStatsType(napi_env env,napi_value exports)337 static napi_value CreateEnumStatsType(napi_env env, napi_value exports)
338 {
339 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
340 napi_value invalid = nullptr;
341 napi_value app = nullptr;
342 napi_value bluetooth = nullptr;
343 napi_value idle = nullptr;
344 napi_value phone = nullptr;
345 napi_value radio = nullptr;
346 napi_value screen = nullptr;
347 napi_value user = nullptr;
348 napi_value wifi = nullptr;
349
350 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_INVALID, &invalid);
351 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_APP, &app);
352 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_BLUETOOTH, &bluetooth);
353 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_IDLE, &idle);
354 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_PHONE, &phone);
355 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_RADIO, &radio);
356 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_SCREEN, &screen);
357 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_USER, &user);
358 napi_create_int32(env, (int32_t)BatteryStatsInfo::ConsumptionType::CONSUMPTION_TYPE_WIFI, &wifi);
359
360 napi_property_descriptor desc[] = {
361 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_INVALID", invalid),
362 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_APP", app),
363 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_BLUETOOTH", bluetooth),
364 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_IDLE", idle),
365 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_PHONE", phone),
366 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_RADIO", radio),
367 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_SCREEN", screen),
368 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_USER", user),
369 DECLARE_NAPI_STATIC_PROPERTY("CONSUMPTION_TYPE_WIFI", wifi),
370 };
371 napi_value result = nullptr;
372 napi_define_class(env, "ConsumptionType", NAPI_AUTO_LENGTH, EnumStatsTypeConstructor, nullptr,
373 sizeof(desc) / sizeof(*desc), desc, &result);
374
375 napi_set_named_property(env, exports, "ConsumptionType", result);
376 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
377 return exports;
378 }
379
380 EXTERN_C_START
381 /*
382 * function for module exports
383 */
BatteryStatsInit(napi_env env,napi_value exports)384 static napi_value BatteryStatsInit(napi_env env, napi_value exports)
385 {
386 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Enter");
387
388 napi_property_descriptor desc[] = {
389 DECLARE_NAPI_FUNCTION("getBatteryStats", GetBatteryStats),
390 DECLARE_NAPI_FUNCTION("getAppPowerValue", GetAppStatsMah),
391 DECLARE_NAPI_FUNCTION("getAppPowerPercent", GetAppStatsPercent),
392 DECLARE_NAPI_FUNCTION("getHardwareUnitPowerValue", GetPartStatsMah),
393 DECLARE_NAPI_FUNCTION("getHardwareUnitPowerPercent", GetPartStatsPercent),
394 };
395 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
396
397 CreateEnumStatsType(env, exports);
398 STATS_HILOGD(STATS_MODULE_JS_NAPI, "Exit");
399 return exports;
400 }
401 EXTERN_C_END
402
403 /*
404 * Module definition
405 */
406 static napi_module batteryStatsModule = {
407 .nm_version = 1,
408 .nm_flags = 0,
409 .nm_filename = "batteryStats",
410 .nm_register_func = BatteryStatsInit,
411 .nm_modname = "batteryStatistics",
412 .nm_priv = ((void *)0),
413 .reserved = {0}
414 };
415
416 /*
417 * Module registration
418 */
RegisterModule(void)419 extern "C" __attribute__((constructor)) void RegisterModule(void)
420 {
421 napi_module_register(&batteryStatsModule);
422 }
423