Relocate healthd extension from device/qcom/common

Project restructure to split modules from device/qcom/common.

Relocation of some files from device/qcom/common at
b5ce80cb1f60759a142a9338104d3adf3303ec0c.

Change-Id: I2314c240a07978bda98ece01a072437d306a8b1e
diff --git a/healthd_board_msm.cpp b/healthd_board_msm.cpp
new file mode 100644
index 0000000..5dc5ce8
--- /dev/null
+++ b/healthd_board_msm.cpp
@@ -0,0 +1,571 @@
+/*
+ *Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ *Redistribution and use in source and binary forms, with or without
+ *modification, are permitted provided that the following conditions are
+ *met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ *WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ *ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ *OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ *IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cutils/klog.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/android_reboot.h>
+#include <cutils/properties.h>
+#include <healthd.h>
+#include "minui/minui.h"
+#include "healthd_msm.h"
+#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
+
+#define HVDCP_CHARGER           "USB_HVDCP"
+#define HVDCP_BLINK_TYPE        2
+
+#define RED_LED_PATH            "/sys/class/leds/red/brightness"
+#define GREEN_LED_PATH          "/sys/class/leds/green/brightness"
+#define BLUE_LED_PATH           "/sys/class/leds/blue/brightness"
+#define RED_LED_BLINK_PATH      "/sys/class/leds/red/blink"
+#define GREEN_LED_BLINK_PATH    "/sys/class/leds/green/blink"
+#define BACKLIGHT_PATH          "/sys/class/backlight/panel0-backlight/brightness"
+
+#define CHARGING_ENABLED_PATH   "/sys/class/power_supply/battery/charging_enabled"
+#define CHARGER_TYPE_PATH       "/sys/class/power_supply/usb/type"
+#define BMS_READY_PATH          "/sys/class/power_supply/bms/soc_reporting_ready"
+#define BMS_BATT_INFO_PATH      "/sys/class/power_supply/bms/battery_info"
+#define BMS_BATT_INFO_ID_PATH   "/sys/class/power_supply/bms/battery_info_id"
+#define BMS_BATT_RES_ID_PATH    "/sys/class/power_supply/bms/resistance_id"
+#define PERSIST_BATT_INFO_PATH  "/persist/bms/batt_info.txt"
+
+#define CHGR_TAG                "charger"
+#define HEALTHD_TAG             "healthd_msm"
+#define LOGE(tag, x...) do { KLOG_ERROR(tag, x); } while (0)
+#define LOGW(tag, x...) do { KLOG_WARNING(tag, x); } while (0)
+#define LOGV(tag, x...) do { KLOG_DEBUG(tag, x); } while (0)
+
+enum {
+    RED_LED = 0x01 << 0,
+    GREEN_LED = 0x01 << 1,
+    BLUE_LED = 0x01 << 2,
+};
+
+enum batt_info_params {
+    BATT_INFO_NOTIFY = 0,
+    BATT_INFO_SOC,
+    BATT_INFO_RES_ID,
+    BATT_INFO_VOLTAGE,
+    BATT_INFO_TEMP,
+    BATT_INFO_FCC,
+    BATT_INFO_MAX,
+};
+
+struct led_ctl {
+    int color;
+    const char *path;
+};
+
+struct led_ctl leds[3] =
+    {{RED_LED, RED_LED_PATH},
+    {GREEN_LED, GREEN_LED_PATH},
+    {BLUE_LED, BLUE_LED_PATH}};
+
+#define HVDCP_COLOR_MAP         (RED_LED | GREEN_LED)
+
+struct soc_led_color_mapping {
+    int soc;
+    int color;
+};
+
+struct soc_led_color_mapping soc_leds[3] = {
+    {15, RED_LED},
+    {90, RED_LED | GREEN_LED},
+    {100, GREEN_LED},
+};
+
+static int batt_info_cached[BATT_INFO_MAX];
+static bool healthd_msm_err_log_once;
+static int8_t healthd_msm_log_en;
+static int8_t healthd_msm_store_params;
+
+static int write_file_int(char const* path, int value)
+{
+    int fd;
+    char buffer[20];
+    int rc = -1, bytes;
+
+    fd = open(path, O_WRONLY);
+    if (fd >= 0) {
+        bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
+        rc = write(fd, buffer, bytes);
+        close(fd);
+    }
+
+    return rc > 0 ? 0 : -1;
+}
+
+static int set_tricolor_led(int on, int color)
+{
+    int rc, i;
+    char buffer[10];
+
+    for (i = 0; i < (int)ARRAY_SIZE(leds); i++) {
+        if ((color & leds[i].color) && (access(leds[i].path, R_OK | W_OK) == 0)) {
+            rc = write_file_int(leds[i].path, on ? 255 : 0);
+            if (rc < 0)
+                return rc;
+        }
+    }
+
+    return 0;
+}
+
+static bool is_hvdcp_inserted()
+{
+    bool hvdcp = false;
+    char buff[12] = "\0";
+    int fd, cnt;
+
+    fd = open(CHARGER_TYPE_PATH, O_RDONLY);
+    if (fd >= 0) {
+        cnt = read(fd, buff, (sizeof(buff) - 1));
+        if (cnt > 0 && !strncmp(buff, HVDCP_CHARGER, 9))
+            hvdcp = true;
+        close(fd);
+    }
+
+    return hvdcp;
+}
+
+static int get_blink_led_for_hvdcp(void)
+{
+    int ret, rc = 0, bytes;
+    int red_blink_fd = -1, green_blink_fd = -1, type_fd = -1;
+    char buf[20];
+
+    type_fd = open(CHARGER_TYPE_PATH, O_RDONLY);
+
+    if (type_fd < 0) {
+        LOGE(CHGR_TAG, "Could not open USB type node\n");
+        return rc;
+    } else {
+        close(type_fd);
+        ret = write_file_int(GREEN_LED_BLINK_PATH, 0);
+        if (ret < 0) {
+            LOGE(CHGR_TAG, "Fail to write: %s\n", GREEN_LED_BLINK_PATH);
+        } else {
+            rc |= GREEN_LED;
+	}
+
+        ret = write_file_int(RED_LED_BLINK_PATH, 0);
+        if (ret < 0) {
+            LOGE(CHGR_TAG, "Fail to write: %s\n", RED_LED_BLINK_PATH);
+        } else {
+            rc |= RED_LED;
+	}
+    }
+
+    return rc;
+}
+
+#if QTI_BSP
+#define STR_LEN 8
+void healthd_board_mode_charger_draw_battery(
+                struct android::BatteryProperties *batt_prop)
+{
+    char cap_str[STR_LEN];
+    int x, y;
+    int str_len_px;
+    static int char_height = -1, char_width = -1;
+
+    if (char_height == -1 && char_width == -1)
+        gr_font_size(&char_width, &char_height);
+    snprintf(cap_str, (STR_LEN - 1), "%d%%", batt_prop->batteryLevel);
+    str_len_px = gr_measure(cap_str);
+    x = (gr_fb_width() - str_len_px) / 2;
+    y = (gr_fb_height() + char_height) / 2;
+    gr_color(0xa4, 0xc6, 0x39, 255);
+    gr_text(x, y, cap_str, 0);
+}
+#endif
+
+void healthd_board_mode_charger_battery_update(
+                struct android::BatteryProperties *batt_prop)
+{
+    static int blink_for_hvdcp = -1;
+    static int old_color = 0;
+    int i, color, soc, rc;
+    bool blink = false;
+
+    if (blink_for_hvdcp == -1)
+        blink_for_hvdcp = get_blink_led_for_hvdcp();
+
+    if ((blink_for_hvdcp > 0) && is_hvdcp_inserted())
+        blink = true;
+
+    soc = batt_prop->batteryLevel;
+
+    for (i = 0; i < ((int)ARRAY_SIZE(soc_leds) - 1); i++) {
+        if (soc < soc_leds[i].soc)
+            break;
+    }
+    color = soc_leds[i].color;
+
+    if (old_color != color) {
+        if ((color == HVDCP_COLOR_MAP) && blink) {
+            if (blink_for_hvdcp & RED_LED) {
+                rc = write_file_int(RED_LED_BLINK_PATH, HVDCP_BLINK_TYPE);
+                if (rc < 0) {
+                    LOGE(CHGR_TAG, "Fail to write: %s\n", RED_LED_BLINK_PATH);
+                    return;
+                }
+            }
+            if (blink_for_hvdcp & GREEN_LED) {
+                rc = write_file_int(GREEN_LED_BLINK_PATH, HVDCP_BLINK_TYPE);
+                if (rc < 0) {
+                    LOGE(CHGR_TAG, "Fail to write: %s\n", GREEN_LED_BLINK_PATH);
+                    return;
+                }
+            }
+        } else {
+                rc = set_tricolor_led(0, old_color);
+                if (rc < 0)
+                    LOGE(CHGR_TAG, "Error in setting old_color on tricolor_led\n");
+
+                rc = set_tricolor_led(1, color);
+                if (rc < 0)
+                    LOGE(CHGR_TAG, "Error in setting color on tricolor_led\n");
+
+                if (!rc) {
+                    old_color = color;
+                    LOGV(CHGR_TAG, "soc = %d, set led color 0x%x\n", soc, soc_leds[i].color);
+                }
+        }
+    }
+}
+
+#define BACKLIGHT_ON_LEVEL    100
+#define BACKLIGHT_OFF_LEVEL    0
+void healthd_board_mode_charger_set_backlight(bool en)
+{
+    int rc;
+
+    if (access(BACKLIGHT_PATH, R_OK | W_OK) != 0)
+    {
+        LOGW(CHGR_TAG, "Backlight control not support\n");
+        return;
+    }
+
+    rc = write_file_int(BACKLIGHT_PATH, en ? BACKLIGHT_ON_LEVEL :
+                BACKLIGHT_OFF_LEVEL);
+    if (rc < 0) {
+        LOGE(CHGR_TAG, "Could not write to backlight node : %s\n", strerror(errno));
+        return;
+    }
+
+    LOGV(CHGR_TAG, "set backlight status to %d\n", en);
+}
+
+static inline void get_healthd_props()
+{
+    healthd_msm_log_en = property_get_bool("persist.healthd_msm.log_en", 1);
+    healthd_msm_store_params =
+                property_get_bool("persist.healthd_msm.store_params", 0);
+}
+
+#define WAIT_BMS_READY_TIMES_MAX	200
+#define WAIT_BMS_READY_INTERVAL_USEC	200000
+void healthd_board_mode_charger_init()
+{
+    int ret;
+    char buff[8] = "\0";
+    int charging_enabled = 0;
+    int bms_ready = 0;
+    int wait_count = 0;
+    int fd;
+
+    /* check the charging is enabled or not */
+    fd = open(CHARGING_ENABLED_PATH, O_RDONLY);
+    if (fd < 0)
+        return;
+    ret = read(fd, buff, (sizeof(buff) - 1));
+    close(fd);
+    if (ret > 0) {
+        buff[ret] = '\0';
+        sscanf(buff, "%d\n", &charging_enabled);
+        LOGW(CHGR_TAG, "android charging is %s\n",
+                !!charging_enabled ? "enabled" : "disabled");
+        /* if charging is disabled, reboot and exit power off charging */
+        if (!charging_enabled)
+            android_reboot(ANDROID_RB_RESTART, 0, 0);
+    }
+    fd = open(BMS_READY_PATH, O_RDONLY);
+    if (fd < 0)
+            return;
+    while (1) {
+        ret = read(fd, buff, (sizeof(buff) - 1));
+        if (ret > 0) {
+            buff[ret] = '\0';
+            sscanf(buff, "%d\n", &bms_ready);
+        } else {
+            LOGE(CHGR_TAG, "read soc-ready failed, ret=%d\n", ret);
+            break;
+        }
+
+        if ((bms_ready > 0) || (wait_count++ > WAIT_BMS_READY_TIMES_MAX))
+            break;
+        usleep(WAIT_BMS_READY_INTERVAL_USEC);
+        lseek(fd, 0, SEEK_SET);
+    }
+    close(fd);
+    LOGV(CHGR_TAG, "Checking BMS SoC ready done %d!\n", bms_ready);
+}
+
+static void healthd_batt_info_notify()
+{
+    int rc, fd, id = 0;
+    int bms_ready = 0;
+    int wait_count = 0;
+    char buff[100] = "";
+    int batt_info[BATT_INFO_MAX];
+    char *ptr, *tmp, *temp_str;
+    char path_str[50] = "";
+    bool notify_bms = false;
+
+    if (!healthd_msm_store_params) {
+        return;
+    }
+
+    fd = open(PERSIST_BATT_INFO_PATH, O_RDONLY);
+    if (fd < 0) {
+        LOGW(HEALTHD_TAG, "Error in opening batt_info.txt, fd=%d\n", fd);
+        fd = creat(PERSIST_BATT_INFO_PATH, S_IRWXU);
+        if (fd < 0) {
+            LOGE(HEALTHD_TAG, "Couldn't create file, fd=%d errno=%s\n", fd,
+                 strerror(errno));
+            goto out;
+        }
+        LOGV(HEALTHD_TAG, "Created file %s\n", PERSIST_BATT_INFO_PATH);
+        close(fd);
+        goto out;
+    } else {
+        LOGV(HEALTHD_TAG, "opened %s\n", PERSIST_BATT_INFO_PATH);
+    }
+
+    rc = read(fd, buff, (sizeof(buff) - 1));
+    if (rc < 0) {
+        LOGE(HEALTHD_TAG, "Error in reading fd %d, rc=%d\n", fd, rc);
+        close(fd);
+        goto out;
+    }
+    close(fd);
+    buff[rc] = '\0';
+    temp_str = strtok_r(buff, ":", &ptr);
+    id = 1;
+    while (temp_str != NULL && id < BATT_INFO_MAX) {
+        batt_info[id++] = (int)strtol(temp_str, &tmp, 10);
+        temp_str = strtok_r(NULL, ":", &ptr);
+    }
+
+    if (id < BATT_INFO_MAX) {
+        LOGE(HEALTHD_TAG, "Read %d batt_info parameters\n", id);
+        goto out;
+    }
+
+    /* Send batt_info parameters to FG driver */
+    for (id = 1; id < BATT_INFO_MAX; id++) {
+        snprintf(path_str, sizeof(path_str), "%s", BMS_BATT_INFO_ID_PATH);
+        rc = write_file_int(path_str, id);
+        if (rc < 0) {
+            LOGE(HEALTHD_TAG, "Error in writing batt_info_id %d, rc=%d\n", id,
+                rc);
+            goto out;
+        }
+
+        snprintf(path_str, sizeof(path_str), "%s", BMS_BATT_INFO_PATH);
+        rc = write_file_int(path_str, batt_info[id]);
+        if (rc < 0) {
+            LOGE(HEALTHD_TAG, "Error in writing batt_info %d, rc=%d\n",
+                batt_info[id], rc);
+            goto out;
+        }
+    }
+
+    notify_bms = true;
+
+out:
+    fd = open(BMS_READY_PATH, O_RDONLY);
+    if (fd < 0) {
+        LOGE(HEALTHD_TAG, "Couldn't open %s\n", BMS_READY_PATH);
+        return;
+    }
+
+    /* Wait for soc_reporting_ready */
+    wait_count = 0;
+    memset(buff, 0, sizeof(buff));
+    while (1) {
+        rc = read(fd, buff, 1);
+        if (rc > 0) {
+            sscanf(buff, "%d\n", &bms_ready);
+        } else {
+            LOGE(HEALTHD_TAG, "read soc-ready failed, rc=%d\n", rc);
+            break;
+        }
+
+        if ((bms_ready > 0) || (wait_count++ > WAIT_BMS_READY_TIMES_MAX))
+            break;
+
+        usleep(WAIT_BMS_READY_INTERVAL_USEC);
+        lseek(fd, 0, SEEK_SET);
+    }
+    close(fd);
+
+    if (!bms_ready)
+        notify_bms = false;
+
+    if (!notify_bms) {
+        LOGE(HEALTHD_TAG, "Not notifying BMS\n");
+        return;
+    }
+
+    /* Notify FG driver */
+    snprintf(path_str, sizeof(path_str), "%s", BMS_BATT_INFO_ID_PATH);
+    rc = write_file_int(path_str, BATT_INFO_NOTIFY);
+    if (rc < 0) {
+        LOGE(HEALTHD_TAG, "Error in writing batt_info_id, rc=%d\n", rc);
+        return;
+    }
+
+    snprintf(path_str, sizeof(path_str), "%s", BMS_BATT_INFO_PATH);
+    rc = write_file_int(path_str, INT_MAX - 1);
+    if (rc < 0)
+        LOGE(HEALTHD_TAG, "Error in writing batt_info, rc=%d\n", rc);
+}
+
+void healthd_board_init(struct healthd_config*)
+{
+    // use defaults
+    get_healthd_props();
+    power_off_alarm_init();
+    healthd_batt_info_notify();
+}
+
+static void healthd_store_batt_props(const struct android::BatteryProperties* props)
+{
+    char buff[100];
+    int fd, rc, len, batteryId = 0;
+
+    if (!healthd_msm_store_params) {
+        return;
+    }
+
+    if (!props->batteryPresent) {
+        return;
+    }
+
+    if (props->batteryLevel == 0 || props->batteryVoltage == 0) {
+        return;
+    }
+
+    memset(buff, 0, sizeof(buff));
+    fd = open(BMS_BATT_RES_ID_PATH, O_RDONLY);
+    if (fd < 0) {
+        if (!healthd_msm_err_log_once) {
+            LOGE(HEALTHD_TAG, "Couldn't open %s\n", BMS_BATT_RES_ID_PATH);
+            healthd_msm_err_log_once = true;
+        }
+    } else {
+        rc = read(fd, buff, 6);
+        if (rc > 0) {
+            sscanf(buff, "%d\n", &batteryId);
+            batteryId /= 1000;
+        } else if (!healthd_msm_err_log_once) {
+            LOGE(HEALTHD_TAG, "reading batt_res_id failed, rc=%d\n", rc);
+            healthd_msm_err_log_once = true;
+        }
+    }
+
+    if (fd >= 0)
+        close(fd);
+
+    if (props->batteryLevel == batt_info_cached[BATT_INFO_SOC] &&
+        props->batteryVoltage == batt_info_cached[BATT_INFO_VOLTAGE] &&
+        props->batteryTemperature == batt_info_cached[BATT_INFO_TEMP] &&
+        props->batteryFullCharge == batt_info_cached[BATT_INFO_FCC] &&
+        batteryId == batt_info_cached[BATT_INFO_RES_ID])
+        return;
+
+    fd = open(PERSIST_BATT_INFO_PATH, O_RDWR | O_TRUNC);
+    if (fd < 0) {
+        /*
+         * Print the error just only once as this function can be called as
+         * long as the system is running and logs should not flood the console.
+         */
+        if (!healthd_msm_err_log_once) {
+            LOGE(HEALTHD_TAG, "Error in opening batt_info.txt, fd=%d\n", fd);
+            healthd_msm_err_log_once = true;
+        }
+        return;
+    }
+
+    len = snprintf(buff, sizeof(buff), "%d:%d:%d:%d:%d", props->batteryLevel,
+                   batteryId, props->batteryVoltage,
+                   props->batteryTemperature, props->batteryFullCharge);
+    if (len < 0) {
+        if (!healthd_msm_err_log_once) {
+            LOGE(HEALTHD_TAG, "Error in printing to buff, len=%d\n", len);
+            healthd_msm_err_log_once = true;
+        }
+        goto out;
+    }
+
+    buff[len] = '\0';
+    rc = write(fd, buff, sizeof(buff));
+    if (rc < 0) {
+        if (!healthd_msm_err_log_once) {
+            LOGE(HEALTHD_TAG, "Error in writing to batt_info.txt, rc=%d\n", rc);
+            healthd_msm_err_log_once = true;
+        }
+        goto out;
+    }
+
+    batt_info_cached[BATT_INFO_SOC] = props->batteryLevel;
+    batt_info_cached[BATT_INFO_RES_ID] = batteryId;
+    batt_info_cached[BATT_INFO_VOLTAGE] = props->batteryVoltage;
+    batt_info_cached[BATT_INFO_TEMP] = props->batteryTemperature;
+    batt_info_cached[BATT_INFO_FCC] = props->batteryFullCharge;
+
+out:
+    if (fd >= 0)
+        close(fd);
+}
+
+int healthd_board_battery_update(struct android::BatteryProperties* props)
+{
+    // return 0 to log periodic polled battery status to kernel log
+    healthd_store_batt_props(props);
+    if (healthd_msm_log_en)
+        return 0;
+    return 1;
+}