power: Convert to fully binderized 1.1 implementation

Based on commits c043816b3ceb8d8094c13f76341d4c86f09a44d1
and f3e845ce21adf40b4caa8982447b0bf99eeeee81
from AOSP device/google/wahoo.

Commit 1:
commit: c043816b3ceb8d8094c13f76341d4c86f09a44d1
author: Ahmed ElArabawy <arabawy@google.com>
date:   Wed Apr 12 09:50:07 2017 -0700

power hal: Add power HAL API 1.1 impl for Wahoo

Add a full binderized implementation for Power hal

Many subsystems (e.g.wifi) could be living on an
independent power island (sourced from VBatt directly)
and might even have their own dedicated XTAL to source
their clocks. Since these SOCs are capable of
autonomously operating (while the platform is in one
of the sleep states), they are still drawing power
from the VBatt. Hence it is critical to understand
the  (SOC) level low power statistics as well when
the battery level changes and be able to find any
correlation in event of unexpected battery drain.

This commit adds the support of the Power Hal 1.1
to wahoo based devices(that includes Muskie/walleye).
This includes the new api for wlan specific power stats

Bug: 29339696
Test: Manual
Change-Id: Iee4e38f2d9ced31f8b6a333b535fa1d9a302ec26
Signed-off-by: Ahmed ElArabawy <arabawy@google.com>

Commit 2:
commit: f3e845ce21adf40b4caa8982447b0bf99eeeee81
author: Ahmed ElArabawy <arabawy@google.com>
aate:   Wed May 24 15:28:04 2017 +0000

Re-introduce of POWER HAL API 1.1 impl for Wahoo

Power HAL 1.1 support for wahoo based devices was initially introduced in CL
ag/2098359
However, this caused a regression in application startup times due
to a bug in passing parameters for power hints on application launch
Hence, that CL was reverted in CL ag/2270791

This commit brings back the support of the Power Hal 1.1
to wahoo based devices. This includes the changes of the original CL
as will as a fix for the app startup time regression

The fix is similar to that in ag/1767023 (done for power HAL 1.0 default
implementation)
where a NULL is passed to the powerHint function when the passed data is
Zero
(instead of passing a pointer to the data). This enable the App Launch
power hints to work properly

The commit has been tested not to cause that regression

Bug: 62040325
Test: Performance Tests along with other tests

Change-Id: I29ce38b2de92c2b9ad878b0076288b689695b8a0
Signed-off-by: Ahmed ElArabawy <arabawy@google.com>
diff --git a/Android.mk b/Android.mk
index 6b9a28b..7c457d1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,16 +1,48 @@
+# Copyright (C) 2017 The Android Open Source Project
+# Copyright (C) 2017 The LineageOS Project
+#
+# 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.
+
 ifeq ($(call my-dir),$(call project-path-for,qcom-power))
 
 LOCAL_PATH := $(call my-dir)
 
 ifeq ($(call is-vendor-board-platform,QCOM),true)
 
-# HAL module implemenation stored in
-# hw/<POWERS_HARDWARE_MODULE_ID>.<ro.hardware>.so
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SHARED_LIBRARIES := liblog libcutils libdl libxml2
-LOCAL_SRC_FILES := power.c metadata-parser.c utils.c list.c hint-data.c powerhintparser.c
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libdl \
+    libxml2 \
+    libhidlbase \
+    libhidltransport \
+    libhardware \
+    libutils \
+    android.hardware.power@1.1
+
+LOCAL_SRC_FILES := \
+    service.cpp \
+    Power.cpp \
+    power-helper.c \
+    metadata-parser.c \
+    utils.c \
+    list.c \
+    hint-data.c \
+    powerhintparser.c
+
 LOCAL_C_INCLUDES := external/libxml2/include \
                     external/icu/icu4c/source/common
 
@@ -83,11 +115,13 @@
     LOCAL_CFLAGS += -DTAP_TO_WAKE_NODE=\"$(TARGET_TAP_TO_WAKE_NODE)\"
 endif
 
