Skip to content

Commit

Permalink
Merge pull request #44 from plundstr/master
Browse files Browse the repository at this point in the history
New plugin bootreasonlogger
  • Loading branch information
Pekka Lundstrom committed Dec 9, 2013
2 parents ce7ec51 + b3aaa4b commit 793d402
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 5 deletions.
17 changes: 15 additions & 2 deletions configure.ac
@@ -1,5 +1,5 @@
# Package name and version
AC_INIT(dsme, 0.64.1)
AC_INIT(dsme, 0.64.2)

AM_INIT_AUTOMAKE

Expand Down Expand Up @@ -135,14 +135,27 @@ AM_CONDITIONAL([WANT_PWRKEY_MONITOR], [test x$enable_pwrkeymonitor != xno])
#
AC_ARG_ENABLE([battery-tracker],
[AS_HELP_STRING([--disable-battery-tracker],
[disable hw thermal management (libbatterytracker)])],
[disable battery tracker (libbatterytracker)])],
[],
[enable_battery_tracker=yes])

AS_IF([test "x$enable_battery_tracker" != xno],
[AC_DEFINE([DSME_BATTERY_TRACKER], [1])])
AM_CONDITIONAL([WANT_BATTERY_TRACKER], [test x$enable_battery_tracker != xno])

#
# Bootreason logger
#
AC_ARG_ENABLE([bootreason-logger],
[AS_HELP_STRING([--disable-bootreason-logger],
[disable bootreason logger (libbootreasonlogger)])],
[],
[enable_bootreason_logger=yes])

AS_IF([test "x$enable_bootreason_logger" != xno],
[AC_DEFINE([DSME_BOOTREASON_LOGGER], [1])])
AM_CONDITIONAL([WANT_BOOTREASON_LOGGER], [test x$enable_bootreason_logger != xno])

#
# Compiler and linker flags
#
Expand Down
10 changes: 10 additions & 0 deletions modules/Makefile.am
Expand Up @@ -71,6 +71,10 @@ if WANT_BATTERY_TRACKER
pkglib_LTLIBRARIES += batterytracker.la
endif

if WANT_BOOTREASON_LOGGER
pkglib_LTLIBRARIES += bootreasonlogger.la
endif

startup_la_SOURCES = startup.c

# TODO: remove this
Expand Down Expand Up @@ -189,3 +193,9 @@ batterytracker_la_SOURCES = batterytracker.c
batterytracker_la_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) -D_GNU_SOURCE
batterytracker_la_LIBADD = $(GLIB_LIBS)
endif

if WANT_BOOTREASON_LOGGER
bootreasonlogger_la_SOURCES = bootreasonlogger.c
bootreasonlogger_la_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) -D_GNU_SOURCE
bootreasonlogger_la_LIBADD = $(GLIB_LIBS)
endif
270 changes: 270 additions & 0 deletions modules/bootreasonlogger.c
@@ -0,0 +1,270 @@
/**
@file bootreasonlogger.c
Log the system shutdown and powerup reasons.
<p>
Copyright (C) 2013 Jolla Oy.
@author Pekka Lundstrom <pekka.lundstrom@jolla.com>
This file is part of Dsme.
Dsme is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License
version 2.1 as published by the Free Software Foundation.
Dsme is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with Dsme. If not, see <http://www.gnu.org/licenses/>.
*/

#include "dbusproxy.h"
#include "dsme_dbus.h"

#include "dsme/modules.h"
#include "dsme/logging.h"

#include <dsme/state.h>
#include <dsme/protocol.h>

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>

#define BOOT_LOG_FILE "/var/log/systemboot.log"
#define PFIX "bootlogger: "
#define MAX_CMDLINE_LEN 1024

typedef enum {
SD_REASON_UNKNOWN,
SD_SW_REBOOT,
SD_SW_SHUTDOWN,
SD_DEVICE_OVERHEAT,
SD_BATTERY_EMPTY,
SD_USER_PWR_KEY,

SD_REASON_COUNT
} shutdown_reason_t;

static const char* const shutdown_reason_string[SD_REASON_COUNT] = {
"Reason Unknown",
"SW reboot request",
"SW shutdown request",
"Device overheated",
"Battery empty",
"User Power Key"
};

