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);
130 bool BatteryMonitor::__updateLastInfo()
132 char *query = sqlite3_mprintf("INSERT OR REPLACE INTO " BATTERY_LAST_INFO_TABLE " (" \
133 BATTERY_ROW_ID ", " BATTERY_LAST_FULL_TIME ", " BATTERY_LAST_HEART_ACCESS_TIME ") VALUES (%s, %d, %d)",
134 DEFAULT_ROW_ID_STR, __lastFullTime, __lastHeartAccessTime);
135 bool ret = __database->execute(query, NULL);
140 void BatteryMonitor::__chargerChangeCb(device_callback_e type, void* value, void* userData)
142 IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CHARGING);
144 bool isCharging = intptr_t(value);
145 IF_FAIL_VOID(!isCharging);
148 int error = device_battery_get_percent(&percent);
149 IF_FAIL_VOID_TAG(error == DEVICE_ERROR_NONE, _E, "Failed to get battery capacity");
150 IF_FAIL_VOID(percent == 100);
152 // If charger is disconnected after 100% charged
153 BatteryMonitor* instance = getInstance();
157 instance->__lastFullTime = CURRENT_TIME;
158 _I("Charger is disconnected after fully charged. Last fully charged time: %d", instance->__lastFullTime);
160 if (!instance->__updateLastInfo())
161 _E("Failed to update last reset time and last percent time");
164 void BatteryMonitor::__timeChangeCb(keynode_t* node, void* userData)
166 int timeDiff = vconf_keynode_get_int(node);
167 IF_FAIL_VOID(timeDiff != 0);
169 _I("Time changed(diff: %d). Related timestamps will be modified.", timeDiff);
171 BatteryMonitor* instance = getInstance();
175 instance->__lastFullTime = instance->__lastFullTime + timeDiff;
176 instance->__lastHeartAccessTime = instance->__lastHeartAccessTime + timeDiff;
178 if (instance->__updateLastInfo()) {
179 __instance->__modifyLastCpuUsage(timeDiff);
181 _E("Failed to update last reset time and last percent time");
185 gboolean BatteryMonitor::__timeoutCb(gpointer data)
187 BatteryMonitor::getInstance()->__processBatteryUsage();
192 int BatteryMonitor::start()
194 __heartReader = new HeartDbReader(__uid);
198 int error = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb, NULL);
199 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, E_FAILED, _E, "Failed to set battery charging change cb");
201 error = vconf_notify_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, __timeChangeCb, NULL);
202 IF_FAIL_RETURN_TAG(error == VCONF_OK, E_FAILED, _E, "Failed to set time changed cb");
204 _D("Start timer to request HEART data");
205 __timer->addTimeout(HEART_DB_QUERY_INTERVAL, __timeoutCb, NULL);
210 int BatteryMonitor::stop()
213 delete __heartReader;
214 __heartReader = NULL;
217 int error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb);
218 IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, E_FAILED, _E, "Failed to remove callback for charger status");
220 error = vconf_ignore_key_changed(VCONFKEY_SYSTEM_TIME_CHANGED, __timeChangeCb);
221 IF_FAIL_RETURN_TAG(error == VCONF_OK, E_FAILED, _E, "Failed to remove callback for time changed");
226 bool BatteryMonitor::__getLastCpuUsageTable(CpuUsageMap* lastHeartCpuLog)
228 std::vector<std::shared_ptr<Tuple>> cpuLog;
229 bool ret = __database->execute("SELECT " BATTERY_APP_ID ", " BATTERY_TIMESTAMP ", "
230 BATTERY_UTIME ", " BATTERY_STIME "," BATTERY_PID " FROM " BATTERY_LAST_CPU_USAGE_TABLE,
231 COL_STRING COL_INT64 COL_INT64 COL_INT64 COL_INT64, NULL, &cpuLog);
232 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last cpu times of apps");
241 while (k < cpuLog.size()) {
242 cpuLog[k]->getAt(0, &appId);
243 cpuLog[k]->getAt(1, ×tamp);
244 cpuLog[k]->getAt(2, &utime);
245 cpuLog[k]->getAt(3, &stime);
246 cpuLog[k]->getAt(4, &pid);
250 appInfo.timestamp = timestamp;
251 appInfo.utime = utime;
252 appInfo.stime = stime;
254 (*lastHeartCpuLog)[appId] = appInfo;
259 bool BatteryMonitor::__processBatteryUsage()
261 int currentTime = CURRENT_TIME;
262 if (__lastHeartAccessTime > currentTime) {
263 __lastHeartAccessTime = currentTime - DEFAULT_TIME_DIFF;
264 __lastFullTime = currentTime - DEFAULT_TIME_DIFF;
266 _W("Last fully charged time & last heart access time changed(%d)", __lastFullTime);
269 // Read from heart cpu table
270 bool ret = __heartReader->dbOpen();
271 IF_FAIL_RETURN_TAG(ret, true, _E, "Failed to open heart db");
273 std::vector<Json::Value> heartCpuLog;
274 ret = __heartReader->readCpuLog(__lastHeartAccessTime, &heartCpuLog);
275 __heartReader->dbClose();
277 IF_FAIL_RETURN_TAG(ret, true, _E, "Cannot read from heart cpu table");
278 IF_FAIL_RETURN_TAG(heartCpuLog.size() > 0, true, _W, "Heart cpu data is not prepared");
279 _D("Read %d rows from heart cpu table from %d", heartCpuLog.size(), __lastHeartAccessTime);
281 __lastHeartAccessTime = heartCpuLog.back()[BATTERY_TIMESTAMP].asInt64();
284 // Get last heart cpu log
285 CpuUsageMap lastHeartCpuLog;;
286 ret = __getLastCpuUsageTable(&lastHeartCpuLog);
288 // Calculate per app battery usage
289 std::vector<Json::Value> usage;
290 BatteryUsageAnalyzer::calculateBatteryUsage(heartCpuLog, lastHeartCpuLog, &usage);
292 // Insert battery usage
293 ret = __insertBatteryUsageLog(usage);
294 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to insert per app battery usage");
296 // Update last cpu usage
297 ret = __updateLastCpuUsageLog(lastHeartCpuLog);
298 IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update last cpu log");
305 bool BatteryMonitor::__insertBatteryUsageLog(std::vector<Json::Value>& usage)
307 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
308 std::string query("INSERT INTO " BATTERY_USAGE_TABLE \
309 "(" BATTERY_APP_ID ", " BATTERY_START_TIME ", " BATTERY_END_TIME ", " \
310 BATTERY_UTIME ", " BATTERY_STIME "," BATTERY_TOTAL_TIME ") VALUES");
313 int startTime, endTime;
316 for (unsigned int i = 0; i < usage.size(); i++) {
317 appId = usage[i][BATTERY_APP_ID].asString();
318 startTime = usage[i][BATTERY_START_TIME].asInt();
319 endTime = usage[i][BATTERY_END_TIME].asInt();
320 utime = usage[i][BATTERY_UTIME].asInt();
321 stime = usage[i][BATTERY_STIME].asInt();
323 query += " ('" + appId + "', "
324 + std::to_string(startTime) + ", "
325 + std::to_string(endTime) + ", "
326 + std::to_string(utime) + ", "
327 + std::to_string(stime) + ", "
328 + std::to_string(utime + stime) + ")";
332 query = query.substr(0, query.size() - 2);
334 // Remove expired log
335 query += "; DELETE FROM " + std::string(BATTERY_USAGE_TABLE)
336 + " WHERE EndTime < " + std::to_string(CURRENT_TIME - LOG_RETENTION_PERIOD)
337 + " OR EndTime > " + std::to_string(CURRENT_TIME) + ";";
339 _D("Insert %d rows of per app battery usage", usage.size());
340 return __database->execute(query.c_str(), NULL);
343 bool BatteryMonitor::__updateLastCpuUsageLog(CpuUsageMap& usage)
345 _D("Delete all rows from last cpu usage table");
346 __database->execute("DELETE FROM " BATTERY_LAST_CPU_USAGE_TABLE, NULL);
348 IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data");
350 std::string query("INSERT INTO " BATTERY_LAST_CPU_USAGE_TABLE "(" BATTERY_APP_ID ", " BATTERY_UTIME ", " BATTERY_STIME ", " BATTERY_TIMESTAMP ", " BATTERY_PID ") VALUES");
353 int stime, utime, pid;
356 for (auto it = usage.begin(); it != usage.end(); it++) {
358 timestamp = (it->second).timestamp;
359 utime = (it->second).utime;
360 stime = (it->second).stime;
361 pid = (it->second).pid;
363 query += " ('" + appId
364 + "', " + std::to_string(utime)
365 + ", " + std::to_string(stime)
366 + ", " + std::to_string(timestamp)
367 + ", " + std::to_string(pid) + ")";
372 _D("Insert %d rows in app last times table", usage.size());
373 query = query.substr(0, query.size() - 2);
374 return __database->execute(query.c_str(), NULL);
377 // Used for Recent Battery Usage
378 int64_t BatteryMonitor::getLastFullTime()
380 return __lastFullTime;
383 void BatteryMonitor::prepareData()
385 int timeDiff = CURRENT_TIME - __lastHeartAccessTime;
386 IF_FAIL_VOID_TAG(__needSync || timeDiff >= TIME_DIFF_THRESHOLD || timeDiff < 0,
387 _D, "Battery usage was updated %d minutes ago", timeDiff / 60);
389 _D("Request to sync heart cpu data");
390 bool ret = __heartReader->requestSync();
391 IF_FAIL_VOID_TAG(ret, _E, "Failed to sync heart db");
393 __processBatteryUsage();
396 void BatteryMonitor::__modifyLastCpuUsage(int timeDiff)
398 char *query = sqlite3_mprintf("UPDATE Temp_LastCpuUsagePerApp SET Timestamp = Timestamp + (%d)", timeDiff);
399 __database->execute(query, NULL);
402 _D("Modified timestamp of LastCpuUsage");