-LOCAL_MODULE := power.qcom
+LOCAL_MODULE := android.hardware.power@1.1-service-qti
+LOCAL_INIT_RC := android.hardware.power@1.1-service-qti.rc
 LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := qcom
 LOCAL_VENDOR_MODULE := true
 LOCAL_HEADER_LIBRARIES := libhardware_headers
-include $(BUILD_SHARED_LIBRARY)
+include $(BUILD_EXECUTABLE)
 
 endif
 
diff --git a/Power.cpp b/Power.cpp
new file mode 100644
index 0000000..186f325
--- /dev/null
+++ b/Power.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.power@1.1-service.wahoo"
+
+#include <android/log.h>
+#include <utils/Log.h>
+#include "Power.h"
+#include "power-common.h"
+#include "power-helper.h"
+
+/* RPM runs at 19.2Mhz. Divide by 19200 for msec */
+#define RPM_CLK 19200
+
+extern struct stat_pair rpm_stat_map[];
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::PowerHint;
+using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using ::android::hardware::power::V1_0::Status;
+using ::android::hardware::power::V1_1::PowerStateSubsystem;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+Power::Power() {
+    power_init();
+}
+
+// Methods from ::android::hardware::power::V1_0::IPower follow.
+Return<void> Power::setInteractive(bool interactive)  {
+    power_set_interactive(interactive ? 1 : 0);
+    return Void();
+}
+
+Return<void> Power::powerHint(PowerHint hint, int32_t data) {
+    power_hint(static_cast<power_hint_t>(hint), data ? (&data) : NULL);
+    return Void();
+}
+
+Return<void> Power::setFeature(Feature feature, bool activate)  {
+    set_feature(static_cast<feature_t>(feature), activate ? 1 : 0);
+    return Void();
+}
+
+Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
+#if 0 // we don't do anything with this
+    hidl_vec<PowerStatePlatformSleepState> states;
+    uint64_t stats[MAX_PLATFORM_STATS * MAX_RPM_PARAMS] = {0};
+    uint64_t *values;
+    struct PowerStatePlatformSleepState *state;
+    int ret;
+
+    states.resize(PLATFORM_SLEEP_MODES_COUNT);
+
+    ret = extract_platform_stats(stats);
+    if (ret != 0) {
+        states.resize(0);
+        goto done;
+    }
+
+    /* Update statistics for XO_shutdown */
+    state = &states[RPM_MODE_XO];
+    state->name = "XO_shutdown";
+    values = stats + (RPM_MODE_XO * MAX_RPM_PARAMS);
+
+    state->residencyInMsecSinceBoot = values[1];
+    state->totalTransitions = values[0];
+    state->supportedOnlyInSuspend = false;
+    state->voters.resize(XO_VOTERS);
+    for(size_t i = 0; i < XO_VOTERS; i++) {
+        int voter = i + XO_VOTERS_START;
+        state->voters[i].name = rpm_stat_map[voter].label;
+        values = stats + (voter * MAX_RPM_PARAMS);
+        state->voters[i].totalTimeInMsecVotedForSinceBoot = values[0] / RPM_CLK;
+        state->voters[i].totalNumberOfTimesVotedSinceBoot = values[1];
+    }
+
+    /* Update statistics for VMIN state */
+    state = &states[RPM_MODE_VMIN];
+    state->name = "VMIN";
+    values = stats + (RPM_MODE_VMIN * MAX_RPM_PARAMS);
+
+    state->residencyInMsecSinceBoot = values[1];
+    state->totalTransitions = values[0];
+    state->supportedOnlyInSuspend = false;
+    state->voters.resize(VMIN_VOTERS);
+    //Note: No filling of state voters since VMIN_VOTERS = 0
+
+done:
+    _hidl_cb(states, Status::SUCCESS);
+#endif
+    return Void();
+}
+
+static int get_wlan_low_power_stats(struct PowerStateSubsystem &subsystem) {
+
+    uint64_t stats[WLAN_POWER_PARAMS_COUNT] = {0};
+    struct PowerStateSubsystemSleepState *state;
+    int ret;
+
+    ret = extract_wlan_stats(stats);
+    if (ret)
+        return ret;
+
+    subsystem.name = "wlan";
+    subsystem.states.resize(WLAN_STATES_COUNT);
+
+    /* Update statistics for Active State */
+    state = &subsystem.states[WLAN_STATE_ACTIVE];
+    state->name = "Active";
+    state->residencyInMsecSinceBoot = stats[CUMULATIVE_TOTAL_ON_TIME_MS];
+    state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
+    state->lastEntryTimestampMs = 0; //FIXME need a new value from Qcom
+    state->supportedOnlyInSuspend = false;
+
+    /* Update statistics for Deep-Sleep state */
+    state = &subsystem.states[WLAN_STATE_DEEP_SLEEP];
+    state->name = "Deep-Sleep";
+    state->residencyInMsecSinceBoot = stats[CUMULATIVE_SLEEP_TIME_MS];
+    state->totalTransitions = stats[DEEP_SLEEP_ENTER_COUNTER];
+    state->lastEntryTimestampMs = stats[LAST_DEEP_SLEEP_ENTER_TSTAMP_MS];
+    state->supportedOnlyInSuspend = false;
+
+    return 0;
+}
+
+// Methods from ::android::hardware::power::V1_1::IPower follow.
+Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
+
+    hidl_vec<PowerStateSubsystem> subsystems;
+    int ret;
+
+    subsystems.resize(SUBSYSTEM_COUNT);
+
+    //We currently have only one Subsystem for WLAN
+    ret = get_wlan_low_power_stats(subsystems[SUBSYSTEM_WLAN]);
+    if (ret != 0)
+        goto done;
+
+    //Add query for other subsystems here
+
+done:
+    _hidl_cb(subsystems, Status::SUCCESS);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
diff --git a/Power.h b/Power.h
new file mode 100644
index 0000000..8a64800
--- /dev/null
+++ b/Power.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * 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 ANDROID_HARDWARE_POWER_V1_1_POWER_H
+#define ANDROID_HARDWARE_POWER_V1_1_POWER_H
+
+#include <android/hardware/power/1.1/IPower.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <hardware/power.h>
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::PowerHint;
+using ::android::hardware::power::V1_1::IPower;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct Power : public IPower {
+    // Methods from ::android::hardware::power::V1_0::IPower follow.
+
+    Power();
+
+    Return<void> setInteractive(bool interactive) override;
+    Return<void> powerHint(PowerHint hint, int32_t data) override;
+    Return<void> setFeature(Feature feature, bool activate) override;
+    Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::power::V1_1::IPower follow.
+    Return<void> getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace power
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_POWER_V1_1_POWER_H
diff --git a/android.hardware.power@1.1-service-qti.rc b/android.hardware.power@1.1-service-qti.rc
new file mode 100644
index 0000000..232b1d8
--- /dev/null
+++ b/android.hardware.power@1.1-service-qti.rc
@@ -0,0 +1,4 @@
+service power-hal-1-1 /vendor/bin/hw/android.hardware.power@1.1-service-qti
+    class hal
+    user system
+    group system
diff --git a/power-8996.c b/power-8996.c
index a0b6be9..c0ad481 100644
--- a/power-8996.c
+++ b/power-8996.c
@@ -47,7 +47,6 @@
 #include "performance.h"
 #include "power-common.h"
 
-pthread_mutex_t camera_hint_mutex = PTHREAD_MUTEX_INITIALIZER;
 static int display_hint_sent;
 static int camera_hint_ref_count;
 
@@ -101,25 +100,21 @@
                 0x41420000, 0x5A, 0x41400100, 0x4, 0x41410100, 0x5F, 0x41414100, 0x22C, 0x41420100, 0x5A,
                 0x41810000, 0x9C4, 0x41814000, 0x32, 0x4180C000, 0x0, 0x41820000, 0xA};
 