static shutdown_reason_t saved_shutdown_reason = SD_REASON_UNKNOWN;

/* Powerup reason is either in enviroment or in kernel commandline
* we will look for all these and in this order
*/
static const char *possible_pwrup_strings[] = {
"pwr_on_status",
"bootreason",
"bootup_reason",
"androidboot.mode",
0
};

static char pwrup_reason[80];

static const char * get_timestamp(void)
{
static const char default_date[] = "00000000_000000";
static char date_time[80];
time_t raw_time;
struct tm *timeinfo;
const char *timestamp = default_date;

if ((time(&raw_time) > 0) &&
((timeinfo = localtime(&raw_time)) != NULL) &&
(strftime(date_time, sizeof(date_time), "%Y%m%d_%H%M%S", timeinfo) > 0)) {
timestamp = date_time;
} else
dsme_log(LOG_ERR, PFIX"failed to get timestamp");

return timestamp;
}

static void write_log(const char *state, const char *reason)
{
FILE* f;
bool success = false;

f = fopen(BOOT_LOG_FILE, "a");
if (f) {
if ( fprintf(f, "%s %s %s\n", get_timestamp(), state, reason) > 0) {
success = true;
sync();
}
fclose(f);
}

if (! success) {
dsme_log(LOG_ERR, PFIX"can't write into %s", BOOT_LOG_FILE);
}
}


static int get_cmd_line_value(char* get_value, int max_len, const char* key)
{
FILE* cmdline_file;
char cmdline[MAX_CMDLINE_LEN];
int ret = -1;
int keylen;
char* key_and_value;
char* value;

cmdline_file = fopen("/proc/cmdline", "r");
if(!cmdline_file) {
dsme_log(LOG_ERR, PFIX"Could not open /proc/cmdline\n");
return -1;
}

if (fgets(cmdline, MAX_CMDLINE_LEN, cmdline_file)) {
key_and_value = strtok(cmdline, " ");
keylen = strlen(key);
while (key_and_value != NULL) {
if(!strncmp(key_and_value, key, keylen)) {
value = strtok(key_and_value, "=");
value = strtok(NULL, "=");
if (value) {
snprintf(get_value, max_len, "%s", value);
ret = strlen(get_value);
}
break;
}
key_and_value = strtok(NULL, " ");
}
}
fclose(cmdline_file);
return ret;
}

static char * get_powerup_reason_str(void)
{
char *env;
const char *search_key;
int i = 0;
char cmdvalue[80];

/* set default */
snprintf(pwrup_reason, sizeof(pwrup_reason), "Reason Unknown");

/* Powerup reason is either in enviroment or in kernel commandline
* we will look both and use first match
*/

while ((search_key = possible_pwrup_strings[i])) {
if ((env = getenv(search_key))) {
snprintf(pwrup_reason, sizeof(pwrup_reason),"%s=%s", search_key, env);
break;
} else if ((get_cmd_line_value(cmdvalue, sizeof(cmdvalue), search_key)) > 0) {
snprintf(pwrup_reason, sizeof(pwrup_reason),"%s=%s", search_key, cmdvalue);
break;
}
i++;
}
return pwrup_reason;
}


static void log_startup(void)
{
write_log("Startup: ", get_powerup_reason_str());
}

static void log_shutdown(void)
{
write_log("Shutdown:", shutdown_reason_string[saved_shutdown_reason]);
}

DSME_HANDLER(DSM_MSGTYPE_SET_BATTERY_STATE, conn, battery)
{
dsme_log(LOG_DEBUG,
PFIX"battery %s state received",
battery->empty ? "empty" : "not empty");

write_log("Received: battery ", battery->empty ? "empty" : "not empty");
if (battery->empty)
saved_shutdown_reason = SD_BATTERY_EMPTY;
else // Battery is no more empty. Shutdown won't happen
saved_shutdown_reason = SD_REASON_UNKNOWN;
}

