diff --git a/aidl/battery/default/Android.bp b/aidl/battery/default/Android.bp index dec5d6b..7d82cec 100644 --- a/aidl/battery/default/Android.bp +++ b/aidl/battery/default/Android.bp @@ -10,6 +10,7 @@ cc_binary { init_rc: ["vendor.samsung_ext.framework.battery-service.rc"], vintf_fragments: ["vendor.samsung_ext.framework.battery-service.xml"], srcs: [ + "JSONParser.cpp", "SmartCharge.cpp", "service.cpp", ], @@ -21,11 +22,19 @@ cc_binary { "liblog", "libutils", "libsafestoi", + "libjsoncpp", "android.hardware.health@2.0", "android.hardware.health-V1-ndk", "vendor.samsung_ext.framework.battery-V1-ndk", ], whole_static_libs: ["libhealthhalutils"], system_ext_specific: true, - required: ["battery.default"], + required: ["smartcharge_nodes_json"], +} + +prebuilt_etc { + name: "smartcharge_nodes_json", + src: "smartcharge_nodes.json", + filename_from_src: true, + system_ext_specific: true, } diff --git a/aidl/battery/default/JSONParser.cpp b/aidl/battery/default/JSONParser.cpp new file mode 100644 index 0000000..58e6f89 --- /dev/null +++ b/aidl/battery/default/JSONParser.cpp @@ -0,0 +1,136 @@ +#include "JSONParser.hpp" +#include + +#include +#include +#include +#include +#include +#include + +void ConfigParser::handler_OpenFile(const std::string &node, + const std::string &data) { + LOG(DEBUG) << "Opening file: " << data; + std::ifstream file(node); + std::string line; + + if (file) { + file >> line; + } else { + PLOG(ERROR) << "Failed to read file"; + } +} + +void ConfigParser::handler_WriteFile(const std::string &node, + const std::string &data) { + LOG(DEBUG) << "Writing to file: " << data; + std::ofstream file(node); + if (file) { + file << data; + } else { + PLOG(ERROR) << "Failed to write to file"; + } +} + +// Returns a pair with the matching device and its match quality. +std::pair +ConfigParser::lookupEntry(const SearchEntry &search) { + std::pair current = {root, MatchQuality::NO_MATCH}; + for (const auto &devices : root) { + if (devices["codename"].asString() == search.codename) { + current = {devices, MatchQuality::EXACT}; + break; + } + if (devices["vendor"].asString() == search.vendor) { + current = {devices, MatchQuality::MATCHES_VENDOR}; + } + } + if (current.second == MatchQuality::NO_MATCH) { + LOG(ERROR) << "No matching device found"; + return current; + } + LOG(DEBUG) << "Found a match with quality: "; + switch (current.second) { + case MatchQuality::EXACT: + LOG(DEBUG) << "EXACT"; + break; + case MatchQuality::MATCHES_VENDOR: + LOG(DEBUG) << "MATCHES_VENDOR"; + break; + case MatchQuality::NO_MATCH: + break; + }; + return current; +} + +ConfigParser::ConfigParser(const std::string &path) { + std::ifstream file(path); + if (!file.is_open()) { + PLOG(ERROR) << "Failed to open file"; + return; + } + file >> root; +} + +std::function ConfigParser::findEntry(const SearchEntry &search) { + constexpr int ENABLE_FN_INDEX = 0; + constexpr int DISABLE_FN_INDEX = 1; + std::array, 2> handlers; + + const auto current = lookupEntry(search); + if (current.second == MatchQuality::NO_MATCH) { + return [](bool) {}; + } + + for (const auto &action : current.first["actions"]) { + if (!action["action"].isString()) { + LOG(ERROR) << "Invalid action type"; + return [](bool) {}; + } + const std::string actionType = action["action"].asString(); + const std::string node = action["node"].asString(); + const std::string handlerName = action["handler"].asString(); + const std::string handlerData = action["handler_data"].asString(); + + if (actionType == "enable") { + for (const auto &handler : m_handlers) { + if (handler.first == handlerName) { + handlers[ENABLE_FN_INDEX] = [callback = handler.second, node, + handlerData]() { + callback(node, handlerData); + }; + break; + } + } + if (!handlers[ENABLE_FN_INDEX]) { + LOG(ERROR) << "No handlers found for enable action"; + return [](bool) {}; + } + } else if (actionType == "disable") { + for (const auto &handler : m_handlers) { + if (handler.first == handlerName) { + handlers[DISABLE_FN_INDEX] = [callback = handler.second, node, + handlerData]() { + callback(node, handlerData); + }; + break; + } + } + if (!handlers[DISABLE_FN_INDEX]) { + LOG(ERROR) << "No handlers found for disable action"; + return [](bool) {}; + } + } else { + LOG(ERROR) << "Invalid action type"; + return [](bool) {}; + } + } + return [handlers](bool enable) { + if (enable) { + handlers[ENABLE_FN_INDEX](); + } else { + handlers[DISABLE_FN_INDEX](); + } + }; +} + diff --git a/aidl/battery/default/JSONParser.hpp b/aidl/battery/default/JSONParser.hpp new file mode 100644 index 0000000..7fabfd7 --- /dev/null +++ b/aidl/battery/default/JSONParser.hpp @@ -0,0 +1,46 @@ +#include +#include + +class ConfigParser { +public: + struct SearchEntry; + +private: + Json::Value root; + struct Handler { + std::function handler; + std::string name; + }; + + static void handler_OpenFile(const std::string &node, + const std::string &data); + + static void handler_WriteFile(const std::string &node, + const std::string &data); + + // Takes a node path and data + using HandlerFunction = + std::function; + // Takes name and handler function + using HandlerType = std::pair; + + std::vector m_handlers = { + {"OpenFile", handler_OpenFile}, + {"WriteFile", handler_WriteFile}, + }; + + enum class MatchQuality { EXACT, MATCHES_VENDOR, NO_MATCH }; + + // Returns a pair with the matching device and its match quality. + std::pair lookupEntry(const SearchEntry &search); + +public: + ConfigParser(const std::string &path); + + struct SearchEntry { + std::string codename; + std::string vendor; + }; + + std::function findEntry(const SearchEntry &search); +}; diff --git a/aidl/battery/default/SmartCharge.cpp b/aidl/battery/default/SmartCharge.cpp index da2d4c8..3fe8d56 100644 --- a/aidl/battery/default/SmartCharge.cpp +++ b/aidl/battery/default/SmartCharge.cpp @@ -5,17 +5,17 @@ */ #include "SmartCharge.h" -#include "modules/include/battery.h" +#include "JSONParser.hpp" #include #include +#include #include #include #include #include -#include #include #include #include @@ -37,22 +37,18 @@ static constexpr int kInvalidCfg = -1; static const char kSmartChargeConfigProp[] = "persist.ext.smartcharge.config"; static const char kSmartChargeEnabledProp[] = "persist.ext.smartcharge.enabled"; -static const char kSmartChargeOverrideProp[] = "ro.hardware.battery"; static const char kComma = ','; template using is_integral_or_bool = std::enable_if_t || std::is_same_v, bool>; -static inline bool isValidBool(const int val) { - return val == !!val; -} +static inline bool isValidBool(const int val) { return val == !!val; } static inline bool verifyConfig(const int lower, const int upper) { return !(upper <= lower || upper > 95 || (0 <= lower && lower < 50)); } -template = true> -struct ConfigPair { +template = true> struct ConfigPair { T first, second; std::string toString(void) { return std::to_string(first) + kComma + std::to_string(second); @@ -74,8 +70,7 @@ bool fromString(const std::string &v, ConfigPair *pair) { return false; } -template <> -bool fromString(const std::string &v, ConfigPair *pair) { +template <> bool fromString(const std::string &v, ConfigPair *pair) { ConfigPair tmp{}; if (fromString(v, &tmp) && isValidBool(tmp.first) && isValidBool(tmp.second)) { @@ -86,11 +81,10 @@ bool fromString(const std::string &v, ConfigPair *pair) { return false; } -template -bool getAndParse(const char *prop, ConfigPair *pair) { +template bool getAndParse(const char *prop, ConfigPair *pair) { std::string propval = GetProperty(prop, ""); if (!propval.empty()) { - return fromString(propval, pair); + return fromString(propval, pair); } return false; } @@ -115,7 +109,8 @@ void SmartCharge::loadHealthImpl(void) { healthState = USE_HEALTH_HIDL; ALOGD("%s: Connected to health HIDL V2.0 HAL", __func__); hidl_death_recp = new hidl_health_death_recipient(health_hidl); - auto ret = health_hidl->linkToDeath(hidl_death_recp, reinterpret_cast(this)); + auto ret = health_hidl->linkToDeath(hidl_death_recp, + reinterpret_cast(this)); linkToDeathSuccess = ret.isOk(); reason = ret.description(); } else { @@ -125,9 +120,9 @@ void SmartCharge::loadHealthImpl(void) { healthState = USE_HEALTH_AIDL; ALOGD("%s: Connected to health AIDL HAL", __func__); aidl_death_recp = ndk::ScopedAIBinder_DeathRecipient( - AIBinder_DeathRecipient_new(onServiceDied) - ); - auto ret = AIBinder_linkToDeath(health_aidl->asBinder().get(), aidl_death_recp.get(), this); + AIBinder_DeathRecipient_new(onServiceDied)); + auto ret = AIBinder_linkToDeath(health_aidl->asBinder().get(), + aidl_death_recp.get(), this); linkToDeathSuccess = ret == STATUS_OK; reason = ndk::ScopedAStatus(AStatus_fromStatus(ret)).getDescription(); } @@ -151,35 +146,14 @@ bool SmartCharge::loadAndParseConfigProp(void) { return true; } -#ifdef __LP64__ -#define LIB_PATH "/system_ext/lib64/hw/" -#else -#define LIB_PATH "/system_ext/lib/hw/" -#endif +void SmartCharge::loadConfiguration(void) { + ConfigParser parser("/system_ext/etc/smartcharge_nodes.json"); -void SmartCharge::loadImplLibrary(void) { - const static std::string filename = "battery." + - GetProperty(kSmartChargeOverrideProp, "default") + ".so"; - const static std::string path = LIB_PATH + filename; - - ALOGI("%s: Try dlopen '%s'", __func__, path.c_str()); - handle = dlopen(path.c_str(), RTLD_NOW); - if (handle) { - setChargableFunc = reinterpret_cast( - dlsym(handle, MODULE_SYM_NAME)); - - if (setChargableFunc) { - ALOGD("%s: " MODULE_SYM_NAME " function loaded", __func__); - } else { - ALOGE("%s: Failed to find " MODULE_SYM_NAME " symbol", __func__); - // Unused handle, close it - dlclose(handle); - } - } else { - ALOGE("%s: %s", __func__, dlerror() ?: "unknown"); - } + setChargableFunc = parser.findEntry({GetProperty("ro.product.device", ""), + GetProperty("ro.product.manufacturer", "")}); if (!setChargableFunc) { - setChargableFunc = [] (const bool) {}; + ALOGD("%s: Using stub for setChargableFunc", __func__); + setChargableFunc = [](const bool) {}; } } @@ -202,7 +176,7 @@ SmartCharge::SmartCharge(void) { bool ret; loadHealthImpl(); - loadImplLibrary(); + loadConfiguration(); ret = loadAndParseConfigProp(); if (ret) { @@ -227,12 +201,12 @@ void SmartCharge::startLoop(bool withrestart) { BatteryStatus status_aidl = BatteryStatus::UNKNOWN; auto ret = health_aidl->getCapacity(&per); if (!ret.isOk()) { - per = ret.getStatus(); + per = ret.getStatus(); break; } ret = health_aidl->getChargeStatus(&status_aidl); if (!ret.isOk()) { - per = ret.getStatus(); + per = ret.getStatus(); break; } switch (status_aidl) { @@ -243,15 +217,15 @@ void SmartCharge::startLoop(bool withrestart) { case BatteryStatus::DISCHARGING: case BatteryStatus::NOT_CHARGING: current = ChargeStatus::OFF; - break; + break; default: break; }; break; } case USE_HEALTH_HIDL: { - using ::android::hardware::health::V2_0::Result; using ::android::hardware::health::V1_0::BatteryStatus; + using ::android::hardware::health::V2_0::Result; ScopedLock _(hal_health_lock); Result res = Result::UNKNOWN; @@ -264,10 +238,11 @@ void SmartCharge::startLoop(bool withrestart) { per = -(static_cast(res)); break; } - health_hidl->getChargeStatus([&res, &status_hidl](Result hal_res, BatteryStatus hal_value) { - res = hal_res; - status_hidl = hal_value; - }); + health_hidl->getChargeStatus( + [&res, &status_hidl](Result hal_res, BatteryStatus hal_value) { + res = hal_res; + status_hidl = hal_value; + }); if (res != Result::SUCCESS) { per = -(static_cast(res)); break; @@ -304,7 +279,8 @@ void SmartCharge::startLoop(bool withrestart) { skip = true; if (current != policy && !skip) { - ALOGD("%s: Updating current, current %d, policy %d", __func__, current, policy); + ALOGD("%s: Updating current, current %d, policy %d", __func__, current, + policy); switch (policy) { case ChargeStatus::OFF: setChargableFunc(false); @@ -320,7 +296,8 @@ void SmartCharge::startLoop(bool withrestart) { skip = false; if (cv.wait_for(lock, 5s) == std::cv_status::no_timeout) { // cv signaled, exit now if kRunning is false - if (!kRunning) break; + if (!kRunning) + break; } } ALOGD("%s: --", __func__); @@ -329,12 +306,14 @@ void SmartCharge::startLoop(bool withrestart) { void SmartCharge::createLoopThread(bool restart) { ScopedLock _(thread_lock); ALOGD("%s: create thread", __func__); - kLoopThread = std::make_shared(&SmartCharge::startLoop, this, restart); + kLoopThread = + std::make_shared(&SmartCharge::startLoop, this, restart); kRunning = true; } ndk::ScopedAStatus SmartCharge::setChargeLimit(int32_t upper_, int32_t lower_) { - ALOGD("%s: upper: %d, lower: %d, kRun: %d", __func__, upper_, lower_, kRunning.load()); + ALOGD("%s: upper: %d, lower: %d, kRun: %d", __func__, upper_, lower_, + kRunning.load()); if (!verifyConfig(lower_, upper_)) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); if (kRunning) @@ -390,56 +369,50 @@ ndk::ScopedAStatus SmartCharge::activate(bool enable, bool restart) { return ndk::ScopedAStatus::ok(); } -binder_status_t SmartCharge::dump(int fd, const char** /* args */, uint32_t /* numArgs */) { - Dl_info info; - void *addr; - auto tryLockFn = [](std::mutex& m) { - const std::unique_lock lk{m, std::try_to_lock}; - return !lk.owns_lock(); +binder_status_t SmartCharge::dump(int fd, const char ** /* args */, + uint32_t /* numArgs */) { + auto tryLockFn = [](std::mutex &m) { + const std::unique_lock lk{m, std::try_to_lock}; + return !lk.owns_lock(); }; dprintf(fd, "Loop thread running: %d\n", kRunning.load()); if (kRunning) { - dprintf(fd, "Loop thread charge control state: "); - switch (status) { - case ChargeStatus::ON: - dprintf(fd, "ON"); - break; - case ChargeStatus::OFF: - dprintf(fd, "OFF"); - break; - } - dprintf(fd, "\n"); + dprintf(fd, "Loop thread charge control state: "); + switch (status) { + case ChargeStatus::ON: + dprintf(fd, "ON"); + break; + case ChargeStatus::OFF: + dprintf(fd, "OFF"); + break; + } + dprintf(fd, "\n"); } dprintf(fd, "Configuration (upper/lower): %d %d\n", upper, lower); - dprintf(fd, "Mutex locked (config/thread/cv) %d %d %d\n", tryLockFn(config_lock), - tryLockFn(thread_lock), tryLockFn(kCVLock)); + dprintf(fd, "Mutex locked (config/thread/cv) %d %d %d\n", + tryLockFn(config_lock), tryLockFn(thread_lock), tryLockFn(kCVLock)); dprintf(fd, "Connected Health HAL: "); switch (healthState) { - case USE_HEALTH_AIDL: - dprintf(fd, "AIDL Health HAL V1"); - break; - case USE_HEALTH_HIDL: - dprintf(fd, "HIDL Health HAL V2.0"); - break; - default: - break; + case USE_HEALTH_AIDL: + dprintf(fd, "AIDL Health HAL V1"); + break; + case USE_HEALTH_HIDL: + dprintf(fd, "HIDL Health HAL V2.0"); + break; + default: + break; }; - dprintf(fd, "\n"); - addr = dlsym(handle, MODULE_SYM_NAME); - if (dladdr(addr, &info) != 0) { - dprintf(fd, "Impl library path: %s\n", info.dli_fname); - } return STATUS_OK; } using ::android::hardware::interfacesEqual; -void hidl_health_death_recipient::serviceDied(uint64_t cookie, - const wp<::android::hidl::base::V1_0::IBase>& who) { - if (mHealth != nullptr && interfacesEqual(mHealth, who.promote())) { - onServiceDied(reinterpret_cast(cookie)); - } +void hidl_health_death_recipient::serviceDied( + uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase> &who) { + if (mHealth != nullptr && interfacesEqual(mHealth, who.promote())) { + onServiceDied(reinterpret_cast(cookie)); + } } } // namespace battery diff --git a/aidl/battery/default/SmartCharge.h b/aidl/battery/default/SmartCharge.h index de49b9f..2db0a9e 100644 --- a/aidl/battery/default/SmartCharge.h +++ b/aidl/battery/default/SmartCharge.h @@ -10,8 +10,6 @@ #include #include -#include - #include #include #include @@ -62,7 +60,6 @@ class SmartCharge : public BnSmartCharge { // Used by above condition_variable std::mutex kCVLock; - void* handle; std::function setChargableFunc; sp health_hidl; @@ -84,7 +81,7 @@ class SmartCharge : public BnSmartCharge { } status; bool loadAndParseConfigProp(); - void loadImplLibrary(); + void loadConfiguration(); void loadEnabledAndStart(); public: diff --git a/aidl/battery/default/modules/Android.bp b/aidl/battery/default/modules/Android.bp deleted file mode 100644 index 05a8413..0000000 --- a/aidl/battery/default/modules/Android.bp +++ /dev/null @@ -1,18 +0,0 @@ -cc_library_headers { - name: "aidl_battery_module_headers", - export_include_dirs: ["include"], -} - -cc_defaults { - name: "aidl_battery_module_defaults", - header_libs: ["aidl_battery_module_headers"], - relative_install_path: "hw", - compile_multilib: "first", - system_ext_specific: true, -} - -cc_library_shared { - name: "battery.default", - defaults: ["aidl_battery_module_defaults"], - srcs: ["DefaultImpl.cpp"], -} diff --git a/aidl/battery/default/modules/DefaultImpl.cpp b/aidl/battery/default/modules/DefaultImpl.cpp deleted file mode 100644 index 5dd9d95..0000000 --- a/aidl/battery/default/modules/DefaultImpl.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include - -static const char kChargeCtlSysfs[] = - "/sys/class/power_supply/battery/batt_slate_mode"; - -extern "C" void setChargable(bool enable) { - std::ofstream p(kChargeCtlSysfs); - if (p) - p << !enable; -} diff --git a/aidl/battery/default/modules/Sample.cpp b/aidl/battery/default/modules/Sample.cpp deleted file mode 100644 index 6d7a8de..0000000 --- a/aidl/battery/default/modules/Sample.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include - -extern "C" -void setChargable(bool enable) { - (void) enable; -} diff --git a/aidl/battery/default/modules/include/battery.h b/aidl/battery/default/modules/include/battery.h deleted file mode 100644 index b2b94a8..0000000 --- a/aidl/battery/default/modules/include/battery.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include - -__BEGIN_DECLS - -/** - * setChargable - Target specific method of enabling charge. - * - * @param enable Enable charging or not - * @return void - */ -extern void setChargable(const bool enable); - -#define MODULE_SYM_NAME "setChargable" - -__END_DECLS diff --git a/aidl/battery/default/smartcharge_nodes.json b/aidl/battery/default/smartcharge_nodes.json new file mode 100644 index 0000000..fcb9d58 --- /dev/null +++ b/aidl/battery/default/smartcharge_nodes.json @@ -0,0 +1,35 @@ +[ + { + "codename": "tb128fu", + "vendor": "lenovo", + "actions": [ + { + "action": "enable", + "node": "/sys/class/power_supply/battery/StartCharging_Test", + "handler": "OpenFile" + }, + { + "action": "disable", + "node": "/sys/class/power_supply/battery/StopCharging_Test", + "handler": "OpenFile" + } + ] + }, + { + "vendor": "samsung", + "actions": [ + { + "action": "enable", + "node": "/sys/class/power_supply/battery/batt_slate_mode", + "handler": "WriteFile", + "handler_data": "0" + }, + { + "action": "disable", + "node": "/sys/class/power_supply/battery/batt_slate_mode", + "handler": "WriteFile", + "handler_data": "1" + } + ] + } +] diff --git a/sepolicy/private/property_contexts b/sepolicy/private/property_contexts index 04752c9..5375395 100644 --- a/sepolicy/private/property_contexts +++ b/sepolicy/private/property_contexts @@ -2,5 +2,3 @@ persist.ext. u:object_r:ext_prop:s0 persist.ext.smartcharge. u:object_r:ext_smartcharge_prop:s0 persist.ext.flashlight. u:object_r:ext_flashlight_prop:s0 persist.ext.logdump. u:object_r:ext_logger_prop:s0 - -ro.hardware.battery u:object_r:exported_default_prop:s0 exact string