-            pthread_mutex_lock(&camera_hint_mutex);
             camera_hint_ref_count++;
             if (camera_hint_ref_count == 1) {
                 perform_hint_action(video_encode_metadata.hint_id,
                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
             }
-            pthread_mutex_unlock(&camera_hint_mutex);
             ALOGI("Video Encode hint start");
             return HINT_HANDLED;
         }
     } else if (video_encode_metadata.state == 0) {
         if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
-            pthread_mutex_lock(&camera_hint_mutex);
             camera_hint_ref_count--;
             if (!camera_hint_ref_count) {
                 undo_hint_action(video_encode_metadata.hint_id);
             }
-            pthread_mutex_unlock(&camera_hint_mutex);
 
             ALOGI("Video Encode hint stop");
             return HINT_HANDLED;
@@ -128,7 +123,7 @@
     return HINT_NONE;
 }
 
-int power_hint_override(struct power_module *UNUSED(module), power_hint_t hint, void *data)
+int power_hint_override(power_hint_t hint, void *data)
 {
     int ret_val = HINT_NONE;
     switch(hint) {
@@ -141,7 +136,7 @@
     return ret_val;
 }
 
-int set_interactive_override(struct power_module *UNUSED(module), int on)
+int set_interactive_override(int on)
 {
     return HINT_HANDLED; /* Don't excecute this code path, not in use */
     char governor[80];
diff --git a/power-8998.c b/power-8998.c
index cf806c9..6dde050 100644
--- a/power-8998.c
+++ b/power-8998.c
@@ -69,7 +69,6 @@
                                            { VR_MODE, VR_MODE_HINT },
                                            { VR_SUSTAINED_MODE, VR_MODE_SUSTAINED_PERF_HINT } };
 
-static pthread_mutex_t perf_mode_switch_lock = PTHREAD_MUTEX_INITIALIZER;
 static int current_mode = NORMAL_MODE;
 
 static inline  int get_perfd_hint_id(perf_mode_type_t type) {
@@ -110,20 +109,16 @@
 
 static int process_perf_hint(void *data, perf_mode_type_t mode) {
 
-    pthread_mutex_lock(&perf_mode_switch_lock);
-
     // enable
     if (data){
         ALOGI("Enable request for mode: 0x%x", mode);
         // check if mode is current mode
         if ( current_mode & mode ) {
-            pthread_mutex_unlock(&perf_mode_switch_lock);
             ALOGD("Mode 0x%x already enabled", mode);
             return HINT_HANDLED;
         }
         // enable requested mode
         if ( 0 != switch_mode(current_mode | mode)) {
-            pthread_mutex_unlock(&perf_mode_switch_lock);
             ALOGE("Couldn't enable mode 0x%x", mode);
             return HINT_NONE;
         }
@@ -134,13 +129,11 @@
         ALOGI("Disable request for mode: 0x%x", mode);
         // check if mode is enabled
         if ( !(current_mode & mode) ) {
-            pthread_mutex_unlock(&perf_mode_switch_lock);
             ALOGD("Mode 0x%x already disabled", mode);
             return HINT_HANDLED;
         }
         //disable requested mode
         if ( 0 != switch_mode(current_mode & ~mode)) {
-            pthread_mutex_unlock(&perf_mode_switch_lock);
             ALOGE("Couldn't disable mode 0x%x", mode);
             return HINT_NONE;
         }
@@ -148,7 +141,6 @@
         ALOGI("Current mode is 0x%x", current_mode);
     }
 
-    pthread_mutex_unlock(&perf_mode_switch_lock);
     return HINT_HANDLED;
 }
 
@@ -193,7 +185,7 @@
     return HINT_NONE;
 }
 
-int power_hint_override(struct power_module *UNUSED(module), power_hint_t hint, void *data)
+int power_hint_override(power_hint_t hint, void *data)
 {
     int ret_val = HINT_NONE;
     switch(hint) {
@@ -207,11 +199,9 @@
             ret_val = process_perf_hint(data, VR_MODE);
             break;
         case POWER_HINT_INTERACTION:
-            pthread_mutex_lock(&perf_mode_switch_lock);
             if (current_mode != NORMAL_MODE) {
                 ret_val = HINT_HANDLED;
             }
-            pthread_mutex_unlock(&perf_mode_switch_lock);
             break;
         default:
             break;
@@ -219,7 +209,7 @@
     return ret_val;
 }
 
-int set_interactive_override(struct power_module *UNUSED(module), int UNUSED(on))
+int set_interactive_override(int UNUSED(on))
 {
     return HINT_HANDLED; /* Don't excecute this code path, not in use */
 }
diff --git a/power-feature.h b/power-feature.h
index 595e3dd..9f3dfb3 100644
--- a/power-feature.h
+++ b/power-feature.h
@@ -19,6 +19,6 @@
 
 #include <hardware/power.h>
 
-void set_device_specific_feature(struct power_module *module, feature_t feature, int state);
+void set_device_specific_feature(feature_t feature, int state);
 
 #endif
diff --git a/power.c b/power-helper.c
similarity index 83%
rename from power.c
rename to power-helper.c
index 4ba5a55..1e19c7d 100644
--- a/power.c
+++ b/power-helper.c
@@ -40,7 +40,6 @@
 
 #define LOG_TAG "QCOM PowerHAL"
 #include <log/log.h>
-#include <hardware/hardware.h>
 #include <hardware/power.h>
 
 #include "utils.h"
@@ -49,6 +48,25 @@
 #include "performance.h"
 #include "power-common.h"
 #include "power-feature.h"
+#include "power-helper.h"
+
+#ifndef WLAN_POWER_STAT
+#define WLAN_POWER_STAT "/d/wlan0/power_stats"
+#endif
+
+#define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
+#define LINE_SIZE 128
+
+const char *wlan_power_stat_params[] = {
+    "cumulative_sleep_time_ms",
+    "cumulative_total_on_time_ms",
+    "deep_sleep_enter_counter",
+    "last_deep_sleep_enter_tstamp_ms"
+};
+
+struct stat_pair wlan_stat_map[] = {
+    { WLAN_POWER_DEBUG_STATS, "POWER DEBUG STATS", wlan_power_stat_params, ARRAY_SIZE(wlan_power_stat_params) },
+};
 
 static int saved_dcvs_cpu0_slack_max = -1;
 static int saved_dcvs_cpu0_slack_min = -1;
@@ -59,14 +77,7 @@
 static int display_hint_sent;
 int display_boost;
 
-static int power_device_open(const hw_module_t* module, const char* name,
-        hw_device_t** device);
-
-static struct hw_module_methods_t power_module_methods = {
-    .open = power_device_open,
-};
-
-static void power_init(struct power_module *UNUSED(module))
+void power_init(void)
 {
     ALOGI("QCOM power HAL initing.");
 
@@ -193,8 +204,7 @@
     }
 }
 
-int __attribute__ ((weak)) power_hint_override(struct power_module *UNUSED(module),
-                                               power_hint_t UNUSED(hint),
+int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
                                                void *UNUSED(data))
 {
     return HINT_NONE;
@@ -203,11 +213,10 @@
 /* Declare function before use */
 void interaction(int duration, int num_args, int opt_list[]);
 
-static void power_hint(struct power_module *module, power_hint_t hint,
-        void *data)
+void power_hint(power_hint_t hint, void *data)
 {
     /* Check if this hint has been overridden. */
-    if (power_hint_override(module, hint, data) == HINT_HANDLED) {
+    if (power_hint_override(hint, data) == HINT_HANDLED) {
         /* The power_hint has been handled. We can skip the rest. */
         return;
     }
@@ -238,13 +247,12 @@
     }
 }
 
-int __attribute__ ((weak)) set_interactive_override(struct power_module *UNUSED(module),
-                                                    int UNUSED(on))
+int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
 {
     return HINT_NONE;
 }
 
-void set_interactive(struct power_module *module, int on)
+void power_set_interactive(int on)
 {
     char governor[80];
     char tmp_str[NODE_MAX];
@@ -259,7 +267,7 @@
         perf_hint_enable(VENDOR_HINT_DISPLAY_ON, 0);
     }
 
-    if (set_interactive_override(module, on) == HINT_HANDLED) {
+    if (set_interactive_override(on) == HINT_HANDLED) {
         return;
     }
 
@@ -457,12 +465,11 @@
     saved_interactive_mode = !!on;
 }
 
-void __attribute__((weak)) set_device_specific_feature(struct power_module *module __unused,
-                                            feature_t feature __unused, int state __unused)
+void __attribute__((weak)) set_device_specific_feature(feature_t UNUSED(feature), int UNUSED(state))
 {
 }
 
-static void set_feature(struct power_module *module, feature_t feature, int state)
+void set_feature(feature_t feature, int state)
 {
     switch (feature) {
 #ifdef TAP_TO_WAKE_NODE
@@ -473,60 +480,79 @@
         default:
             break;
     }
-    set_device_specific_feature(module, feature, state);
+    set_device_specific_feature(feature, state);
 }
 
-static int power_device_open(const hw_module_t* module, const char* name,
-        hw_device_t** device)
-{
-    int status = -EINVAL;
-    if (module && name && device) {
-        if (!strcmp(name, POWER_HARDWARE_MODULE_ID)) {
-            power_module_t *dev = (power_module_t *)malloc(sizeof(*dev));
-
-            if(dev) {
-                memset(dev, 0, sizeof(*dev));
-
-                if(dev) {
-                    /* initialize the fields */
-                    dev->common.module_api_version = POWER_MODULE_API_VERSION_0_3;
-                    dev->common.tag = HARDWARE_DEVICE_TAG;
-                    dev->init = power_init;
-                    dev->powerHint = power_hint;
-                    dev->setInteractive = set_interactive;
-                    /* At the moment we support 0.3 APIs */
-                    dev->setFeature = set_feature,
-                        dev->get_number_of_platform_modes = NULL,
-                        dev->get_platform_low_power_stats = NULL,
-                        dev->get_voter_list = NULL,
-                        *device = (hw_device_t*)dev;
-                    status = 0;
-                } else {
-                    status = -ENOMEM;
-                }
-            }
-            else {
-                status = -ENOMEM;
+static int parse_stats(const char **params, size_t params_size,
+                       uint64_t *list, FILE *fp) {
+    ssize_t nread;
+    size_t len = LINE_SIZE;
+    char *line;
+    size_t params_read = 0;
+    size_t i;
+    line = malloc(len);
+    if (!line) {
+        ALOGE("%s: no memory to hold line", __func__);
+        return -ENOMEM;
+    }
+    while ((params_read < params_size) &&
+        (nread = getline(&line, &len, fp) > 0)) {
+        char *key = line + strspn(line, " \t");
+        char *value = strchr(key, ':');
+        if (!value || (value > (line + len)))
+            continue;
+        *value++ = '\0';
+        for (i = 0; i < params_size; i++) {
+            if (!strcmp(key, params[i])) {
+                list[i] = strtoull(value, NULL, 0);
+                params_read++;
+                break;
             }
         }
     }
-
-    return status;
+    free(line);
+    return 0;
 }
 
-struct power_module HAL_MODULE_INFO_SYM = {
-    .common = {
-        .tag = HARDWARE_MODULE_TAG,
-        .module_api_version = POWER_MODULE_API_VERSION_0_3,
-        .hal_api_version = HARDWARE_HAL_API_VERSION,
-        .id = POWER_HARDWARE_MODULE_ID,
-        .name = "QCOM Power HAL",
-        .author = "Qualcomm",
-        .methods = &power_module_methods,
-    },
+static int extract_stats(uint64_t *list, char *file,
+                         struct stat_pair *map, size_t map_size) {
+    FILE *fp;
+    ssize_t read;
+    size_t len = LINE_SIZE;
+    char *line;
+    size_t i, stats_read = 0;
+    int ret = 0;
+    fp = fopen(file, "re");
+    if (fp == NULL) {
+        ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
+        return -errno;
+    }
+    line = malloc(len);
+    if (!line) {
+        ALOGE("%s: no memory to hold line", __func__);
+        fclose(fp);
+        return -ENOMEM;
+    }
+    while ((stats_read < map_size) && (read = getline(&line, &len, fp) != -1)) {
+        size_t begin = strspn(line, " \t");
+        for (i = 0; i < map_size; i++) {
+            if (!strncmp(line + begin, map[i].label, strlen(map[i].label))) {
+                stats_read++;
+                break;
+            }
+        }
+        if (i == map_size)
+            continue;
+        ret = parse_stats(map[i].parameters, map[i].num_parameters,
+                          &list[map[i].stat * MAX_RPM_PARAMS], fp);
+        if (ret < 0)
+            break;
+    }
+    free(line);
+    fclose(fp);
+    return ret;
+}
 
-    .init = power_init,
-    .powerHint = power_hint,
-    .setInteractive = set_interactive,
-    .setFeature = set_feature,
-};
+int extract_wlan_stats(uint64_t *list) {
+    return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map));
+}
diff --git a/power-helper.h b/power-helper.h
new file mode 100644
index 0000000..d7862c7
--- /dev/null
+++ b/power-helper.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012-2017, 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.
+ */
+
+#ifndef __POWER_HELPER_H__
+#define __POWER_HELPER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hardware/power.h"
+
+
+enum stats_type {
+    //WLAN Stats
+    WLAN_POWER_DEBUG_STATS = 0,
+    MAX_WLAN_STATS,
+};
+
+enum subsystem_type {
+    SUBSYSTEM_WLAN = 0,
+
+    //Don't add any lines after this line
+    SUBSYSTEM_COUNT
+};
+
+enum wlan_sleep_states {
+    WLAN_STATE_ACTIVE = 0,
+    WLAN_STATE_DEEP_SLEEP,
+
+    //Don't add any lines after this line
+    WLAN_STATES_COUNT
+};
+
+enum wlan_power_params {
+    CUMULATIVE_SLEEP_TIME_MS = 0,
+    CUMULATIVE_TOTAL_ON_TIME_MS,
+    DEEP_SLEEP_ENTER_COUNTER,
+    LAST_DEEP_SLEEP_ENTER_TSTAMP_MS,
+
+    //Don't add any lines after this line
+    WLAN_POWER_PARAMS_COUNT
+};
+
+
+#define MAX_RPM_PARAMS 2
+#define XO_VOTERS (MAX_PLATFORM_STATS - XO_VOTERS_START)
+#define VMIN_VOTERS 0
+
+struct stat_pair {
+    enum stats_type stat;
+    const char *label;
+    const char **parameters;
+    size_t num_parameters;
+};
+
+
+void power_init(void);
+void power_hint(power_hint_t hint, void *data);
+void power_set_interactive(int on);
+void set_feature(feature_t feature, int state);
+int extract_wlan_stats(uint64_t *list);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__POWER_HELPER_H__
diff --git a/service.cpp b/service.cpp
new file mode 100644
index 0000000..d119052
--- /dev/null
+++ b/service.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.power@1.1-service-qti"
+
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hardware/power.h>
+#include "Power.h"
+
+using android::sp;
+using android::status_t;
+using android::OK;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::V1_1::IPower;
+using android::hardware::power::V1_1::implementation::Power;
+
+int main() {
+
+    status_t status;
+    android::sp<IPower> service = nullptr;
+
+    ALOGI("Power HAL Service 1.1 for QCOM is starting.");
+
+    service = new Power();
+    if (service == nullptr) {
+        ALOGE("Can not create an instance of Power HAL Iface, exiting.");
+
+        goto shutdown;
+    }
+
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status = service->registerAsService();
+    if (status != OK) {
+        ALOGE("Could not register service for Power HAL Iface (%d).", status);
+        goto shutdown;
+    }
+
+    ALOGI("Power Service is ready");
+    joinRpcThreadpool();
+    //Should not pass this line
+
+shutdown:
+    // In normal operation, we don't expect the thread pool to exit
+
+    ALOGE("Power Service is shutting down");
+    return 1;
+}
diff --git a/utils.c b/utils.c
index 0456377..02c15e3 100644
--- a/utils.c
+++ b/utils.c
@@ -39,6 +39,7 @@
 #include "list.h"
 #include "hint-data.h"
 #include "power-common.h"
+#include "power-helper.h"
 
 #define LOG_TAG "QCOM PowerHAL"
 #include <log/log.h>