DSME_HANDLER(DSM_MSGTYPE_SET_THERMAL_STATE, conn, msg)
{
dsme_log(LOG_DEBUG,
PFIX"%s state received",
msg->overheated ? "overheated" : "not overheated");

write_log("Received: device ", msg->overheated ? "overheated" : "not overheated");
if (msg->overheated)
saved_shutdown_reason = SD_DEVICE_OVERHEAT;
else // Device is no more overheated. Shutdown won't happen
saved_shutdown_reason = SD_REASON_UNKNOWN;
}

DSME_HANDLER(DSM_MSGTYPE_REBOOT_REQ, conn, msg)
{
dsme_log(LOG_DEBUG, PFIX"reboot request received");
if (saved_shutdown_reason == SD_REASON_UNKNOWN)
saved_shutdown_reason = SD_SW_REBOOT;
}

DSME_HANDLER(DSM_MSGTYPE_SHUTDOWN_REQ, conn, msg)
{
char* sender = endpoint_name(conn);

dsme_log(LOG_DEBUG, PFIX"shutdown request received from %s",
(sender ? sender : "(unknown)"));
if (saved_shutdown_reason == SD_REASON_UNKNOWN) {
if (sender && (strstr(sender, "/mce") != NULL))
saved_shutdown_reason = SD_USER_PWR_KEY;
else
saved_shutdown_reason = SD_SW_SHUTDOWN;
}
free(sender);
}

DSME_HANDLER(DSM_MSGTYPE_STATE_CHANGE_IND, conn, msg)
{
dsme_log(LOG_DEBUG, PFIX"Received new state %d", msg->state);
if (saved_shutdown_reason == SD_REASON_UNKNOWN) {
if (msg->state == DSME_STATE_SHUTDOWN)
saved_shutdown_reason = SD_SW_SHUTDOWN;
else if (msg->state == DSME_STATE_REBOOT)
saved_shutdown_reason = SD_SW_REBOOT;
}
}

module_fn_info_t message_handlers[] = {
DSME_HANDLER_BINDING(DSM_MSGTYPE_SHUTDOWN_REQ),
DSME_HANDLER_BINDING(DSM_MSGTYPE_REBOOT_REQ),
DSME_HANDLER_BINDING(DSM_MSGTYPE_SET_THERMAL_STATE),
DSME_HANDLER_BINDING(DSM_MSGTYPE_SET_BATTERY_STATE),
DSME_HANDLER_BINDING(DSM_MSGTYPE_STATE_CHANGE_IND),
{0}
};


void module_init(module_t* handle)
{
dsme_log(LOG_DEBUG, "bootreasonlogger.so loaded");
log_startup();
saved_shutdown_reason = SD_REASON_UNKNOWN;
}

void module_fini(void)
{
log_shutdown();
dsme_log(LOG_DEBUG, "bootreasonlogger.so unloaded");
}
3 changes: 3 additions & 0 deletions modules/startup.c
Expand Up @@ -82,6 +82,9 @@ const char *modules[] = {
"iphb.so",
"processwd.so",
"alarmtracker.so",
#ifdef DSME_BOOTREASON_LOGGER
"bootreasonlogger.so",
#endif
#ifdef DSME_BATTERY_TRACKER
"batterytracker.so",
#endif
Expand Down
4 changes: 2 additions & 2 deletions rpm/dsme.spec
Expand Up @@ -13,7 +13,7 @@ Name: dsme
# << macros

Summary: Device State Management Entity
Version: 0.64.1
Version: 0.64.2
Release: 0
Group: System/System Control
License: LGPLv2+
Expand All @@ -30,7 +30,7 @@ Requires(postun): systemd
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(dbus-glib-1)
BuildRequires: pkgconfig(libiphb) >= 1.1.0
BuildRequires: pkgconfig(libiphb)
BuildRequires: pkgconfig(dsme)
BuildRequires: pkgconfig(systemd)
BuildRequires: pkgconfig(mce) >= 1.12.3
Expand Down
2 changes: 1 addition & 1 deletion rpm/dsme.yaml
@@ -1,6 +1,6 @@
Name: dsme
Summary: Device State Management Entity
Version: 0.64.1
Version: 0.64.2
Release: 0
Group: System/System Control
License: LGPLv2+
Expand Down

0 comments on commit 793d402

Please sign in to comment.