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.
21 #include <device/battery.h>
24 #include <AppHistoryTypesPrivate.h>
25 #include "../DatabaseManager.h"
26 #include "BatteryMonitor.h"
28 #define DEFAULT_ROW_ID_STR "1"
29 #define HEART_DB_QUERY_INTERVAL 10 * 60 * 1000
30 #define DEFAULT_TIME_DIFF 600
31 #define TIME_DIFF_THRESHOLD 300
35 bool __needSync = true;
36 BatteryMonitor* BatteryMonitor::__instance = NULL;
38 BatteryMonitor::BatteryMonitor() :
40 __lastHeartAccessTime(0),
48 BatteryMonitor::~BatteryMonitor()
52 BatteryMonitor* BatteryMonitor::getInstance()
54 IF_FAIL_RETURN(!__instance, __instance);
56 __instance = new BatteryMonitor();
61 void BatteryMonitor::destroy()
63 IF_FAIL_VOID(__instance);
69 void BatteryMonitor::initialize(uid_t uid, Timer* timer)
78 __database = DatabaseManager::getInstance();
82 "CREATE TABLE IF NOT EXISTS " BATTERY_USAGE_TABLE \
83 " (" BATTERY_USAGE_TABLE_COLUMNS "); " \
84 "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_INFO_TABLE \
85 " (" BATTERY_LAST_INFO_TABLE_COLUMNS "); " \
86 "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_CPU_USAGE_TABLE \
87 " (" BATTERY_LAST_CPU_USAGE_TABLE_COLUMNS ");", NULL);
90 bool BatteryMonitor::__loadLastInfo()
92 std::vector<std::string> columns;
93 std::vector<std::shared_ptr<Tuple>> records;
94 bool ret = __database->execute(
95 "SELECT " BATTERY_LAST_FULL_TIME ", " BATTERY_LAST_HEART_ACCESS_TIME " FROM " BATTERY_LAST_INFO_TABLE \
96 " WHERE " BATTERY_ROW_ID " = " DEFAULT_ROW_ID_STR, COL_INT64 COL_INT64, NULL, &records);
97 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last info");
99 if (records.size() == 1) {
100 records[0]->getAt(0, &__lastFullTime);
101 records[0]->getAt(1, &__lastHeartAccessTime);
104 // Adjust last full time & last heart access time
106 bool charging = false;
107 device_battery_get_percent(&percent);
108 device_battery_is_charging(&charging);
110 int currentTime = CURRENT_TIME;
111 if (!charging && percent == 100) { // Fully charged
112 __lastFullTime = currentTime;
113 __lastHeartAccessTime = currentTime;
114 _I("Fully charged. Last fully charged time: %d", __lastFullTime);
116 } else if (__lastFullTime == 0) { // Never fully charged yet
117 __lastFullTime = currentTime;
118 _I("Device has not fully charged until now. Start time of recent battery usage will be %d", __lastFullTime);
120 } else if (__lastFullTime > currentTime || currentTime - __lastFullTime > LOG_RETENTION_PERIOD) {
121 __lastFullTime = currentTime;
122 __lastHeartAccessTime = currentTime;
123 _I("Last fully charged time changed: %d", __lastFullTime);
127 if (__lastHeartAccessTime == 0)
128 __lastHeartAccessTime = currentTime - DEFAULT_TIME_DIFF;
133 bool BatteryMonitor::__updateLastInfo()
135 char *query = sqlite3_mprintf("INSERT OR REPLACE INTO " BATTERY_LAST_INFO_TABLE " (" \
136 BATTERY_ROW_ID ", " BATTERY_LAST_FULL_TIME ", " BATTERY_LAST_HEART_ACCESS_TIME ") VALUES (%s, %lld, %lld)",
137 DEFAULT_ROW_ID_STR, __lastFullTime, __lastHeartAccessTime);
138 bool ret = __database->execute(query, NULL);
143 void BatteryMonitor::__chargerChangeCb(device_callback_e type, void* value, void* userData)
145 IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CHARGING);
147 bool isCharging = intptr_t(value);
148 IF_FAIL_VOID(!isCharging);
151 int error = device_battery_get_percent(&percent);
152 IF_FAIL_VOID_TAG(error == DEVICE_ERROR_NONE, _E, "Failed to get battery capacity");
153 IF_FAIL_VOID(percent == 100);
155 // If charger is disconnected after 100% charged
156 BatteryMonitor* instance = getInstance();
160 instance->__lastFullTime = CURRENT_TIME;
161 _I("Charger is disconnected after fully charged. Last fully charged time: %d", instance->__lastFullTime);
163 if (!instance->__updateLastInfo())
164 _E("Failed to update last reset time and last percent time");
167 void BatteryMonitor::__timeChangeCb(keynode_t* node, void* userData)
169 int timeDiff = vconf_keynode_get_int(node);
170 IF_FAIL_VOID(timeDiff != 0);
172 _I("Time changed(diff: %d). Related timestamps will be modified.", timeDiff);
174 BatteryMonitor* instance = getInstance();
178 instance->__lastFullTime = instance->__lastFullTime + timeDiff;
179 instance->__lastHeartAccessTime = instance->__lastHeartAccessTime + timeDiff;
181 if (instance->__updateLastInfo()) {
182 __instance->__modifyLastCpuUsage(timeDiff);
184 _E("Failed to update last reset time and last percent time");
188 gboolean BatteryMonitor::__timeoutCb(gpointer data)
190 BatteryMonitor::getInstance()->__processBatteryUsage();
195 int BatteryMonitor::start()
197 __heartReader = new HeartDbReader(__uid);
201 int error = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb, NULL);
202 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, E_FAILED, _E, "Failed to set battery charging change cb");
204 error = vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, __timeChangeCb, NULL);
205 IF_FAIL_RETURN_TAG(error == VCONF_OK, E_FAILED, _E, "Failed to set time changed cb");
207 _D("Start timer to request HEART data");
208 __timer->addTimeout(HEART_DB_QUERY_INTERVAL, __timeoutCb, NULL);
213 int BatteryMonitor::stop()
216 delete __heartReader;
217 __heartReader = NULL;
220 int error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb);
221 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, E_FAILED, _E, "Failed to remove callback for charger status");
223 error = vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, __timeChangeCb);
224 IF_FAIL_RETURN_TAG(error == VCONF_OK, E_FAILED, _E, "Failed to remove callback for time changed");
229 bool BatteryMonitor::__getLastCpuUsageTable(CpuUsageMap* lastHeartCpuLog)
231 std::vector<std::shared_ptr<Tuple>> cpuLog;
232 bool ret = __database->execute("SELECT " BATTERY_APP_ID ", " BATTERY_TIMESTAMP ", "
233 BATTERY_UTIME ", " BATTERY_STIME "," BATTERY_PID " FROM " BATTERY_LAST_CPU_USAGE_TABLE,
234 COL_STRING COL_INT64 COL_INT64 COL_INT64 COL_INT64, NULL, &cpuLog);
235 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last cpu times of apps");
244 while (k < cpuLog.size()) {
245 cpuLog[k]->getAt(0, &appId);
246 cpuLog[k]->getAt(1, ×tamp);
247 cpuLog[k]->getAt(2, &utime);
248 cpuLog[k]->getAt(3, &stime);
249 cpuLog[k]->getAt(4, &pid);
253 appInfo.timestamp = timestamp;
254 appInfo.utime = utime;
255 appInfo.stime = stime;
257 (*lastHeartCpuLog)[appId] = appInfo;
262 bool BatteryMonitor::__processBatteryUsage()
264 int currentTime = CURRENT_TIME;
265 if (__lastHeartAccessTime > currentTime) {
266 __lastHeartAccessTime = currentTime - DEFAULT_TIME_DIFF;
267 __lastFullTime = currentTime - DEFAULT_TIME_DIFF;
269 _W("Last fully charged time & last heart access time changed(%d)", __lastFullTime);
272 // Read from heart cpu table
273 bool ret = __heartReader->dbOpen();
274 IF_FAIL_RETURN_TAG(ret, true, _E, "Failed to open heart db");
276 std::vector<Json::Value> heartCpuLog;
277 ret = __heartReader->readCpuLog(__lastHeartAccessTime, &heartCpuLog);
278 __heartReader->dbClose();
280 IF_FAIL_RETURN_TAG(ret, true, _E, "Cannot read from heart cpu table");
281 IF_FAIL_RETURN_TAG(heartCpuLog.size() > 0, true, _W, "Heart cpu data is not prepared");
282 _D("Read %d rows from heart cpu table from %lld", \
283 heartCpuLog.size(), (long long int)__lastHeartAccessTime);
285 __lastHeartAccessTime = heartCpuLog.back()[BATTERY_TIMESTAMP].asInt64();
288 // Get last heart cpu log
289 CpuUsageMap lastHeartCpuLog;;
290 ret = __getLastCpuUsageTable(&lastHeartCpuLog);
292 // Calculate per app battery usage
293 std::vector<Json::Value> usage;
294 BatteryUsageAnalyzer::calculateBatteryUsage(heartCpuLog, lastHeartCpuLog, &usage);
296 // Insert battery usage
297 ret = __insertBatteryUsageLog(usage);
298 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to insert per app battery usage");
300 // Update last cpu usage
301 ret = __updateLastCpuUsageLog(lastHeartCpuLog);
302 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update last cpu log");
309 bool BatteryMonitor::__insertBatteryUsageLog(std::vector<Json::Value>& usage)
311 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
312 std::string query("INSERT INTO " BATTERY_USAGE_TABLE \
313 "(" BATTERY_APP_ID ", " BATTERY_START_TIME ", " BATTERY_END_TIME ", " \
314 BATTERY_UTIME ", " BATTERY_STIME "," BATTERY_TOTAL_TIME ") VALUES");
317 int startTime, endTime;
320 for (unsigned int i = 0; i < usage.size(); i++) {
321 appId = usage[i][BATTERY_APP_ID].asString();
322 startTime = usage[i][BATTERY_START_TIME].asInt();
323 endTime = usage[i][BATTERY_END_TIME].asInt();
324 utime = usage[i][BATTERY_UTIME].asInt();
325 stime = usage[i][BATTERY_STIME].asInt();
327 query += " ('" + appId + "', "
328 + std::to_string(startTime) + ", "
329 + std::to_string(endTime) + ", "
330 + std::to_string(utime) + ", "
331 + std::to_string(stime) + ", "
332 + std::to_string(utime + stime) + ")";
336 query = query.substr(0, query.size() - 2);
338 // Remove expired log
339 query += "; DELETE FROM " + std::string(BATTERY_USAGE_TABLE)
340 + " WHERE EndTime < " + std::to_string(CURRENT_TIME - LOG_RETENTION_PERIOD)
341 + " OR EndTime > " + std::to_string(CURRENT_TIME) + ";";
343 _D("Insert %d rows of per app battery usage", usage.size());
344 return __database->execute(query.c_str(), NULL);
347 bool BatteryMonitor::__updateLastCpuUsageLog(CpuUsageMap& usage)
349 _D("Delete all rows from last cpu usage table");
350 __database->execute("DELETE FROM " BATTERY_LAST_CPU_USAGE_TABLE, NULL);
352 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
354 std::string query("INSERT INTO " BATTERY_LAST_CPU_USAGE_TABLE "(" BATTERY_APP_ID ", " BATTERY_UTIME ", " BATTERY_STIME ", " BATTERY_TIMESTAMP ", " BATTERY_PID ") VALUES");
357 int stime, utime, pid;
360 for (auto it = usage.begin(); it != usage.end(); it++) {
362 timestamp = (it->second).timestamp;
363 utime = (it->second).utime;
364 stime = (it->second).stime;
365 pid = (it->second).pid;
367 query += " ('" + appId
368 + "', " + std::to_string(utime)
369 + ", " + std::to_string(stime)
370 + ", " + std::to_string(timestamp)
371 + ", " + std::to_string(pid) + ")";
376 _D("Insert %d rows in app last times table", usage.size());
377 query = query.substr(0, query.size() - 2);
378 return __database->execute(query.c_str(), NULL);
381 // Used for Recent Battery Usage
382 int BatteryMonitor::getLastFullTime()
384 return __lastFullTime;
387 void BatteryMonitor::prepareData()
389 int timeDiff = CURRENT_TIME - __lastHeartAccessTime;
390 IF_FAIL_VOID_TAG(__needSync || timeDiff >= TIME_DIFF_THRESHOLD || timeDiff < 0,
391 _D, "Battery usage was updated %d minutes ago", timeDiff / 60);
393 _D("Request to sync heart cpu data");
394 bool ret = __heartReader->requestSync();
395 IF_FAIL_VOID_TAG(ret, _E, "Failed to sync heart db");
397 __processBatteryUsage();
400 void BatteryMonitor::__modifyLastCpuUsage(int timeDiff)
402 char *query = sqlite3_mprintf("UPDATE Temp_LastCpuUsagePerApp SET Timestamp = Timestamp + (%d)", timeDiff);
403 __database->execute(query, NULL);
406 _D("Modified timestamp of LastCpuUsage");