2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
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.
24 #include <sys/types.h>
26 #include <app_manager.h>
27 #include <runtime_info.h>
29 #include "bm_plugin_interface.h"
30 #include "bm_cpu_util.h"
33 enum heart_cpu_status {
41 time_t last_checkpoint; // Need to get usage from this time
42 time_t used_time; // utime + stime
43 enum heart_cpu_status last_status;
46 static struct timeval last_requested_time;
48 static GDBusConnection *dbus_connection;
49 static GHashTable *running_app_list; // Key(appid), Val(app_status)
51 gint find_app_time(gconstpointer a, gconstpointer b)
53 const char *appid = (const char *)b;
54 const app_time_map_st1 *app_time = (const app_time_map_st1 *)a;
56 return g_strcmp0(appid, app_time->app_id);
59 void free_atm_st1(gpointer data)
61 app_time_map_st1 *atm = (app_time_map_st1 *)data;
71 bool is_running_app(const char *appid)
73 bool is_running = false;
74 int ret = app_manager_is_running(appid, &is_running);
75 if (ret != APP_MANAGER_ERROR_NONE) {
76 _E("app_manager_is_running failed (%d)", ret);
87 if (dbus_connection) {
88 g_object_unref(dbus_connection);
89 dbus_connection = NULL;
92 if (running_app_list) {
93 g_hash_table_destroy(running_app_list);
94 running_app_list = NULL;
98 return BM_PLUGIN_ERROR_NONE;
105 GError *g_err = NULL;
107 if (gettimeofday(&last_requested_time, NULL) != 0) {
108 _E("gettimeofday failed : %m");
112 dbus_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &g_err);
113 if (!dbus_connection) {
114 _E("g_bus_get_sync failed : %s", g_err->message ? g_err->message : NULL);
119 running_app_list = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
120 if (!running_app_list) {
121 _E("g_hash_table_new_full failed");
126 return BM_PLUGIN_ERROR_NONE;
132 return BM_PLUGIN_ERROR_OUT_OF_MEMORY;
135 int get_feature_data(bm_data_h *handle, bm_plugin_data_type_e type)
141 bm_cpu_st *usage = NULL;
145 GError *g_err = NULL;
146 GDBusMessage *msg_req, *msg_reply;
157 unsigned int utime, stime, pid, status;
160 struct app_status *app_status, *new_app_status;
162 process_cpu_usage_s *cpu_usage;
164 gpointer g_key, g_val;
167 app_time_map_st1 *app_time_map;
171 if (!handle || type != BM_DATA_TYPE_CPU) {
172 _E("Invalid argument");
173 return BM_PLUGIN_ERROR_INVALID_PARAMETER;
176 /* Get current time */
177 ret = gettimeofday(&tv, NULL);
179 _E("gettimeofday failed : %m");
182 return BM_PLUGIN_ERROR_OUT_OF_MEMORY;
185 /* Request for resourced to update HEART-CPU DB */
186 msg_req = g_dbus_message_new_method_call(
187 "org.tizen.resourced",
188 "/Org/Tizen/ResourceD/Logging",
189 "org.tizen.resourced.logging",
194 _E("g_dbus_message_new_method_call failed : %s", g_err->message ? g_err->message : NULL);
197 _E("g_dbus_message_new_method_call failed");
200 return BM_PLUGIN_ERROR_NOT_SUPPORTED;
203 msg_reply = g_dbus_connection_send_message_with_reply_sync(dbus_connection, msg_req, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &g_err);
205 g_object_unref(msg_reply);
208 _W("g_dbus_connection_send_message_with_reply_sync failed : %s", g_err->message ? g_err->message : NULL);
211 _W("g_dbus_connection_send_message_with_reply_sync failed");
214 /* Open HEART-CPU DB */
215 ret = sqlite3_open("/opt/usr/home/owner/.applications/dbspace/.resourced-heart-default.db", &db);
216 if (ret != SQLITE_OK) {
217 _E("sqlite3_open failed (%d)", ret);
220 return BM_PLUGIN_ERROR_NO_DATA;
223 /* Make usage data structure */
224 usage = (bm_cpu_st *)calloc(1, sizeof(bm_cpu_st));
229 return BM_PLUGIN_ERROR_OUT_OF_MEMORY;
232 /* Read data from HEART-CPU DB */
233 _I("Gather CPU usage : %ld ~ %ld", last_requested_time.tv_sec, tv.tv_sec);
234 snprintf(query, 128, "SELECT time,appid,data FROM cpu WHERE time >= %ld", last_requested_time.tv_sec);
235 ret = sqlite3_prepare_v2(db, query, -1, &stmt, 0);
236 while (sqlite3_step(stmt) == SQLITE_ROW) {
237 time = sqlite3_column_int(stmt, 0);
238 appid = (const char *)sqlite3_column_text(stmt, 1);
239 data = (const char *)sqlite3_column_text(stmt, 2);
240 sscanf(data, "%u %u %u %u", &utime, &stime, &pid, &status);
242 //_D("time(%u), appid(%s), utime(%u), stime(%u), pid(%u), status(%u)", time, appid, utime, stime, pid, status);
244 /* Ignore terminated app */
245 if (!is_running_app(appid)) {
246 _D("%s is already terminated", appid);
247 g_hash_table_remove(running_app_list, appid);
251 app_status = g_hash_table_lookup(running_app_list, appid);
253 /* Insert newly launched app in the running app list */
255 _D("%s is newly launched", appid);
256 new_app_status = malloc(sizeof(struct app_status));
257 if (!new_app_status) {
259 ret = BM_PLUGIN_ERROR_OUT_OF_MEMORY;
262 new_app_status->pid = pid;
263 new_app_status->last_checkpoint = time;
264 new_app_status->used_time = utime + stime;
265 new_app_status->last_status = status;
266 g_hash_table_insert(running_app_list, g_strdup(appid), new_app_status);
270 /* Initialize restarted app */
271 if (app_status->pid != pid) {
272 _D("%s is restarted", appid);
273 app_status->pid = pid;
274 app_status->last_checkpoint = time;
275 app_status->used_time = utime + stime;
276 app_status->last_status = status;
280 /* Ignore CPU unused app */
281 elapsed = utime + stime - app_status->used_time;
283 _D("%s doesn't use CPU. Ignore it", appid);
287 /* Accumulate used time */
288 _D("%s uses CPU (+%d)", appid, elapsed);
289 usage->cpuTicks += elapsed;
290 switch (app_status->last_status) {
292 usage->cpuTimeForeground += elapsed;
296 usage->cpuTimeBackground += elapsed;
300 /* Insert the app using CPU in the ATM list */
301 if (!g_slist_find_custom(usage->atm_list, appid, find_app_time)) {
302 app_time_map = malloc(sizeof(app_time_map_st1));
305 ret = BM_PLUGIN_ERROR_OUT_OF_MEMORY;
308 app_time_map->app_id = g_strdup(appid);
309 if (!app_time_map->app_id) {
310 _E("g_strdup failed");
311 ret = BM_PLUGIN_ERROR_OUT_OF_MEMORY;
314 app_time_map->time = tv.tv_sec - app_status->last_checkpoint;
315 if (app_time_map->time <= 0)
316 app_time_map->time = 1;
317 usage->atm_list = g_slist_append(usage->atm_list, app_time_map);
320 /* Update app status */
321 app_status->used_time = utime + stime;
322 app_status->last_status = status;
325 /* Update all running apps with current value */
326 g_hash_table_iter_init(&iter, running_app_list);
327 while (g_hash_table_iter_next(&iter, &g_key, &g_val)) {
328 appid = (const char *)g_key;
329 app_status = (struct app_status *)g_val;
331 /* Ignore terminated app */
332 if (!is_running_app(appid)) {
333 _D("%s is already terminated", appid);
334 g_hash_table_iter_remove(&iter);
338 /* Get latest CPU time */
339 ret = runtime_info_get_process_cpu_usage(&app_status->pid, 1, &cpu_usage);
340 if (ret != RUNTIME_INFO_ERROR_NONE) {
341 _E("runtime_info_get_process_cpu_usage for %u failed(%d)", app_status->pid, ret);
345 app_status->last_checkpoint = tv.tv_sec;
347 /* Ignore CPU unused app */
348 elapsed = cpu_usage->utime + cpu_usage->stime - app_status->used_time;
350 _D("%s doesn't use CPU. Ignore it", appid);
354 /* Update CPU time */
355 _D("%s uses CPU (+%d)", appid, elapsed);
356 usage->cpuTicks += elapsed;
357 switch (app_status->last_status) {
359 usage->cpuTimeForeground += elapsed;
363 usage->cpuTimeBackground += elapsed;
367 /* Insert the app using CPU in the ATM list */
368 if (!g_slist_find_custom(usage->atm_list, appid, find_app_time)) {
369 app_time_map = malloc(sizeof(app_time_map_st1));
372 ret = BM_PLUGIN_ERROR_OUT_OF_MEMORY;
375 app_time_map->app_id = g_strdup(appid);
376 if (!app_time_map->app_id) {
377 _E("g_strdup failed");
378 ret = BM_PLUGIN_ERROR_OUT_OF_MEMORY;
381 app_time_map->time = tv.tv_sec - last_requested_time.tv_sec;
382 if (app_time_map->time <= 0)
383 app_time_map->time = 1;
384 usage->atm_list = g_slist_append(usage->atm_list, app_time_map);
387 app_status->used_time = cpu_usage->utime + cpu_usage->stime;
392 /* Update last requested time */
393 last_requested_time.tv_sec = tv.tv_sec;
394 last_requested_time.tv_usec = tv.tv_usec;
399 _I("Succeed to get CPU usage");
400 ret = BM_PLUGIN_ERROR_NONE;
404 g_slist_free_full(usage->atm_list, free_atm_st1);
407 sqlite3_finalize(stmt);
414 static bm_api_st cpu_api = {
417 .get_feature_data = get_feature_data
420 int plugin_init(bm_api_st **api)
430 int plugin_deinit(void)
438 BM_PLUGIN_ADD(BM_PLUGIN_ID_CPU, NAME, AUTHOR, VERSION, plugin_init, plugin_deinit);