From: Somin Kim Date: Fri, 2 Sep 2016 20:52:55 +0000 (+0900) Subject: Per app battery usage (Only foreground app duration considered - based on HEART cpu db) X-Git-Tag: submit/tizen/20160907.123648^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c70c9a3e4e1c25ea050bbbda411fc8c7ddc7a7f3;p=platform%2Fcore%2Fcontext%2Fcontext-provider.git Per app battery usage (Only foreground app duration considered - based on HEART cpu db) Change-Id: I857e83ae8a20796865a056bd11106fa3254c54d9 Signed-off-by: Somin Kim --- diff --git a/include/ProviderList.h b/include/ProviderList.h index 3042ca2..4da36a8 100644 --- a/include/ProviderList.h +++ b/include/ProviderList.h @@ -39,6 +39,7 @@ const struct { } subjectLibraryList[] = { {SUBJ_ACTIVITY, "activity"}, {SUBJ_APP_STATS, "app-stats"}, + {SUBJ_BATTERY_STATS, "battery-stats"}, {SUBJ_STATE_CALL, "call"}, {SUBJ_STATE_CONTACTS, "contacts"}, {SUBJ_CUSTOM, "custom"}, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f41f86b..30d980b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ ADD_SUBDIRECTORY(wifi) IF("${PROFILE}" STREQUAL "mobile") ADD_SUBDIRECTORY(app-stats) +ADD_SUBDIRECTORY(battery-stats) ADD_SUBDIRECTORY(call) ADD_SUBDIRECTORY(contacts) ADD_SUBDIRECTORY(email) diff --git a/src/battery-stats/BatteryMonitor.cpp b/src/battery-stats/BatteryMonitor.cpp new file mode 100644 index 0000000..6c9ba5d --- /dev/null +++ b/src/battery-stats/BatteryMonitor.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "BatteryStatisticsTypes.h" +#include "HeartDbReader.h" +#include "BatteryMonitor.h" + +#define DEFAULT_ROW_ID_STR "1" + +using namespace ctx; + +static int __lastResetTime = 0; +static int __lastPercent = -1; +static int __lastPercentTime = 0; +static bool __isCharging = 0; +static std::vector __batteryTimeInfoVec; + + +BatteryMonitor::BatteryMonitor() +{ + __initialize(); +} + +BatteryMonitor::~BatteryMonitor() +{ +} + +void BatteryMonitor::__initialize() +{ + std::vector records; + __dbMgr.executeSync( + "CREATE TABLE IF NOT EXISTS " BATTERY_USAGE_TABLE \ + " (" BATTERY_USAGE_TABLE_COLUMNS ")", &records); + + __dbMgr.executeSync( + "CREATE TABLE IF NOT EXISTS " BATTERY_LAST_INFO_TABLE \ + " (" BATTERY_LAST_INFO_TABLE_COLUMNS ")", &records); + + __dbMgr.createTableSync(BATTERY_TEMP_TIME_INFO, BATTERY_TEMP_TIME_INFO_COLUMNS, NULL); +} + +bool BatteryMonitor::__loadLastInfo() +{ + device_battery_is_charging(&__isCharging); + + std::vector records; + bool ret = __dbMgr.executeSync( + "SELECT * FROM " BATTERY_LAST_INFO_TABLE \ + " WHERE " BATTERY_ROW_ID " = " DEFAULT_ROW_ID_STR, &records); + IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to load last info"); + + if (records.size() == 1) { + records[0].get(NULL, BATTERY_LAST_RESET_TIME, &__lastResetTime); + records[0].get(NULL, BATTERY_LAST_PERCENT, &__lastPercent); + records[0].get(NULL, BATTERY_LAST_PERCENT_TIME, &__lastPercentTime); + } + records.clear(); + + __batteryTimeInfoVec.clear(); + ret = __dbMgr.executeSync("SELECT * FROM " BATTERY_TEMP_TIME_INFO , &__batteryTimeInfoVec); + + ret = __dbMgr.executeSync("DELETE FROM " BATTERY_TEMP_TIME_INFO, &records); + + return true; +} + +bool BatteryMonitor::__updateLastInfo() +{ + if (__batteryTimeInfoVec.size() > 0) { + for (unsigned int i = 0; i < __batteryTimeInfoVec.size(); i++) { + int64_t rowId; + __dbMgr.insertSync(BATTERY_TEMP_TIME_INFO, __batteryTimeInfoVec.at(i), &rowId); + } + } + + IF_FAIL_RETURN_TAG(__lastResetTime != 0 || __lastPercentTime != 0, false, _W, "Last info doesn't exist"); + + char *query = sqlite3_mprintf( + "INSERT OR REPLACE INTO " BATTERY_LAST_INFO_TABLE " (" \ + BATTERY_ROW_ID ", " BATTERY_LAST_RESET_TIME ", " \ + BATTERY_LAST_PERCENT ", " BATTERY_LAST_PERCENT_TIME ") VALUES (%s, %d, %d, %d)", + DEFAULT_ROW_ID_STR, __lastResetTime, __lastPercent, __lastPercentTime); + + std::vector records; + bool ret = __dbMgr.executeSync(query, &records); + sqlite3_free(query); + IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to update battery stat last info"); + + return true; +} + +void BatteryMonitor::__batteryChangeCb(device_callback_e type, void* value, void* userData) +{ + IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CAPACITY); + + int percent = intptr_t(value); + int currentTime = CURRENT_TIME; + BatteryMonitor* instance = static_cast(userData); + + if (!__isCharging && percent == (__lastPercent - 1) && __lastPercentTime != 0) { + _D("Battery capacity decreased: %d% -> %d%", __lastPercent, percent); + + Json battTimeInfo; + battTimeInfo.set(NULL, BATTERY_AMOUNT, percent); + battTimeInfo.set(NULL, BATTERY_START_TIME, __lastPercentTime); + battTimeInfo.set(NULL, BATTERY_END_TIME, currentTime); + __batteryTimeInfoVec.push_back(battTimeInfo); + + instance->processBatteryUsage(); + } + + __lastPercentTime = currentTime; + __lastPercent = percent; +} + +void BatteryMonitor::__chargerChangeCb(device_callback_e type, void* value, void* userData) +{ + IF_FAIL_VOID(type == DEVICE_CALLBACK_BATTERY_CHARGING); + + __isCharging = intptr_t(value); + IF_FAIL_VOID(!__isCharging); + + int percent; + if (__lastPercent < 0) { + int error = device_battery_get_percent(&percent); + IF_FAIL_VOID_TAG(error == DEVICE_ERROR_NONE, _E, "Failed to get battery capacity"); + } else { + percent = __lastPercent; + } + + // If charger is disconnected after 100% charged + if (percent == 100) { + __lastResetTime = CURRENT_TIME; + __lastPercentTime = __lastResetTime; + _D("Charger is disconnected after fully charged. ResetTime: %d", __lastResetTime); + } +} + +int BatteryMonitor::start() +{ + __loadLastInfo(); + + int error = device_add_callback(DEVICE_CALLBACK_BATTERY_CAPACITY, __batteryChangeCb, this); + IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to set battery capacity change cb"); + + error = device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb, NULL); + IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to set battery charging change cb"); + + return ERR_NONE; +} + +int BatteryMonitor::stop() +{ + __updateLastInfo(); + + int error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CAPACITY, __batteryChangeCb); + IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to remove callback for battery capacity"); + + error = device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, __chargerChangeCb); + IF_FAIL_RETURN_TAG(error == DEVICE_ERROR_NONE, ERR_OPERATION_FAILED, _E, "Failed to remove callback for charger status"); + + return ERR_NONE; +} + +bool BatteryMonitor::processBatteryUsage() +{ + IF_FAIL_RETURN_TAG(__batteryTimeInfoVec.size() > 0, true, _D, "All per-app battery usages are already calculated"); + + int totalStartTime; + int totalEndTime; + __batteryTimeInfoVec.front().get(NULL, BATTERY_START_TIME, &totalStartTime); + __batteryTimeInfoVec.back().get(NULL, BATTERY_END_TIME, &totalEndTime); + + // Read cpu table from heart db for time span of stacked in __batteryTimeInfoVec + HeartDbReader heartReader; + bool ret = heartReader.open(); + IF_FAIL_RETURN_TAG(ret, false, _E, "Failed to open heart db"); + + std::vector appLog; + ret = heartReader.readAppLaunchLog(totalStartTime, totalEndTime, &appLog); + heartReader.close(); + IF_FAIL_RETURN_TAG(ret, false, _E, "Cannot read from heart cpu table"); + IF_FAIL_RETURN_TAG(appLog.size() > 0, true, _W, "Heart cpu data is not prepared yet (%d ~ %d)", totalStartTime, totalEndTime); + _D("Read %d rows from heart cpu table from %d to %d", appLog.size(), totalStartTime, totalEndTime); + + // Get the last timestamp of HEART cpu data + int lastHeartTimestamp; + appLog.back().get(NULL, BATTERY_TIMESTAMP, &lastHeartTimestamp); + + unsigned int i; + for (i = 0; i < __batteryTimeInfoVec.size(); i++) { + int startTime; + int endTime; + + Json row = __batteryTimeInfoVec[i].str(); + row.get(NULL, BATTERY_START_TIME, &startTime); + row.get(NULL, BATTERY_END_TIME, &endTime); + + if (endTime > lastHeartTimestamp) { + _W("[%d] Heart cpu data is not prepared yet (%d ~ %d)", i, startTime, endTime); + break; + } + + // Calculate per app battery usage + std::vector usage; + ret = __analyzer.calculateBatteryUsage(startTime, endTime, appLog, &usage); + if (!ret) { + _E("[%d] Failed to calculate battery usage (%d ~ %d)", i, startTime, endTime); + continue; + } + _D("[%d] Battery usage per app calculated (%d ~ %d)", i, startTime, endTime); + + // Insert battery usage + ret = __insertUsageLog(usage); + if (!ret) { + _E("Failed to insert per app battery usage"); + } + } + + // Remove completed time info + _D("Total %d time intervals, %d intervals are calculated", __batteryTimeInfoVec.size(), i); + __batteryTimeInfoVec.erase(__batteryTimeInfoVec.begin(), __batteryTimeInfoVec.begin() + i); + + return true; +} + +bool BatteryMonitor::__insertUsageLog(std::vector& usage) +{ + IF_FAIL_RETURN_TAG(usage.size(), true, _W, "No data"); + std::string query = std::string("INSERT INTO " BATTERY_USAGE_TABLE \ + "(" BATTERY_APP_ID ", " BATTERY_START_TIME ", " BATTERY_END_TIME "," BATTERY_AMOUNT ") VALUES"); + + std::string appId; + int startTime; + int endTime; + double amount; + + for (unsigned int i = 0; i < usage.size(); i++) { + usage[i].get(NULL, BATTERY_APP_ID, &appId); + usage[i].get(NULL, BATTERY_START_TIME, &startTime); + usage[i].get(NULL, BATTERY_END_TIME, &endTime); + usage[i].get(NULL, BATTERY_AMOUNT, &amount); + + query += std::string(" ('" + appId + "', " + std::to_string(startTime) + ", " + + std::to_string(endTime) + ", " + std::to_string((int) (amount * 10000)) + ")"); + + if (i != usage.size() - 1 ) { + query += ", "; + } + } + + _D("Insert %d rows of per app battery usage", usage.size()); + std::vector records; + return __dbMgr.executeSync(query.c_str(), &records); +} + +int BatteryMonitor::getLastResetTime() +{ + IF_FAIL_RETURN_TAG(__lastResetTime != 0, CURRENT_TIME, _D, "Last reset time doesn't exist"); + return __lastResetTime; +} diff --git a/src/battery-stats/BatteryMonitor.h b/src/battery-stats/BatteryMonitor.h new file mode 100644 index 0000000..361a08f --- /dev/null +++ b/src/battery-stats/BatteryMonitor.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_BATTERY_MONITOR_H_ +#define _CONTEXT_BATTERY_MONITOR_H_ + +#include +#include +#include +#include "BatteryUsageAnalyzer.h" + +namespace ctx { + + class BatteryMonitor { + public: + BatteryMonitor(); + ~BatteryMonitor(); + + int start(); + int stop(); + + static int getLastResetTime(); + bool processBatteryUsage(); + + private: + void __initialize(); + bool __loadLastInfo(); + bool __updateLastInfo(); + + static void __batteryChangeCb(device_callback_e type, void* value, void* userData); + static void __chargerChangeCb(device_callback_e type, void* value, void* userData); + + bool __insertUsageLog(std::vector& usage); + + DatabaseManager __dbMgr; + BatteryUsageAnalyzer __analyzer; + + }; + +} /* namespace ctx */ + +#endif /* _CONTEXT_BATTERY_MONITOR_H_ */ diff --git a/src/battery-stats/BatteryStatisticsTypes.h b/src/battery-stats/BatteryStatisticsTypes.h new file mode 100644 index 0000000..dc43678 --- /dev/null +++ b/src/battery-stats/BatteryStatisticsTypes.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_STATS_BATTERY_TYPES_H_ +#define _CONTEXT_STATS_BATTERY_TYPES_H_ + +#include + +#define BATTERY_HISTORY_PRIV PRIV_APP_HISTORY + +#define BATTERY_USAGE_TABLE "Log_BatteryUsagePerApp" +#define BATTERY_USAGE_TABLE_COLUMNS \ + "AppId TEXT NOT NULL, StartTime INTEGER NOT NULL DEFAULT 0, " \ + "EndTime INTEGER NOT NULL DEFAULT 0, Amount INTEGER NOT NULL DEFAULT 0" + +#define BATTERY_LAST_INFO_TABLE "Battery_LastInfo" +#define BATTERY_LAST_INFO_TABLE_COLUMNS \ + "RowId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " \ + "LastResetTime UNSIGNED INT NOT NULL DEFAULT 0, " \ + "LastPercent UNSIGNED INT NOT NULL DEFAULT 0," \ + "LastPercentTime UNSIGNED INT NOT NULL DEFAULT 0" + +#define BATTERY_TEMP_TIME_INFO "Temp_BatteryTimeInfo" +#define BATTERY_TEMP_TIME_INFO_COLUMNS \ + "Amount INTEGER NOT NULL DEFAULT 0, StartTime INTEGER NOT NULL DEFAULT 0, " \ + "EndTime INTEGER NOT NULL DEFAULT 0" + +#define BATTERY_APP_ID "AppId" +#define BATTERY_TIMESTAMP "Timestamp" +#define BATTERY_TYPE "Type" +#define BATTERY_START_TIME "StartTime" +#define BATTERY_END_TIME "EndTime" +#define BATTERY_AMOUNT "Amount" +#define BATTERY_LAST_RESET_TIME "LastResetTime" +#define BATTERY_LAST_PERCENT "LastPercent" +#define BATTERY_LAST_PERCENT_TIME "LastPercentTime" +#define BATTERY_ROW_ID "RowId" + +#define CURRENT_TIME (int)(time(0)) + +enum AppLaunchType { + TYPE_SERVICE = 0, + TYPE_FOREGROUND, + TYPE_BACKGROUND +}; + +#endif /* End of _CONTEXT_STATS_BATTERY_TYPES_H_ */ diff --git a/src/battery-stats/BatteryStatsLogger.cpp b/src/battery-stats/BatteryStatsLogger.cpp new file mode 100644 index 0000000..89e0309 --- /dev/null +++ b/src/battery-stats/BatteryStatsLogger.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BatteryStatisticsTypes.h" +#include "BatteryMonitor.h" +#include "BatteryStatsLogger.h" + +using namespace ctx; + +BatteryStatsLogger::BatteryStatsLogger() : + ContextProvider(SUBJ_BATTERY_LOGGER), + __monitor(NULL) +{ + __monitor = new(std::nothrow) BatteryMonitor(); + IF_FAIL_VOID_TAG(__monitor, _E, "Memory allocation failed"); +} + +BatteryStatsLogger::~BatteryStatsLogger() +{ + delete __monitor; +} + +void BatteryStatsLogger::getPrivilege(std::vector &privilege) +{ + privilege.push_back(BATTERY_HISTORY_PRIV); +} + +int BatteryStatsLogger::subscribe(Json option, Json* requestResult) +{ + return __monitor->start(); +} + +int BatteryStatsLogger::unsubscribe(Json option) +{ + return __monitor->stop(); +} diff --git a/src/battery-stats/BatteryStatsLogger.h b/src/battery-stats/BatteryStatsLogger.h new file mode 100644 index 0000000..026b72e --- /dev/null +++ b/src/battery-stats/BatteryStatsLogger.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_BATTERY_STATS_LOGGER_H_ +#define _CONTEXT_BATTERY_STATS_LOGGER_H_ + +#include + +namespace ctx { + + class BatteryMonitor; + + class BatteryStatsLogger : public ContextProvider { + public: + BatteryStatsLogger(); + ~BatteryStatsLogger(); + + int subscribe(Json option, Json *requestResult); + int unsubscribe(Json option); + + void getPrivilege(std::vector &privilege); + + private: + BatteryMonitor *__monitor; + }; + +} /* namespace ctx */ + +#endif /* _CONTEXT_BATTERY_STATS_LOGGER_H_ */ diff --git a/src/battery-stats/BatteryStatsProvider.cpp b/src/battery-stats/BatteryStatsProvider.cpp new file mode 100644 index 0000000..53899ff --- /dev/null +++ b/src/battery-stats/BatteryStatsProvider.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BatteryStatsProvider.h" + +using namespace ctx; + +BatteryStatsProvider::BatteryStatsProvider(const char *subject) : + ContextProvider(subject) +{ +} + +BatteryStatsProvider::~BatteryStatsProvider() +{ +} + +void BatteryStatsProvider::getPrivilege(std::vector &privilege) +{ + privilege.push_back(BATTERY_HISTORY_PRIV); +} + +BatteryStatsQuerier* BatteryStatsProvider::getQuerier(Json option) +{ + BatteryStatsQuerier *querier = new(std::nothrow) BatteryStatsQuerier(this, option); + IF_FAIL_RETURN_TAG(querier, NULL, _E, "Memory allocation failed"); + return querier; +} diff --git a/src/battery-stats/BatteryStatsProvider.h b/src/battery-stats/BatteryStatsProvider.h new file mode 100644 index 0000000..94d0341 --- /dev/null +++ b/src/battery-stats/BatteryStatsProvider.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_BATTERY_STATS_PROVIDER_H_ +#define _CONTEXT_BATTERY_STATS_PROVIDER_H_ + +#include +#include "BatteryStatisticsTypes.h" +#include "Querier.h" + +namespace ctx { + + class BatteryStatsProvider : public ContextProvider { + public: + virtual int read(Json option, Json *requestResult) = 0; + void getPrivilege(std::vector &privilege); + + protected: + BatteryStatsProvider(const char *subject); + virtual ~BatteryStatsProvider(); + + BatteryStatsQuerier* getQuerier(Json option); + }; + +} /* namespace ctx */ + +#endif /* _CONTEXT_BATTERY_STATS_PROVIDER_H_ */ diff --git a/src/battery-stats/BatteryUsage.cpp b/src/battery-stats/BatteryUsage.cpp new file mode 100644 index 0000000..631308d --- /dev/null +++ b/src/battery-stats/BatteryUsage.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BatteryUsage.h" + +#define SECONDS_IN_A_DAY 86400 + +using namespace ctx; + +BatteryUsageProvider::BatteryUsageProvider() : + BatteryStatsProvider(SUBJ_BATTERY_USAGE) +{ +} + +BatteryUsageProvider::~BatteryUsageProvider() +{ +} + +int BatteryUsageProvider::read(Json option, Json *requestResult) +{ + int startTime; + int endTime; + int timeSpan = DEFAULT_TIME_SPAN; + int timeSpanPoint; + + option.get(NULL, KEY_TIME_SPAN, &timeSpan); + timeSpanPoint = CURRENT_TIME - timeSpan * SECONDS_IN_A_DAY; + + if (!option.get(NULL, KEY_START_TIME, &startTime)) { + startTime = timeSpanPoint; + } + + if (!option.get(NULL, KEY_END_TIME, &endTime)) { + endTime = CURRENT_TIME; + } + + int resultSize; + bool hasLimit = option.get(NULL, KEY_RESULT_SIZE, &resultSize); + + BatteryStatsQuerier *querier = getQuerier(option); + IF_FAIL_RETURN(querier, ERR_OPERATION_FAILED); + + int error; + if (hasLimit) { + error = querier->queryRangeLimit((startTime > timeSpanPoint)? startTime : timeSpanPoint, endTime, resultSize); + } else { + error = querier->queryRange((startTime > timeSpanPoint)? startTime : timeSpanPoint, endTime); + } + IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Failed to get app battery usage"); + + return ERR_NONE; +} diff --git a/src/battery-stats/BatteryUsage.h b/src/battery-stats/BatteryUsage.h new file mode 100644 index 0000000..f446dd3 --- /dev/null +++ b/src/battery-stats/BatteryUsage.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_BATTERY_USAGE_PROVIDER_H_ +#define _CONTEXT_BATTERY_USAGE_PROVIDER_H_ + +#include "BatteryStatsProvider.h" + +namespace ctx { + + class BatteryUsageProvider : public BatteryStatsProvider { + + public: + BatteryUsageProvider(); + ~BatteryUsageProvider(); + + int read(Json option, Json *requestResult); + }; +} + +#endif /* _CONTEXT_BATTERY_USAGE_PROVIDER_H_ */ diff --git a/src/battery-stats/BatteryUsageAnalyzer.cpp b/src/battery-stats/BatteryUsageAnalyzer.cpp new file mode 100644 index 0000000..e02b7be --- /dev/null +++ b/src/battery-stats/BatteryUsageAnalyzer.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "BatteryStatisticsTypes.h" +#include "BatteryUsageAnalyzer.h" + +using namespace ctx; + +bool BatteryUsageAnalyzer::calculateBatteryUsage(int lastTime, int currTime, std::vector& appLog, std::vector* usage) +{ + int timeInterval = currTime - lastTime; + IF_FAIL_RETURN(timeInterval > 0, false); + + std::map lastAppTimeMap; + std::string appId; + int timestamp; + int type; + + for (unsigned int i = 0; i < appLog.size(); i++) { + appLog[i].get(NULL, BATTERY_APP_ID, &appId); + appLog[i].get(NULL, BATTERY_TIMESTAMP, ×tamp); + appLog[i].get(NULL, BATTERY_TYPE, &type); + + if (timestamp < lastTime) { + continue; + } + + if (timestamp > currTime) { + break; + } + + if (type == TYPE_FOREGROUND) { // Mark timestamp of foreground + lastAppTimeMap[appId] = timestamp; + } else if (type == TYPE_BACKGROUND) { // Foreground duration calculation (Foreground->Background) + Json row; + if (lastAppTimeMap.find(appId) == lastAppTimeMap.end() || lastAppTimeMap[appId] == 0) { + __createBatteryUsage(appId, lastTime, timestamp, timeInterval, &row); + } else { + __createBatteryUsage(appId, lastAppTimeMap[appId], timestamp, timeInterval, &row); + lastAppTimeMap[appId] = 0; + } + usage->push_back(row); + } + } + + // Not closed app + for (auto it = lastAppTimeMap.begin(); it != lastAppTimeMap.end(); it++) { + if (it->second == 0) { + continue; + } + + Json row; + __createBatteryUsage(it->first, it->second, currTime, timeInterval, &row); + usage->push_back(row); + } + + return true; +} + +void BatteryUsageAnalyzer::__createBatteryUsage(std::string appId, int startTime, int endTime, int timeInterval, Json* record) +{ + record->set(NULL, BATTERY_APP_ID, appId); + record->set(NULL, BATTERY_START_TIME, startTime); + record->set(NULL, BATTERY_END_TIME, endTime); + record->set(NULL, BATTERY_AMOUNT, (double)(endTime - startTime) / (double)timeInterval); +} diff --git a/src/battery-stats/BatteryUsageAnalyzer.h b/src/battery-stats/BatteryUsageAnalyzer.h new file mode 100644 index 0000000..982ca59 --- /dev/null +++ b/src/battery-stats/BatteryUsageAnalyzer.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_BATTERY_USAGE_ANALYZER_H_ +#define _CONTEXT_BATTERY_USAGE_ANALYZER_H_ + +#include +#include + +namespace ctx { + + class BatteryUsageAnalyzer { + + public: + BatteryUsageAnalyzer() {}; + ~BatteryUsageAnalyzer() {}; + + bool calculateBatteryUsage(int lastTime, int currTime, std::vector& appLog, std::vector* usage); + + private: + void __createBatteryUsage(std::string appId, int startTime, int endTime, int timeInterval, Json* record); + + }; + +} /* namespace ctx */ + +#endif /* _CONTEXT_BATTERY_USAGE_ANALYZER_H_ */ diff --git a/src/battery-stats/CMakeLists.txt b/src/battery-stats/CMakeLists.txt new file mode 100644 index 0000000..00fbdf8 --- /dev/null +++ b/src/battery-stats/CMakeLists.txt @@ -0,0 +1,19 @@ +SET(target "${target_prefix}-battery-stats") + +SET(DEPS ${DEPS} + capi-system-device +) + +FILE(GLOB SRCS *.cpp) + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PKG_BATTERY_STATS REQUIRED ${DEPS}) + +FOREACH(flag ${PKG_BATTERY_STATS_CFLAGS}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") +ENDFOREACH(flag) + +ADD_LIBRARY(${target} SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(${target} ${PKG_BATTERY_LDFLAGS} ${target_shared}) + +INSTALL(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR}/${target_dir}) diff --git a/src/battery-stats/CreateProvider.cpp b/src/battery-stats/CreateProvider.cpp new file mode 100644 index 0000000..c1c07e9 --- /dev/null +++ b/src/battery-stats/CreateProvider.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "BatteryStatsLogger.h" +#include "BatteryUsage.h" +#include "RecentBatteryUsage.h" + +using namespace ctx; + +extern "C" SO_EXPORT ContextProvider* CreateProvider(const char *subject) +{ + ADD_PROVIDER(SUBJ_BATTERY_LOGGER, BatteryStatsLogger); + ADD_PROVIDER(SUBJ_BATTERY_USAGE, BatteryUsageProvider); + ADD_PROVIDER(SUBJ_BATTERY_RECENT_USAGE, RecentBatteryUsageProvider); + + return NULL; +} diff --git a/src/battery-stats/HeartDbReader.cpp b/src/battery-stats/HeartDbReader.cpp new file mode 100644 index 0000000..dcb5efc --- /dev/null +++ b/src/battery-stats/HeartDbReader.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#include +#include +#include "BatteryStatisticsTypes.h" +#include "HeartDbReader.h" + +#define HEART_CPU_TABLE "cpu" +#define HEART_APP_ID "appid" +#define HEART_TIME "time" +#define HEART_DATA "data" + +#ifdef LEGACY_FILE_PATH +#define HEART_DB_PATH "/opt/usr/dbspace/.resourced-logging.db" +#else +#include +#define HEART_DB_PATH tzplatform_mkpath(TZ_USER_DB, ".resourced-heart-default.db") +#endif + +using namespace ctx; + +HeartDbReader::HeartDbReader() : + __heartDb(NULL) +{ +} + +HeartDbReader::~HeartDbReader() +{ + if (__heartDb) { + close(); + } +} + +bool HeartDbReader::open() +{ + sqlite3 *db = NULL; + int ret; + ret = sqlite3_open_v2(HEART_DB_PATH, &db, SQLITE_OPEN_READONLY, NULL); + IF_FAIL_RETURN_TAG(ret == SQLITE_OK, false, _E, "Failed to open HEART db: %s", sqlite3_errmsg(db)); + + __heartDb = db; + + return true; +} + +void HeartDbReader::close() +{ + sqlite3_close(__heartDb); + __heartDb = NULL; +} + +bool HeartDbReader::readAppLaunchLog(int startTime, int endTime, std::vector* appLog) +{ + IF_FAIL_RETURN(__heartDb, false); + + char* sql = sqlite3_mprintf( + "SELECT " HEART_APP_ID ", " HEART_TIME ", " HEART_DATA " FROM " HEART_CPU_TABLE \ + " WHERE " HEART_TIME " >= %d AND " HEART_TIME " < %d", startTime, endTime); + + char* err = NULL; + int ret = sqlite3_exec(__heartDb, sql, __appLaunchLogCb, appLog, &err); + sqlite3_free(sql); + if (ret != SQLITE_OK) { + _E("Failed to read heart DB: Error(%s)", err); + sqlite3_free(err); + return false; + } + + return true; +} + +int HeartDbReader::__appLaunchLogCb(void *userData, int dim, char **value, char **column) +{ + IF_FAIL_RETURN(userData, 0); + + std::vector *records = static_cast*>(userData); + Json row; + Json newRow; + bool columnNull = false; + + for (int i = 0; i < dim; ++i) { + if (!value[i]) { + columnNull = true; + _W(RED("Null columns exist")); + break; + } + + row.set(NULL, column[i], value[i]); + } + + if (!columnNull) { + __convertAppLaunchLog(row, &newRow); + records->push_back(newRow); + } + + return 0; +} + +void HeartDbReader::__convertAppLaunchLog(Json& row, Json* newRow) +{ + std::string appId; + std::string timestamp; + std::string data; +/* int utime; + int stime; + int pid; + int type; +*/ + row.get(NULL, HEART_APP_ID, &appId); + row.get(NULL, HEART_TIME, ×tamp); + row.get(NULL, HEART_DATA, &data); +/* + std::stringstream buf = data; // TODO use utim & stime + buf >> utime >> stime >> pid >> type; +*/ + std::string type = data.substr(data.length() - 2, 1); + + newRow->set(NULL, BATTERY_APP_ID, appId); + newRow->set(NULL, BATTERY_TIMESTAMP, atoi(timestamp.c_str())); + newRow->set(NULL, BATTERY_TYPE, atoi(type.c_str())); +} diff --git a/src/battery-stats/HeartDbReader.h b/src/battery-stats/HeartDbReader.h new file mode 100644 index 0000000..f355233 --- /dev/null +++ b/src/battery-stats/HeartDbReader.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_HEART_DB_READER_H_ +#define _CONTEXT_HEART_DB_READER_H_ + +#include +#include +#include + +namespace ctx { + + class HeartDbReader { + + public: + HeartDbReader(); + ~HeartDbReader(); + + bool open(); + void close(); + + bool readAppLaunchLog(int startTime, int endTime, std::vector* appLog); + + private: + static int __appLaunchLogCb(void *userData, int dim, char **value, char **column); + static void __convertAppLaunchLog(Json& row, Json* newRow); + + sqlite3 *__heartDb; + }; + +} /* namespace ctx */ + +#endif /* _CONTEXT_HEART_DB_READER_H_ */ diff --git a/src/battery-stats/Querier.cpp b/src/battery-stats/Querier.cpp new file mode 100644 index 0000000..f0f043a --- /dev/null +++ b/src/battery-stats/Querier.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "BatteryStatisticsTypes.h" +#include "Querier.h" + +#define BATTERY_USAGE_DEFAULT_QUERY \ + "SELECT " BATTERY_APP_ID " AS " KEY_APP_ID ", ROUND(SUM(" BATTERY_AMOUNT ")/10000.0, 2) AS " KEY_TOTAL_AMOUNT \ + " FROM " BATTERY_USAGE_TABLE " WHERE " BATTERY_START_TIME " >= %d AND " BATTERY_END_TIME " <= %d" \ + " GROUP BY " KEY_APP_ID " ORDER BY " KEY_TOTAL_AMOUNT " DESC" + +using namespace ctx; + +BatteryStatsQuerier::BatteryStatsQuerier(ContextProvider *provider, Json option) : + __provider(provider), + __option(option) +{ +} + +BatteryStatsQuerier::~BatteryStatsQuerier() +{ +} + +int BatteryStatsQuerier::query(const char *sql) +{ + return __dbMgr.execute(0, sql, this) ? ERR_NONE : ERR_OPERATION_FAILED; +} + +int BatteryStatsQuerier::queryRange(int startTime, int endTime) +{ + char *sql = sqlite3_mprintf(BATTERY_USAGE_DEFAULT_QUERY, startTime, endTime); + + int error = query(sql); + sqlite3_free(sql); + + return error; +} + +int BatteryStatsQuerier::queryRangeLimit(int startTime, int endTime, int resultSize) +{ + char *sql = sqlite3_mprintf(BATTERY_USAGE_DEFAULT_QUERY " LIMIT %d", startTime, endTime, resultSize); + + int error = query(sql); + sqlite3_free(sql); + + return error; +} + +void BatteryStatsQuerier::onTableCreated(unsigned int queryId, int error) +{ +} + +void BatteryStatsQuerier::onInserted(unsigned int queryId, int error, int64_t rowId) +{ +} + +void BatteryStatsQuerier::onExecuted(unsigned int queryId, int error, std::vector& records) +{ + Json response; + __convertToResponse(records, response); + __provider->replyToRead(__option, error, response); + + delete this; +} + +void BatteryStatsQuerier::__convertToResponse(std::vector &sqlResult, Json &response) +{ + response = "{\"" KEY_QUERY_RESULT "\":[]}"; + + for (Json& tuple : sqlResult) { + response.append(NULL, KEY_QUERY_RESULT, tuple); + } +} diff --git a/src/battery-stats/Querier.h b/src/battery-stats/Querier.h new file mode 100644 index 0000000..2385a2f --- /dev/null +++ b/src/battery-stats/Querier.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_BATTERY_STATS_QUERIER_H_ +#define _CONTEXT_BATTERY_STATS_QUERIER_H_ + +#include +#include + +namespace ctx { + + class BatteryStatsQuerier : public IDatabaseListener { + public: + BatteryStatsQuerier(ContextProvider *provider, Json option); + ~BatteryStatsQuerier(); + + // For now, Default result size(10) isn't applied, unlike other history type. + int queryRange(int startTime, int endTime); + int queryRangeLimit(int startTime, int endTime, int resultSize); + + protected: + int query(const char *sql); + + void onTableCreated(unsigned int queryId, int error); + void onInserted(unsigned int queryId, int error, int64_t rowId); + void onExecuted(unsigned int queryId, int error, std::vector& records); + + private: + void __convertToResponse(std::vector &sqlResult, Json& response); + + DatabaseManager __dbMgr; + ContextProvider *__provider; + Json __option; + }; +} + +#endif /* _CONTEXT_BATTERY_STATS_QUERIER_H_ */ diff --git a/src/battery-stats/RecentBatteryUsage.cpp b/src/battery-stats/RecentBatteryUsage.cpp new file mode 100644 index 0000000..0663650 --- /dev/null +++ b/src/battery-stats/RecentBatteryUsage.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BatteryMonitor.h" +#include "RecentBatteryUsage.h" + +using namespace ctx; + +RecentBatteryUsageProvider::RecentBatteryUsageProvider() : + BatteryStatsProvider(SUBJ_BATTERY_RECENT_USAGE) +{ +} + +RecentBatteryUsageProvider::~RecentBatteryUsageProvider() +{ +} + +int RecentBatteryUsageProvider::read(Json option, Json *requestResult) +{ + int resultSize; + bool hasLimit = option.get(NULL, KEY_RESULT_SIZE, &resultSize); + + BatteryStatsQuerier *querier = getQuerier(option); + IF_FAIL_RETURN(querier, ERR_OPERATION_FAILED); + + int error; + if (hasLimit) { + error = querier->queryRangeLimit(BatteryMonitor::getLastResetTime(), CURRENT_TIME, resultSize); + } else { + error = querier->queryRange(BatteryMonitor::getLastResetTime(), CURRENT_TIME); + } + IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Failed to get recent app battery usage"); + + return ERR_NONE; +} + + diff --git a/src/battery-stats/RecentBatteryUsage.h b/src/battery-stats/RecentBatteryUsage.h new file mode 100644 index 0000000..2cb7c54 --- /dev/null +++ b/src/battery-stats/RecentBatteryUsage.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CONTEXT_RECENT_BATTERY_USAGE_PROVIDER_H_ +#define _CONTEXT_RECENT_BATTERY_USAGE_PROVIDER_H_ + +#include "BatteryStatsProvider.h" + +namespace ctx { + + class RecentBatteryUsageProvider : public BatteryStatsProvider { + public: + RecentBatteryUsageProvider(); + ~RecentBatteryUsageProvider(); + + int read(Json option, Json *requestResult); + }; +} + +#endif /* _CONTEXT_RECENT_BATTERY_USAGE_PROVIDER_H_ */