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;
39 BatteryMonitor::BatteryMonitor()
44 BatteryMonitor::~BatteryMonitor()
48 void BatteryMonitor::__initialize()
50 std::vector<Json> records;
52 "CREATE TABLE IF NOT EXISTS " BATTERY_USAGE_TABLE \
53 " (" BATTERY_USAGE_TABLE_COLUMNS ")", &records);
56 "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_INFO_TABLE \
57 " (" BATTERY_LAST_INFO_TABLE_COLUMNS ")", &records);
60 "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_CPU_USAGE_TABLE \
61 " (" BATTERY_LAST_CPU_USAGE_TABLE_COLUMNS ")", &records);
63 __dbMgr.createTableSync(BATTERY_TEMP_TIME_INFO, BATTERY_TEMP_TIME_INFO_COLUMNS, NULL);
66 bool BatteryMonitor::__loadLastInfo()
68 __bootingTime = CURRENT_TIME;
70 device_battery_is_charging(&__isCharging);
72 std::vector<Json> records;
73 bool ret = __dbMgr.executeSync(
74 "SELECT * FROM " BATTERY_LAST_INFO_TABLE \
75 " WHERE " BATTERY_ROW_ID " = " DEFAULT_ROW_ID_STR, &records);
76 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last info");
78 if (records.size() == 1) {
79 records[0].get(NULL, BATTERY_LAST_RESET_TIME, &__lastResetTime);
80 records[0].get(NULL, BATTERY_LAST_PERCENT, &__lastPercent);
81 records[0].get(NULL, BATTERY_LAST_PERCENT_TIME, &__lastPercentTime);
82 records[0].get(NULL, BATTERY_LAST_HEART_TIMESTAMP, &__lastHeartTimestamp);
86 __batteryTimeInfoVec.clear();
87 ret = __dbMgr.executeSync("SELECT * FROM " BATTERY_TEMP_TIME_INFO , &__batteryTimeInfoVec);
89 ret = __dbMgr.executeSync("DELETE FROM " BATTERY_TEMP_TIME_INFO, &records);
94 bool BatteryMonitor::__updateLastInfo()
96 if (__batteryTimeInfoVec.size() > 0) {
97 for (unsigned int i = 0; i < __batteryTimeInfoVec.size(); i++) {
99 __dbMgr.insertSync(BATTERY_TEMP_TIME_INFO, __batteryTimeInfoVec.at(i), &rowId);
103 IF_FAIL_RETURN_TAG(__lastResetTime != 0 || __lastPercentTime != 0, false, _W, "Last info doesn't exist");
105 char *query = sqlite3_mprintf(
106 "INSERT OR REPLACE INTO " BATTERY_LAST_INFO_TABLE " (" \
107 BATTERY_ROW_ID ", " BATTERY_LAST_RESET_TIME ", " \
108 BATTERY_LAST_PERCENT ", " BATTERY_LAST_PERCENT_TIME ", " BATTERY_LAST_HEART_TIMESTAMP ") VALUES (%s, %d, %d, %d, %d)",
109 DEFAULT_ROW_ID_STR, __lastResetTime, __lastPercent, __lastPercentTime, __lastHeartTimestamp);
111 std::vector<Json> records;
112 bool ret = __dbMgr.executeSync(query, &records);
114 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update battery stat last info");
119 void BatteryMonitor::__batteryChangeCb(device_callback_e type, void* value, void* userData)
121 IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CAPACITY);
123 int percent = intptr_t(value);
124 int currentTime = CURRENT_TIME;
125 BatteryMonitor* instance = static_cast<BatteryMonitor*>(userData);
127 if (!__isCharging && percent == (__lastPercent - 1) && __lastPercentTime != 0) {
128 _D("Battery capacity decreased: %d% -> %d%", __lastPercent, percent);
131 battTimeInfo.set(NULL, BATTERY_AMOUNT, percent);
132 battTimeInfo.set(NULL, BATTERY_START_TIME, __lastPercentTime);
133 battTimeInfo.set(NULL, BATTERY_END_TIME, currentTime);
134 __batteryTimeInfoVec.push_back(battTimeInfo);
136 instance->processBatteryUsage();
139 __lastPercentTime = currentTime;
140 __lastPercent = percent;
143 void BatteryMonitor::__chargerChangeCb(device_callback_e type, void* value, void* userData)
145 IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CHARGING);
147 __isCharging = intptr_t(value);
148 IF_FAIL_VOID(!__isCharging);
151 if (__lastPercent < 0) {
152 int error = device_battery_get_percent(&percent);
153 IF_FAIL_VOID_TAG(error == DEVICE_ERROR_NONE, _E, "Failed to get battery capacity");
155 percent = __lastPercent;
158 // If charger is disconnected after 100% charged
159 if (percent == 100) {
160 __lastResetTime = CURRENT_TIME;
161 __lastPercentTime = __lastResetTime;
162 _D("Charger is disconnected after fully charged. ResetTime: %d", __lastResetTime);
166 int BatteryMonitor::start()
170 int error = device_add_callback(DEVICE_CALLBACK_BATTERY_CAPACITY, __batteryChangeCb, this);
171 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to set battery capacity change cb");
173 error = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb, NULL);
174 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to set battery charging change cb");
179 int BatteryMonitor::stop()
183 int error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CAPACITY, __batteryChangeCb);
184 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to remove callback for battery capacity");
186 error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb);
187 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to remove callback for charger status");
192 bool BatteryMonitor::__getLastCpuUsageTable(CpuUsageMap* lastCpuUsage)
194 std::vector<Json> lastCpuUsageLog;
195 bool ret = __dbMgr.executeSync(
196 "SELECT * FROM " BATTERY_LAST_CPU_USAGE_TABLE,
198 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last Cpu Times of Apps");
206 while (k < lastCpuUsageLog.size()) {
207 lastCpuUsageLog[k].get(NULL, BATTERY_APP_ID, &appId);
208 lastCpuUsageLog[k].get(NULL, BATTERY_TIMESTAMP, ×tamp);
209 lastCpuUsageLog[k].get(NULL, BATTERY_UTIME, &utime);
210 lastCpuUsageLog[k].get(NULL, BATTERY_STIME, &stime);
213 LastAppCpuUsageInfo lastAppCpuUsage;
214 lastAppCpuUsage.timestamp = timestamp;
215 lastAppCpuUsage.utime = utime;
216 lastAppCpuUsage.stime = stime;
217 (*lastCpuUsage)[appId] = lastAppCpuUsage;
222 bool BatteryMonitor::processBatteryUsage()
224 IF_FAIL_RETURN_TAG(__batteryTimeInfoVec.size() > 0, true, _D, "All per-app battery usages are already calculated");
228 __batteryTimeInfoVec.front().get(NULL, BATTERY_START_TIME, &totalStartTime);
229 __batteryTimeInfoVec.back().get(NULL, BATTERY_END_TIME, &totalEndTime);
231 // Read cpu table from heart db for time span of stacked in __batteryTimeInfoVec
232 HeartDbReader heartReader;
233 bool ret = heartReader.open();
234 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to open heart db");
236 std::vector<Json> cpuUsageLog;
237 ret = heartReader.readCpuUsageLog(totalStartTime, totalEndTime, &cpuUsageLog);
239 IF_FAIL_RETURN_TAG(ret, false, _E, "Cannot read from heart cpu table");
240 IF_FAIL_RETURN_TAG(cpuUsageLog.size() > 0, true, _W, "Heart cpu data is not prepared yet (%d ~ %d)", totalStartTime, totalEndTime);
241 _D("Read %d rows from heart cpu table from %d to %d", cpuUsageLog.size(), totalStartTime, totalEndTime);
243 // Get the last timestamp of HEART cpu data and maximum app times tables in cache
244 cpuUsageLog.back().get(NULL, BATTERY_TIMESTAMP, &__lastHeartTimestamp);
245 CpuUsageMap lastCpuUsage;
246 ret = __getLastCpuUsageTable(&lastCpuUsage);
249 for (i = 0; i < __batteryTimeInfoVec.size(); i++) {
253 Json row = __batteryTimeInfoVec[i].str();
254 row.get(NULL, BATTERY_START_TIME, &startTime);
255 row.get(NULL, BATTERY_END_TIME, &endTime);
257 if (endTime > __lastHeartTimestamp) {
258 _W("[%d] Heart cpu data is not prepared yet (%d ~ %d)", i, startTime, endTime);
262 // Calculate per app battery usage
263 std::vector<Json> usage;
264 ret = __analyzer.calculateBatteryUsage(startTime, endTime, cpuUsageLog, lastCpuUsage, &usage);
266 _E("[%d] Failed to calculate battery usage (%d ~ %d)", i, startTime, endTime);
269 _D("[%d] Battery usage per app calculated (%d ~ %d)", i, startTime, endTime);
271 // Insert battery usage
272 ret = __insertBatteryUsageLog(usage);
274 _E("Failed to insert per app battery usage");
278 // Insert log of last times of apps
280 ret = __insertLastCpuUsageLog(lastCpuUsage);
282 _E("Failed to insert last Cpu Usage of apps");
286 // Remove completed time info
287 _D("Total %d time intervals, %d intervals are calculated", __batteryTimeInfoVec.size(), i);
288 __batteryTimeInfoVec.erase(__batteryTimeInfoVec.begin(), __batteryTimeInfoVec.begin() + i);
293 bool BatteryMonitor::__insertBatteryUsageLog(std::vector<Json>& usage)
295 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
296 std::string query("INSERT INTO " BATTERY_USAGE_TABLE \
297 "(" BATTERY_APP_ID ", " BATTERY_START_TIME ", " \
298 BATTERY_END_TIME ", " BATTERY_UTIME ", " \
299 BATTERY_STIME ", " BATTERY_AMOUNT ") VALUES");
307 for (unsigned int i = 0; i < usage.size(); i++) {
308 usage[i].get(NULL, BATTERY_APP_ID, &appId);
309 usage[i].get(NULL, BATTERY_START_TIME, &startTime);
310 usage[i].get(NULL, BATTERY_END_TIME, &endTime);
311 usage[i].get(NULL, BATTERY_UTIME, &utime);
312 usage[i].get(NULL, BATTERY_STIME, &stime);
313 usage[i].get(NULL, BATTERY_AMOUNT, &amount);
315 query += " ('" + appId + "', "
316 + std::to_string(startTime) + ", "
317 + std::to_string(endTime) + ", "
318 + std::to_string(utime) + ", "
319 + std::to_string(stime) + ", "
320 + std::to_string((int) (amount * 10000)) + ")";
324 query = query.substr(0, query.size() - 2);
326 _D("Insert %d rows of per app battery usage", usage.size());
327 return __dbMgr.executeSync(query.c_str(), NULL);
330 bool BatteryMonitor::__insertLastCpuUsageLog(CpuUsageMap& usage)
332 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
333 _D("Delete all rows from app last times table");
334 __dbMgr.executeSync("DELETE FROM " BATTERY_LAST_CPU_USAGE_TABLE, NULL);
336 std::string query("INSERT INTO " BATTERY_LAST_CPU_USAGE_TABLE "(" BATTERY_APP_ID ", " BATTERY_UTIME ", " BATTERY_STIME "," BATTERY_TIMESTAMP ") VALUES");
342 for (auto it = usage.begin(); it != usage.end(); it++) {
344 timestamp = (it->second).timestamp;
345 utime = (it->second).utime;
346 stime = (it->second).stime;
348 query += " ('" + appId
349 + "', " + std::to_string(utime)
350 + ", " + std::to_string(stime)
351 + ", " + std::to_string(timestamp) + ")";
356 _D("Insert %d rows in app last times table", usage.size());
357 query = query.substr(0, query.size() - 2);
358 return __dbMgr.executeSync(query.c_str(), NULL);
361 // Used for Recent Battery Usage
362 int BatteryMonitor::getLastResetTime()
364 if (__lastResetTime == 0) {
365 _I("Device has not fully charged until now. Start time of recent battery usage will be booting time");
366 return __bootingTime;
369 return __lastResetTime;