2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include "HeartDbReader.h"
24 #include "BatteryMonitor.h"
26 #define DEFAULT_ROW_ID_STR "1"
30 static int __bootingTime = 0;
31 static int __lastResetTime = 0;
32 static int __lastPercent = -1;
33 static int __lastPercentTime = 0;
34 static int __lastHeartTimestamp = 0;
35 static bool __isCharging = 0;
36 static std::vector<Json> __batteryTimeInfoVec;
37 static bool __timerRunning = false;
39 #define DB_QUERY_DELAY 600000
41 BatteryMonitor::BatteryMonitor()
46 BatteryMonitor::~BatteryMonitor()
50 void BatteryMonitor::__initialize()
52 std::vector<Json> records;
54 "CREATE TABLE IF NOT EXISTS " BATTERY_USAGE_TABLE \
55 " (" BATTERY_USAGE_TABLE_COLUMNS ")", &records);
58 "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_INFO_TABLE \
59 " (" BATTERY_LAST_INFO_TABLE_COLUMNS ")", &records);
62 "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_CPU_USAGE_TABLE \
63 " (" BATTERY_LAST_CPU_USAGE_TABLE_COLUMNS ")", &records);
65 __dbMgr.createTableSync(BATTERY_TEMP_TIME_INFO, BATTERY_TEMP_TIME_INFO_COLUMNS, NULL);
68 bool BatteryMonitor::__loadLastInfo()
70 __bootingTime = CURRENT_TIME;
72 device_battery_is_charging(&__isCharging);
74 std::vector<Json> records;
75 bool ret = __dbMgr.executeSync(
76 "SELECT * FROM " BATTERY_LAST_INFO_TABLE \
77 " WHERE " BATTERY_ROW_ID " = " DEFAULT_ROW_ID_STR, &records);
78 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last info");
80 if (records.size() == 1) {
81 records[0].get(NULL, BATTERY_LAST_RESET_TIME, &__lastResetTime);
82 records[0].get(NULL, BATTERY_LAST_PERCENT, &__lastPercent);
83 records[0].get(NULL, BATTERY_LAST_PERCENT_TIME, &__lastPercentTime);
84 records[0].get(NULL, BATTERY_LAST_HEART_TIMESTAMP, &__lastHeartTimestamp);
88 __batteryTimeInfoVec.clear();
89 ret = __dbMgr.executeSync("SELECT * FROM " BATTERY_TEMP_TIME_INFO , &__batteryTimeInfoVec);
91 ret = __dbMgr.executeSync("DELETE FROM " BATTERY_TEMP_TIME_INFO, &records);
96 bool BatteryMonitor::__updateLastInfo()
98 if (__batteryTimeInfoVec.size() > 0) {
99 for (unsigned int i = 0; i < __batteryTimeInfoVec.size(); i++) {
101 __dbMgr.insertSync(BATTERY_TEMP_TIME_INFO, __batteryTimeInfoVec.at(i), &rowId);
105 IF_FAIL_RETURN_TAG(__lastResetTime != 0 || __lastPercentTime != 0, false, _W, "Last info doesn't exist");
107 char *query = sqlite3_mprintf(
108 "INSERT OR REPLACE INTO " BATTERY_LAST_INFO_TABLE " (" \
109 BATTERY_ROW_ID ", " BATTERY_LAST_RESET_TIME ", " \
110 BATTERY_LAST_PERCENT ", " BATTERY_LAST_PERCENT_TIME ", " BATTERY_LAST_HEART_TIMESTAMP ") VALUES (%s, %d, %d, %d, %d)",
111 DEFAULT_ROW_ID_STR, __lastResetTime, __lastPercent, __lastPercentTime, __lastHeartTimestamp);
113 std::vector<Json> records;
114 bool ret = __dbMgr.executeSync(query, &records);
116 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update battery stat last info");
121 void BatteryMonitor::__batteryChangeCb(device_callback_e type, void* value, void* userData)
123 IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CAPACITY);
125 int percent = intptr_t(value);
126 int currentTime = CURRENT_TIME;
127 BatteryMonitor* instance = static_cast<BatteryMonitor*>(userData);
129 if (!__isCharging && percent == (__lastPercent - 1) && __lastPercentTime != 0) {
130 _D("Battery capacity decreased: %d% -> %d%", __lastPercent, percent);
133 battTimeInfo.set(NULL, BATTERY_AMOUNT, percent);
134 battTimeInfo.set(NULL, BATTERY_START_TIME, __lastPercentTime);
135 battTimeInfo.set(NULL, BATTERY_END_TIME, currentTime);
136 __batteryTimeInfoVec.push_back(battTimeInfo);
138 bool dataRemaining = instance->processBatteryUsage();
139 if (dataRemaining && !__timerRunning) {
140 __timerRunning = true;
141 _D("Start timer to request HEART data");
142 g_timeout_add(DB_QUERY_DELAY, __timeoutCb, instance);
146 __lastPercentTime = currentTime;
147 __lastPercent = percent;
150 void BatteryMonitor::__chargerChangeCb(device_callback_e type, void* value, void* userData)
152 IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CHARGING);
154 __isCharging = intptr_t(value);
155 IF_FAIL_VOID(!__isCharging);
158 if (__lastPercent < 0) {
159 int error = device_battery_get_percent(&percent);
160 IF_FAIL_VOID_TAG(error == DEVICE_ERROR_NONE, _E, "Failed to get battery capacity");
162 percent = __lastPercent;
165 // If charger is disconnected after 100% charged
166 if (percent == 100) {
167 __lastResetTime = CURRENT_TIME;
168 __lastPercentTime = __lastResetTime;
169 _D("Charger is disconnected after fully charged. ResetTime: %d", __lastResetTime);
173 gboolean BatteryMonitor::__timeoutCb(gpointer data) {
174 BatteryMonitor* instance = static_cast<BatteryMonitor*>(data);
176 bool dataRemaining = instance->processBatteryUsage();
177 if (!dataRemaining) {
178 _D("Stop timer, no more data to process");
179 __timerRunning = false;
182 return dataRemaining ? TRUE : FALSE;
185 int BatteryMonitor::start()
189 int error = device_add_callback(DEVICE_CALLBACK_BATTERY_CAPACITY, __batteryChangeCb, this);
190 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to set battery capacity change cb");
192 error = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb, NULL);
193 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to set battery charging change cb");
195 __timerRunning = true;
196 _D("Start timer to request HEAERT data");
197 g_timeout_add(DB_QUERY_DELAY, __timeoutCb, this);
201 int BatteryMonitor::stop()
205 int error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CAPACITY, __batteryChangeCb);
206 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to remove callback for battery capacity");
208 error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb);
209 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to remove callback for charger status");
214 bool BatteryMonitor::__getLastCpuUsageTable(CpuUsageMap* lastCpuUsage)
216 std::vector<Json> lastCpuUsageLog;
217 bool ret = __dbMgr.executeSync(
218 "SELECT * FROM " BATTERY_LAST_CPU_USAGE_TABLE,
220 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last Cpu Times of Apps");
228 while (k < lastCpuUsageLog.size()) {
229 lastCpuUsageLog[k].get(NULL, BATTERY_APP_ID, &appId);
230 lastCpuUsageLog[k].get(NULL, BATTERY_TIMESTAMP, ×tamp);
231 lastCpuUsageLog[k].get(NULL, BATTERY_UTIME, &utime);
232 lastCpuUsageLog[k].get(NULL, BATTERY_STIME, &stime);
235 LastAppCpuUsageInfo lastAppCpuUsage;
236 lastAppCpuUsage.timestamp = timestamp;
237 lastAppCpuUsage.utime = utime;
238 lastAppCpuUsage.stime = stime;
239 (*lastCpuUsage)[appId] = lastAppCpuUsage;
244 //Return false if all is processed, true otherwise
245 bool BatteryMonitor::processBatteryUsage()
247 IF_FAIL_RETURN_TAG(__batteryTimeInfoVec.size() > 0, false, _D, "All per-app battery usages are already calculated");
251 __batteryTimeInfoVec.front().get(NULL, BATTERY_START_TIME, &totalStartTime);
252 __batteryTimeInfoVec.back().get(NULL, BATTERY_END_TIME, &totalEndTime);
254 // Read cpu table from heart db for time span of stacked in __batteryTimeInfoVec
255 HeartDbReader heartReader;
256 bool ret = heartReader.open();
257 IF_FAIL_RETURN_TAG(ret, true, _E, "Failed to open heart db");
259 std::vector<Json> cpuUsageLog;
260 ret = heartReader.readCpuUsageLog(totalStartTime, totalEndTime, &cpuUsageLog);
262 IF_FAIL_RETURN_TAG(ret, true, _E, "Cannot read from heart cpu table");
263 IF_FAIL_RETURN_TAG(cpuUsageLog.size() > 0, true, _W, "Heart cpu data is not prepared yet (%d ~ %d)", totalStartTime, totalEndTime);
264 _D("Read %d rows from heart cpu table from %d to %d", cpuUsageLog.size(), totalStartTime, totalEndTime);
266 // Get the last timestamp of HEART cpu data and maximum app times tables in cache
267 cpuUsageLog.back().get(NULL, BATTERY_TIMESTAMP, &__lastHeartTimestamp);
268 CpuUsageMap lastCpuUsage;
269 ret = __getLastCpuUsageTable(&lastCpuUsage);
272 for (i = 0; i < __batteryTimeInfoVec.size(); i++) {
276 Json row = __batteryTimeInfoVec[i].str();
277 row.get(NULL, BATTERY_START_TIME, &startTime);
278 row.get(NULL, BATTERY_END_TIME, &endTime);
280 if (endTime > __lastHeartTimestamp) {
281 _W("[%d] Heart cpu data is not prepared yet (%d ~ %d)", i, startTime, endTime);
285 // Calculate per app battery usage
286 std::vector<Json> usage;
287 ret = __analyzer.calculateBatteryUsage(startTime, endTime, cpuUsageLog, lastCpuUsage, &usage);
289 _E("[%d] Failed to calculate battery usage (%d ~ %d)", i, startTime, endTime);
292 _D("[%d] Battery usage per app calculated (%d ~ %d)", i, startTime, endTime);
294 // Insert battery usage
295 ret = __insertBatteryUsageLog(usage);
297 _E("Failed to insert per app battery usage");
301 // Insert log of last times of apps
303 ret = __insertLastCpuUsageLog(lastCpuUsage);
305 _E("Failed to insert last Cpu Usage of apps");
309 // Remove completed time info
310 _D("Total %d time intervals, %d intervals are calculated", __batteryTimeInfoVec.size(), i);
311 __batteryTimeInfoVec.erase(__batteryTimeInfoVec.begin(), __batteryTimeInfoVec.begin() + i);
313 if (__batteryTimeInfoVec.size() == 0) {
321 bool BatteryMonitor::__insertBatteryUsageLog(std::vector<Json>& usage)
323 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
324 std::string query("INSERT INTO " BATTERY_USAGE_TABLE \
325 "(" BATTERY_APP_ID ", " BATTERY_START_TIME ", " \
326 BATTERY_END_TIME ", " BATTERY_UTIME ", " \
327 BATTERY_STIME ", " BATTERY_AMOUNT ") VALUES");
335 for (unsigned int i = 0; i < usage.size(); i++) {
336 usage[i].get(NULL, BATTERY_APP_ID, &appId);
337 usage[i].get(NULL, BATTERY_START_TIME, &startTime);
338 usage[i].get(NULL, BATTERY_END_TIME, &endTime);
339 usage[i].get(NULL, BATTERY_UTIME, &utime);
340 usage[i].get(NULL, BATTERY_STIME, &stime);
341 usage[i].get(NULL, BATTERY_AMOUNT, &amount);
343 query += " ('" + appId + "', "
344 + std::to_string(startTime) + ", "
345 + std::to_string(endTime) + ", "
346 + std::to_string(utime) + ", "
347 + std::to_string(stime) + ", "
348 + std::to_string((int) (amount * 10000)) + ")";
352 query = query.substr(0, query.size() - 2);
354 _D("Insert %d rows of per app battery usage", usage.size());
355 return __dbMgr.executeSync(query.c_str(), NULL);
358 bool BatteryMonitor::__insertLastCpuUsageLog(CpuUsageMap& usage)
360 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
361 _D("Delete all rows from app last times table");
362 __dbMgr.executeSync("DELETE FROM " BATTERY_LAST_CPU_USAGE_TABLE, NULL);
364 std::string query("INSERT INTO " BATTERY_LAST_CPU_USAGE_TABLE "(" BATTERY_APP_ID ", " BATTERY_UTIME ", " BATTERY_STIME "," BATTERY_TIMESTAMP ") VALUES");
370 for (auto it = usage.begin(); it != usage.end(); it++) {
372 timestamp = (it->second).timestamp;
373 utime = (it->second).utime;
374 stime = (it->second).stime;
376 query += " ('" + appId
377 + "', " + std::to_string(utime)
378 + ", " + std::to_string(stime)
379 + ", " + std::to_string(timestamp) + ")";
384 _D("Insert %d rows in app last times table", usage.size());
385 query = query.substr(0, query.size() - 2);
386 return __dbMgr.executeSync(query.c_str(), NULL);
389 // Used for Recent Battery Usage
390 int BatteryMonitor::getLastResetTime()
392 if (__lastResetTime == 0) {
393 _I("Device has not fully charged until now. Start time of recent battery usage will be booting time");
394 return __bootingTime;
397 return __lastResetTime;