From c043816b3ceb8d8094c13f76341d4c86f09a44d1 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Wed, 12 Apr 2017 09:50:07 -0700 Subject: [PATCH] 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 --- device.mk | 4 +- manifest.xml | 2 +- power/Android.mk | 46 +++-- power/Power.cpp | 171 +++++++++++++++++ power/Power.h | 44 +++++ ...ndroid.hardware.power@1.1-service.wahoo.rc | 4 + power/power-8998.c | 23 +-- power/{power.c => power-helper.c} | 175 +++--------------- power/power-helper.h | 108 +++++++++++ power/service.cpp | 68 +++++++ sepolicy/file.te | 1 + sepolicy/file_contexts | 4 +- sepolicy/genfs_contexts | 1 + sepolicy/hal_power_default.te | 6 + sepolicy/hal_wifi_default.te | 7 + sepolicy/kernel.te | 1 + 16 files changed, 480 insertions(+), 185 deletions(-) create mode 100644 power/Power.cpp create mode 100644 power/Power.h create mode 100644 power/android.hardware.power@1.1-service.wahoo.rc rename power/{power.c => power-helper.c} (78%) create mode 100644 power/power-helper.h create mode 100644 power/service.cpp diff --git a/device.mk b/device.mk index 896c8dac..4c99a45d 100755 --- a/device.mk +++ b/device.mk @@ -156,9 +156,7 @@ PRODUCT_COPY_FILES += \ # power HAL PRODUCT_PACKAGES += \ - power.$(PRODUCT_HARDWARE) \ - android.hardware.power@1.0-impl \ - android.hardware.power@1.0-service + android.hardware.power@1.1-service.wahoo PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/powerhint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/powerhint.xml diff --git a/manifest.xml b/manifest.xml index 0ec24ab0..3752997e 100644 --- a/manifest.xml +++ b/manifest.xml @@ -133,7 +133,7 @@ android.hardware.power hwbinder - 1.0 + 1.1 IPower default diff --git a/power/Android.mk b/power/Android.mk index a9b07d55..1788d0b6 100644 --- a/power/Android.mk +++ b/power/Android.mk @@ -1,26 +1,48 @@ +# Copyright (C) 2017 The Android Open Source 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. + LOCAL_PATH := $(call my-dir) -ifeq ($(call is-vendor-board-platform,QCOM),true) - -# HAL module implemenation stored in -# hw/..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_PROPRIETARY_MODULE := true +LOCAL_MODULE_OWNER := qcom +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE := android.hardware.power@1.1-service.wahoo +LOCAL_INIT_RC := android.hardware.power@1.1-service.wahoo.rc +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 -ifeq ($(call is-board-platform-in-list,msm8998), true) +# Include target-specific files. LOCAL_SRC_FILES += power-8998.c -endif + # Enable interaction boost all the time LOCAL_CFLAGS += -DINTERACTION_BOOST -LOCAL_MODULE := power.$(TARGET_DEVICE) -LOCAL_MODULE_TAGS := optional -include $(BUILD_SHARED_LIBRARY) +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libxml2 \ + libhidlbase \ + libhidltransport \ + libhardware \ + libutils \ + android.hardware.power@1.1 \ -endif +include $(BUILD_EXECUTABLE) diff --git a/power/Power.cpp b/power/Power.cpp new file mode 100644 index 00000000..1776690c --- /dev/null +++ b/power/Power.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2016 The Android Open Source 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 +#include +#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 Power::setInteractive(bool interactive) { + power_set_interactive(interactive ? 1 : 0); + return Void(); +} + +Return Power::powerHint(PowerHint hint, int32_t data) { + int32_t param = data; + power_hint(static_cast(hint), ¶m); + return Void(); +} + +Return Power::setFeature(Feature /*feature*/, bool /*activate*/) { + //Nothing to do + return Void(); +} + +Return Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) { + + hidl_vec 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); + 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 Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) { + + hidl_vec 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/Power.h b/power/Power.h new file mode 100644 index 00000000..9a1e1bf7 --- /dev/null +++ b/power/Power.h @@ -0,0 +1,44 @@ +#ifndef ANDROID_HARDWARE_POWER_V1_1_POWER_H +#define ANDROID_HARDWARE_POWER_V1_1_POWER_H + +#include +#include +#include +#include + +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 setInteractive(bool interactive) override; + Return powerHint(PowerHint hint, int32_t data) override; + Return setFeature(Feature feature, bool activate) override; + Return getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override; + + // Methods from ::android::hardware::power::V1_1::IPower follow. + Return 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/power/android.hardware.power@1.1-service.wahoo.rc b/power/android.hardware.power@1.1-service.wahoo.rc new file mode 100644 index 00000000..064cf35a --- /dev/null +++ b/power/android.hardware.power@1.1-service.wahoo.rc @@ -0,0 +1,4 @@ +service power-hal-1-1 /vendor/bin/hw/android.hardware.power@1.1-service.wahoo + class hal + user system + group system diff --git a/power/power-8998.c b/power/power-8998.c index ff3e0e66..69add280 100644 --- a/power/power-8998.c +++ b/power/power-8998.c @@ -57,7 +57,6 @@ static int launch_handle = 0; static int sustained_performance_mode = 0; static int vr_mode = 0; static int launch_mode = 0; -static pthread_mutex_t s_interaction_lock = PTHREAD_MUTEX_INITIALIZER; #define CHECK_HANDLE(x) (((x)>0) && ((x)!=-1)) static struct timespec s_previous_boost_timespec; @@ -71,20 +70,17 @@ static int process_sustained_perf_hint(void *data) int *resource_values = NULL; int resources = 0; - pthread_mutex_lock(&s_interaction_lock); if (data && sustained_performance_mode == 0) { if (vr_mode == 0) { // Sustained mode only. resource_values = getPowerhint(SUSTAINED_PERF_HINT_ID, &resources); if (!resource_values) { ALOGE("Can't get sustained perf hints from xml "); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } sustained_mode_handle = interaction_with_handle( sustained_mode_handle, duration, resources, resource_values); if (!CHECK_HANDLE(sustained_mode_handle)) { ALOGE("Failed interaction_with_handle for sustained_mode_handle"); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } } else if (vr_mode == 1) { // Sustained + VR mode. @@ -92,14 +88,12 @@ static int process_sustained_perf_hint(void *data) resource_values = getPowerhint(VR_MODE_SUSTAINED_PERF_HINT_ID, &resources); if (!resource_values) { ALOGE("Can't get VR mode sustained perf hints from xml "); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } sustained_mode_handle = interaction_with_handle( sustained_mode_handle, duration, resources, resource_values); if (!CHECK_HANDLE(sustained_mode_handle)) { ALOGE("Failed interaction_with_handle for sustained_mode_handle"); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } } @@ -110,20 +104,17 @@ static int process_sustained_perf_hint(void *data) resource_values = getPowerhint(VR_MODE_HINT_ID, &resources); if (!resource_values) { ALOGE("Can't get VR mode perf hints from xml "); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } vr_mode_handle = interaction_with_handle( vr_mode_handle, duration, resources, resource_values); if (!CHECK_HANDLE(vr_mode_handle)) { ALOGE("Failed interaction_with_handle for vr_mode_handle"); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } } sustained_performance_mode = 0; } - pthread_mutex_unlock(&s_interaction_lock); return HINT_HANDLED; } @@ -133,20 +124,17 @@ static int process_vr_mode_hint(void *data) int *resource_values = NULL; int resources = 0; - pthread_mutex_lock(&s_interaction_lock); if (data && vr_mode == 0) { if (sustained_performance_mode == 0) { // VR mode only. resource_values = getPowerhint(VR_MODE_HINT_ID, &resources); if (!resource_values) { ALOGE("Can't get VR mode perf hints from xml "); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } vr_mode_handle = interaction_with_handle( vr_mode_handle, duration, resources, resource_values); if (!CHECK_HANDLE(vr_mode_handle)) { ALOGE("Failed interaction_with_handle for vr_mode_handle"); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } } else if (sustained_performance_mode == 1) { // Sustained + VR mode. @@ -154,14 +142,12 @@ static int process_vr_mode_hint(void *data) resource_values = getPowerhint(VR_MODE_SUSTAINED_PERF_HINT_ID, &resources); if (!resource_values) { ALOGE("Can't get VR mode sustained perf hints from xml "); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } vr_mode_handle = interaction_with_handle( vr_mode_handle, duration, resources, resource_values); if (!CHECK_HANDLE(vr_mode_handle)) { ALOGE("Failed interaction_with_handle for vr_mode_handle"); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } } @@ -172,20 +158,17 @@ static int process_vr_mode_hint(void *data) resource_values = getPowerhint(SUSTAINED_PERF_HINT_ID, &resources); if (!resource_values) { ALOGE("Can't get sustained perf hints from xml "); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } sustained_mode_handle = interaction_with_handle( sustained_mode_handle, duration, resources, resource_values); if (!CHECK_HANDLE(sustained_mode_handle)) { ALOGE("Failed interaction_with_handle for sustained_mode_handle"); - pthread_mutex_unlock(&s_interaction_lock); return HINT_NONE; } } vr_mode = 0; } - pthread_mutex_unlock(&s_interaction_lock); return HINT_HANDLED; } @@ -333,7 +316,7 @@ static int interaction_hint(void *data) return HINT_HANDLED; } -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) { @@ -347,9 +330,7 @@ int power_hint_override(struct power_module *UNUSED(module), power_hint_t hint, ret_val = process_vr_mode_hint(data); break; case POWER_HINT_INTERACTION: - pthread_mutex_lock(&s_interaction_lock); ret_val = interaction_hint(data); - pthread_mutex_unlock(&s_interaction_lock); break; case POWER_HINT_LAUNCH: ret_val = process_activity_launch_hint(data); @@ -360,7 +341,7 @@ int power_hint_override(struct power_module *UNUSED(module), power_hint_t hint, 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/power.c b/power/power-helper.c similarity index 78% rename from power/power.c rename to power/power-helper.c index 47229bbd..8a3bc4fb 100644 --- a/power/power.c +++ b/power/power-helper.c @@ -40,7 +40,6 @@ #define LOG_TAG "QCOM PowerHAL" #include -#include #include #include "utils.h" @@ -48,41 +47,19 @@ #include "hint-data.h" #include "performance.h" #include "power-common.h" +#include "power-helper.h" #ifndef RPM_SYSTEM_STAT #define RPM_SYSTEM_STAT "/d/system_stats" #endif -/* RPM runs at 19.2Mhz. Divide by 19200 for msec */ -#define RPM_CLK 19200 +#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 -#define MAX_RPM_PARAMS 2 -#define PLATFORM_SLEEP_MODES RPM_MODE_MAX -#define XO_VOTERS (MAX_STATS - XO_VOTERS_START) -#define VMIN_VOTERS 0 - -enum stats_type { - RPM_MODE_XO, - RPM_MODE_VMIN, - RPM_MODE_MAX, - XO_VOTERS_START = RPM_MODE_MAX, - VOTER_APSS = XO_VOTERS_START, - VOTER_MPSS, - VOTER_ADSP, - VOTER_SLPI, - MAX_STATS, -}; - -struct stat_pair { - enum stats_type stat; - const char *label; - const char **parameters; - size_t num_parameters; -}; - const char *rpm_stat_params[MAX_RPM_PARAMS] = { "count", "actual last sleep(msec)", @@ -102,6 +79,18 @@ struct stat_pair rpm_stat_map[] = { { VOTER_SLPI, "SLPI", master_stat_params, ARRAY_SIZE(master_stat_params) }, }; + +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; static int saved_mpdecision_slack_max = -1; @@ -110,7 +99,7 @@ static int saved_interactive_mode = -1; static int slack_node_rw_failed = 0; static int display_hint_sent; -static void power_init(struct power_module *UNUSED(module)) +void power_init(void) { ALOGI("QCOM power HAL initing."); } @@ -221,8 +210,7 @@ static void process_video_encode_hint(void *metadata) } } -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; @@ -231,11 +219,10 @@ int __attribute__ ((weak)) power_hint_override(struct power_module *UNUSED(modul /* 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; } @@ -268,20 +255,19 @@ static void power_hint(struct power_module *module, power_hint_t hint, } } -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]; struct video_encode_metadata_t video_encode_metadata; int rc = 0; - if (set_interactive_override(module, on) == HINT_HANDLED) { + if (set_interactive_override(on) == HINT_HANDLED) { return; } @@ -479,16 +465,6 @@ void set_interactive(struct power_module *module, int on) saved_interactive_mode = !!on; } -static ssize_t get_number_of_platform_modes(struct power_module *UNUSED(module)) { - return PLATFORM_SLEEP_MODES; -} - -static int get_voter_list(struct power_module *UNUSED(module), size_t *voter) { - voter[0] = XO_VOTERS; - voter[1] = VMIN_VOTERS; - - return 0; -} static int parse_stats(const char **params, size_t params_size, uint64_t *list, FILE *fp) { @@ -525,6 +501,7 @@ static int parse_stats(const char **params, size_t params_size, return 0; } + static int extract_stats(uint64_t *list, char *file, struct stat_pair *map, size_t map_size) { FILE *fp; @@ -536,7 +513,7 @@ static int extract_stats(uint64_t *list, char *file, fp = fopen(file, "re"); if (fp == NULL) { - ALOGE("%s: failed to open '%s': %s", __func__, file, strerror(errno)); + ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno)); return -errno; } @@ -571,104 +548,10 @@ static int extract_stats(uint64_t *list, char *file, return ret; } -static int get_platform_low_power_stats(struct power_module *UNUSED(module), - power_state_platform_sleep_state_t *list) { - uint64_t stats[MAX_STATS * MAX_RPM_PARAMS] = {0}; - uint64_t *values; - int ret; - unsigned i; - - if (!list) { - return -EINVAL; - } - - ret = extract_stats(stats, RPM_SYSTEM_STAT, - rpm_stat_map, ARRAY_SIZE(rpm_stat_map)); - if (ret) { - return ret; - } - - /* Update statistics for XO_shutdown */ - strcpy(list[0].name, "XO_shutdown"); - values = stats + (RPM_MODE_XO * MAX_RPM_PARAMS); - list[0].total_transitions = values[0]; - list[0].residency_in_msec_since_boot = values[1]; - list[0].supported_only_in_suspend = false; - list[0].number_of_voters = XO_VOTERS; - - for (i = 0; i < XO_VOTERS; i++) { - int voter = i + XO_VOTERS_START; - strlcpy(list[0].voters[i].name, rpm_stat_map[voter].label, - POWER_STATE_VOTER_NAME_MAX_LENGTH); - values = stats + (voter * MAX_RPM_PARAMS); - list[0].voters[i].total_time_in_msec_voted_for_since_boot = values[0] / RPM_CLK; - list[0].voters[i].total_number_of_times_voted_since_boot = values[1]; - } - - /* Update statistics for VMIN state */ - strcpy(list[1].name, "VMIN"); - values = stats + (RPM_MODE_VMIN * MAX_RPM_PARAMS); - list[1].total_transitions = values[0]; - list[1].residency_in_msec_since_boot = values[1]; - list[1].supported_only_in_suspend = false; - list[1].number_of_voters = VMIN_VOTERS; - - return 0; +int extract_platform_stats(uint64_t *list) { + return extract_stats(list, RPM_SYSTEM_STAT, rpm_stat_map, ARRAY_SIZE(rpm_stat_map)); } -static int power_open(const hw_module_t* UNUSED(module), const char* name, - hw_device_t** device) -{ - ALOGD("%s: enter; name=%s", __FUNCTION__, name); - int retval = 0; /* 0 is ok; -1 is error */ - - if (strcmp(name, POWER_HARDWARE_MODULE_ID) == 0) { - power_module_t *dev = (power_module_t *)calloc(1, - sizeof(power_module_t)); - - if (dev) { - /* Common hw_device_t fields */ - dev->common.tag = HARDWARE_MODULE_TAG; - dev->common.module_api_version = POWER_MODULE_API_VERSION_0_5; - dev->common.module_api_version = HARDWARE_HAL_API_VERSION; - - dev->init = power_init; - dev->powerHint = power_hint; - dev->setInteractive = set_interactive; - dev->get_number_of_platform_modes = get_number_of_platform_modes; - dev->get_platform_low_power_stats = get_platform_low_power_stats; - dev->get_voter_list = get_voter_list; - - *device = (hw_device_t*)dev; - } else - retval = -ENOMEM; - } else { - retval = -EINVAL; - } - - ALOGD("%s: exit %d", __FUNCTION__, retval); - return retval; +int extract_wlan_stats(uint64_t *list) { + return extract_stats(list, WLAN_POWER_STAT, wlan_stat_map, ARRAY_SIZE(wlan_stat_map)); } - -static struct hw_module_methods_t power_module_methods = { - .open = power_open, -}; - -struct power_module HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .module_api_version = POWER_MODULE_API_VERSION_0_5, - .hal_api_version = HARDWARE_HAL_API_VERSION, - .id = POWER_HARDWARE_MODULE_ID, - .name = "QCOM Power HAL", - .author = "Qualcomm", - .methods = &power_module_methods, - }, - - .init = power_init, - .powerHint = power_hint, - .setInteractive = set_interactive, - .get_number_of_platform_modes = get_number_of_platform_modes, - .get_platform_low_power_stats = get_platform_low_power_stats, - .get_voter_list = get_voter_list -}; diff --git a/power/power-helper.h b/power/power-helper.h new file mode 100644 index 00000000..79441c9a --- /dev/null +++ b/power/power-helper.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2012, 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 { + //Platform Stats + RPM_MODE_XO = 0, + RPM_MODE_VMIN, + RPM_MODE_MAX, + XO_VOTERS_START = RPM_MODE_MAX, + VOTER_APSS = XO_VOTERS_START, + VOTER_MPSS, + VOTER_ADSP, + VOTER_SLPI, + MAX_PLATFORM_STATS, + + //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 PLATFORM_SLEEP_MODES_COUNT RPM_MODE_MAX + +#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); +int extract_platform_stats(uint64_t *list); +int extract_wlan_stats(uint64_t *list); + + +#ifdef __cplusplus +} +#endif + +#endif //__POWER_HELPER_H__ diff --git a/power/service.cpp b/power/service.cpp new file mode 100644 index 00000000..beb9292a --- /dev/null +++ b/power/service.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 The Android Open Source 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. + */ + +//TODO I want to make this based on the device name +#define LOG_TAG "android.hardware.power@1.1-service.wahoo" + +#include +#include +#include +#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 service = nullptr; + + ALOGI("Power HAL Service 1.1 for Wahoo 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/sepolicy/file.te b/sepolicy/file.te index fc9a841d..45621a46 100644 --- a/sepolicy/file.te +++ b/sepolicy/file.te @@ -15,6 +15,7 @@ type debugfs_kgsl, debugfs_type, fs_type; type debugfs_rpm, debugfs_type, fs_type; type debugfs_rmt_storage, debugfs_type, fs_type; type debugfs_usb, debugfs_type, fs_type; +type debugfs_wlan, debugfs_type, fs_type; # /proc type proc_wifi_dbg, fs_type; diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts index 1862c315..8a6e7f7a 100644 --- a/sepolicy/file_contexts +++ b/sepolicy/file_contexts @@ -159,7 +159,6 @@ /sys/kernel/debug/pd_engine/usbpd0 u:object_r:debugfs_usb:s0 /sys/kernel/debug/ipc_logging/smblib/log u:object_r:debugfs_usb:s0 - # files in /system /system/bin/init\.power\.sh u:object_r:init_power_exec:s0 /system/bin/init\.radio\.sh u:object_r:init_radio_exec:s0 @@ -202,7 +201,8 @@ /vendor/bin/qmuxd u:object_r:qmuxd_exec:s0 /vendor/bin/cnd u:object_r:cnd_exec:s0 /vendor/bin/esed u:object_r:esed_exec:s0 -/vendor/bin/hw/android\.hardware\.usb@1\.1-service.wahoo u:object_r:hal_usb_default_exec:s0 +/vendor/bin/hw/android\.hardware\.usb@1\.1-service.wahoo u:object_r:hal_usb_default_exec:s0 +/vendor/bin/hw/android\.hardware\.power@1\.1-service.wahoo u:object_r:hal_power_default_exec:s0 /vendor/bin/chre u:object_r:chre_exec:s0 /vendor/bin/folio_daemon u:object_r:folio_daemon_exec:s0 /vendor/bin/time_daemon u:object_r:time_daemon_exec:s0 diff --git a/sepolicy/genfs_contexts b/sepolicy/genfs_contexts index 054dd317..a127f575 100644 --- a/sepolicy/genfs_contexts +++ b/sepolicy/genfs_contexts @@ -8,3 +8,4 @@ genfscon sysfs /class/devfreq u:object_r:sysfs_msm_subsy genfscon sysfs /class/rfkill/rfkill0/state u:object_r:sysfs_bluetooth_writable:s0 genfscon debugfs /kgsl/proc u:object_r:debugfs_kgsl:s0 +genfscon debugfs /wlan0 u:object_r:debugfs_wlan:s0 diff --git a/sepolicy/hal_power_default.te b/sepolicy/hal_power_default.te index 1dfc36b3..792d7239 100644 --- a/sepolicy/hal_power_default.te +++ b/sepolicy/hal_power_default.te @@ -1,4 +1,10 @@ allow hal_power_default perfd:unix_stream_socket connectto; allow hal_power_default perfd_socket:sock_file write; +userdebug_or_eng(` +# debugfs entries are only needed in user-debug or eng builds allow hal_power_default debugfs_rpm:file { open read getattr }; + +allow hal_power_default debugfs_wlan:dir search; +allow hal_power_default debugfs_wlan:file { open read getattr }; +') \ No newline at end of file diff --git a/sepolicy/hal_wifi_default.te b/sepolicy/hal_wifi_default.te index 80e28380..0bc1b4c3 100644 --- a/sepolicy/hal_wifi_default.te +++ b/sepolicy/hal_wifi_default.te @@ -10,3 +10,10 @@ allow hal_wifi_default wlan_device:chr_file w_file_perms; # Allow wifi hal to read debug info from the driver. r_dir_file(hal_wifi_default, proc_wifi_dbg) + +userdebug_or_eng(` +# debugfs entries are only needed in user-debug or eng builds + +# Allow wifi hal to access wlan debugfs files and directories +allow hal_wifi_default debugfs_wlan:dir search; +') \ No newline at end of file diff --git a/sepolicy/kernel.te b/sepolicy/kernel.te index 8243f45e..b4455a93 100644 --- a/sepolicy/kernel.te +++ b/sepolicy/kernel.te @@ -1,6 +1,7 @@ # for diag over socket userdebug_or_eng(` allow kernel self:socket create; + allow kernel debugfs_wlan:dir search; ') allow kernel vendor_firmware_file:file r_file_perms;