| /* |
| * Copyright (C) 2020 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. |
| */ |
| |
| #include "BatteryDefender.h" |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include <utils/Timers.h> |
| |
| #include <android-base/file.h> |
| #include <android-base/properties.h> |
| |
| #define MIN_TIME_BETWEEN_FILE_UPDATES (30 + 1) |
| |
| class HealthInterface { |
| public: |
| virtual ~HealthInterface() {} |
| virtual bool ReadFileToString(const std::string &path, std::string *content, |
| bool follow_symlinks); |
| virtual int GetIntProperty(const std::string &key, int default_value, int min, int max); |
| virtual bool GetBoolProperty(const std::string &key, bool default_value); |
| virtual bool SetProperty(const std::string &key, const std::string &value); |
| virtual bool WriteStringToFile(const std::string &content, const std::string &path, |
| bool follow_symlinks); |
| }; |
| |
| class HealthInterfaceMock : public HealthInterface { |
| public: |
| virtual ~HealthInterfaceMock() {} |
| |
| MOCK_METHOD3(ReadFileToString, |
| bool(const std::string &path, std::string *content, bool follow_symlinks)); |
| MOCK_METHOD4(GetIntProperty, int(const std::string &key, int default_value, int min, int max)); |
| MOCK_METHOD2(GetBoolProperty, bool(const std::string &key, bool default_value)); |
| MOCK_METHOD2(SetProperty, bool(const std::string &key, const std::string &value)); |
| MOCK_METHOD3(WriteStringToFile, |
| bool(const std::string &content, const std::string &path, bool follow_symlinks)); |
| }; |
| |
| HealthInterfaceMock *mock; |
| |
| namespace android { |
| namespace base { |
| |
| bool ReadFileToString(const std::string &path, std::string *content, bool follow_symlinks) { |
| return mock->ReadFileToString(path, content, follow_symlinks); |
| } |
| |
| bool WriteStringToFile(const std::string &content, const std::string &path, bool follow_symlinks) { |
| return mock->WriteStringToFile(content, path, follow_symlinks); |
| } |
| |
| template <typename T> |
| T GetIntProperty(const std::string &key, T default_value, T min, T max) { |
| return (T)(mock->GetIntProperty(key, default_value, min, max)); |
| } |
| |
| bool GetBoolProperty(const std::string &key, bool default_value) { |
| return mock->GetBoolProperty(key, default_value); |
| } |
| |
| template int8_t GetIntProperty(const std::string &, int8_t, int8_t, int8_t); |
| template int16_t GetIntProperty(const std::string &, int16_t, int16_t, int16_t); |
| template int32_t GetIntProperty(const std::string &, int32_t, int32_t, int32_t); |
| template int64_t GetIntProperty(const std::string &, int64_t, int64_t, int64_t); |
| |
| bool SetProperty(const std::string &key, const std::string &value) { |
| return mock->SetProperty(key, value); |
| } |
| |
| } // namespace base |
| } // namespace android |
| |
| nsecs_t testvar_systemTimeSecs = 0; |
| nsecs_t systemTime(int clock) { |
| UNUSED(clock); |
| return seconds_to_nanoseconds(testvar_systemTimeSecs); |
| } |
| |
| namespace hardware { |
| namespace google { |
| namespace pixel { |
| namespace health { |
| |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::AtLeast; |
| using ::testing::DoAll; |
| using ::testing::InSequence; |
| using ::testing::Return; |
| using ::testing::SetArgPointee; |
| |
| class BatteryDefenderTest : public ::testing::Test { |
| public: |
| BatteryDefenderTest() {} |
| |
| void SetUp() { |
| mock = &mockFixture; |
| |
| EXPECT_CALL(*mock, SetProperty(_, _)).Times(AnyNumber()); |
| EXPECT_CALL(*mock, ReadFileToString(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(*mock, GetIntProperty(_, _, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(*mock, GetBoolProperty(_, _)).Times(AnyNumber()); |
| EXPECT_CALL(*mock, WriteStringToFile(_, _, _)).Times(AnyNumber()); |
| |
| ON_CALL(*mock, ReadFileToString(_, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::string("0")), Return(true))); |
| |
| ON_CALL(*mock, WriteStringToFile(_, _, _)).WillByDefault(Return(true)); |
| } |
| |
| void TearDown() {} |
| |
| private: |
| HealthInterfaceMock mockFixture; |
| }; |
| |
| const char *kPathWirelessChargerOnline = "/sys/class/power_supply/wireless/online"; |
| const char *kPathWiredChargerPresent = "/sys/class/power_supply/usb/present"; |
| const char *kPathBatteryCapacity = "/sys/class/power_supply/battery/capacity"; |
| const char *kPathPersistChargerPresentTime = "/mnt/vendor/persist/battery/defender_charger_time"; |
| const char *kPathPersistDefenderActiveTime = "/mnt/vendor/persist/battery/defender_active_time"; |
| const char *kPathStartLevel = "/sys/devices/platform/soc/soc:google,charger/charge_start_level"; |
| const char *kPathStopLevel = "/sys/devices/platform/soc/soc:google,charger/charge_stop_level"; |
| |
| const char *kPropChargeLevelVendorStart = "persist.vendor.charge.start.level"; |
| const char *kPropChargeLevelVendorStop = "persist.vendor.charge.stop.level"; |
| const char *kPropBatteryDefenderState = "vendor.battery.defender.state"; |
| const char *kPropBatteryDefenderDisable = "vendor.battery.defender.disable"; |
| const char *kPropBatteryDefenderThreshold = "vendor.battery.defender.threshold"; |
| |
| static void enableDefender(void) { |
| ON_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStart, _, _, _)).WillByDefault(Return(0)); |
| ON_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStop, _, _, _)).WillByDefault(Return(100)); |
| ON_CALL(*mock, GetBoolProperty(kPropBatteryDefenderDisable, _)).WillByDefault(Return(false)); |
| } |
| |
| static void powerAvailable(void) { |
| ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true))); |
| ON_CALL(*mock, ReadFileToString(kPathWiredChargerPresent, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true))); |
| } |
| |
| static void defaultThreshold(void) { |
| ON_CALL(*mock, GetIntProperty(kPropBatteryDefenderThreshold, _, _, _)) |
| .WillByDefault(Return(DEFAULT_TIME_TO_ACTIVATE_SECONDS)); |
| } |
| |
| static void capacityReached(void) { |
| ON_CALL(*mock, ReadFileToString(kPathBatteryCapacity, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::to_string(100)), Return(true))); |
| } |
| |
| static void initToConnectedCapacityReached(void) { |
| ON_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::to_string(1000)), Return(true))); |
| } |
| |
| static void initToActive(void) { |
| ON_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _)) |
| .WillByDefault( |
| DoAll(SetArgPointee<1>(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1)), |
| Return(true))); |
| } |
| |
| TEST_F(BatteryDefenderTest, EnableAndDisconnected) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| // No power |
| |
| // Enable Battery Defender |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, DisableNonDefaultLevels) { |
| BatteryDefender battDefender; |
| |
| // Enable Battery Defender |
| EXPECT_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStart, _, _, _)).WillOnce(Return(30)); |
| EXPECT_CALL(*mock, GetIntProperty(kPropChargeLevelVendorStop, _, _, _)).WillOnce(Return(35)); |
| |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, DisableExplicit) { |
| BatteryDefender battDefender; |
| |
| // Enable Battery Defender |
| EXPECT_CALL(*mock, GetBoolProperty(kPropBatteryDefenderDisable, _)).WillOnce(Return(true)); |
| |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISABLED")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, InitActive) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| powerAvailable(); |
| defaultThreshold(); |
| |
| EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1)), |
| Return(true))); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, InitConnectedCapacityReached) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| powerAvailable(); |
| defaultThreshold(); |
| |
| InSequence s; |
| |
| int time_expected = DEFAULT_TIME_TO_ACTIVATE_SECONDS - 1; |
| EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(std::to_string(time_expected)), Return(true))); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| battDefender.update(); |
| |
| testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES; |
| time_expected = DEFAULT_TIME_TO_ACTIVATE_SECONDS - 1 + MIN_TIME_BETWEEN_FILE_UPDATES; |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(time_expected), |
| kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, InitConnected) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| powerAvailable(); |
| defaultThreshold(); |
| |
| InSequence s; |
| |
| EXPECT_CALL(*mock, ReadFileToString(kPathPersistChargerPresentTime, _, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(std::to_string(0)), Return(true))); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| battDefender.update(); |
| |
| // mHasReachedHighCapacityLevel shall be false |
| testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1; |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, TriggerTime) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| powerAvailable(); |
| defaultThreshold(); |
| |
| InSequence s; |
| |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES; |
| battDefender.update(); |
| |
| // Reached 100% capacity at least once |
| EXPECT_CALL(*mock, ReadFileToString(kPathBatteryCapacity, _, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(std::to_string(100)), Return(true))); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES; |
| battDefender.update(); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS), |
| kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS; |
| battDefender.update(); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(DEFAULT_TIME_TO_ACTIVATE_SECONDS + |
| MIN_TIME_BETWEEN_FILE_UPDATES), |
| kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")); |
| testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES; |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, ChargeLevels) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| powerAvailable(); |
| defaultThreshold(); |
| initToConnectedCapacityReached(); |
| |
| InSequence s; |
| |
| // No expectations needed; default values already set |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 0; |
| battDefender.update(); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathStartLevel, _)); |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStopLevel, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")); |
| testvar_systemTimeSecs += DEFAULT_TIME_TO_ACTIVATE_SECONDS + 1; |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, ActiveTime) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| powerAvailable(); |
| defaultThreshold(); |
| initToActive(); |
| |
| InSequence s; |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathStartLevel, _)); |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(70), kPathStopLevel, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "ACTIVE")); |
| battDefender.update(); |
| } |
| |
| TEST_F(BatteryDefenderTest, ConnectDisconnectCycle) { |
| BatteryDefender battDefender; |
| |
| enableDefender(); |
| defaultThreshold(); |
| initToConnectedCapacityReached(); |
| |
| InSequence s; |
| |
| // Power ON |
| ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true))); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1000), kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60; |
| battDefender.update(); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(1060), kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60; |
| battDefender.update(); |
| |
| // Power OFF |
| ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::string("0")), Return(true))); |
| |
| // Maintain kPathPersistChargerPresentTime = 1060 |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60; |
| battDefender.update(); |
| |
| // Maintain kPathPersistChargerPresentTime = 1060 |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60 * 4; |
| battDefender.update(); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(0), kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "DISCONNECTED")); |
| testvar_systemTimeSecs += MIN_TIME_BETWEEN_FILE_UPDATES; |
| battDefender.update(); |
| |
| // Power ON |
| ON_CALL(*mock, ReadFileToString(kPathWirelessChargerOnline, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(std::string("1")), Return(true))); |
| |
| // Maintain kPathPersistChargerPresentTime = 0 |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60; |
| battDefender.update(); |
| |
| capacityReached(); |
| // Maintain kPathPersistChargerPresentTime = 0 |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60; |
| battDefender.update(); |
| |
| EXPECT_CALL(*mock, WriteStringToFile(std::to_string(60), kPathPersistChargerPresentTime, _)); |
| EXPECT_CALL(*mock, SetProperty(kPropBatteryDefenderState, "CONNECTED")); |
| testvar_systemTimeSecs += 60; |
| battDefender.update(); |
| } |
| |
| } // namespace health |
| } // namespace pixel |
| } // namespace google |
| } // namespace hardware |