/* * Copyright (c) 2021, 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 "CarPowerPolicyServer.h" #include "SilentModeHandler.h" #include #include #include #include #include #include #include namespace android { namespace frameworks { namespace automotive { namespace powerpolicy { using ::aidl::android::frameworks::automotive::powerpolicy::BnCarPowerPolicyServer; using ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicy; using ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicyFilter; using ::aidl::android::frameworks::automotive::powerpolicy::ICarPowerPolicyChangeCallback; using ::aidl::android::frameworks::automotive::powerpolicy::PowerComponent; using ::android::sp; using ::android::base::ReadFileToString; using ::android::base::Trim; using ::android::base::WriteStringToFd; using ::ndk::ScopedAStatus; using ::testing::_; namespace { constexpr const char* kBootReasonNormal = "reboot,shell"; constexpr int kMaxPollingAttempts = 5; constexpr std::chrono::microseconds kPollingDelayUs = 50ms; } // namespace namespace internal { class SilentModeHandlerPeer { public: explicit SilentModeHandlerPeer(SilentModeHandler* handler) : mHandler(handler) {} ~SilentModeHandlerPeer() { mHandler->stopMonitoringSilentModeHwState(); } void init() { mHandler->init(); mHandler->stopMonitoringSilentModeHwState(); mHandler->mSilentModeHwStateFilename = mFileSilentModeHwState.path; mHandler->mKernelSilentModeFilename = mFileKernelSilentMode.path; mHandler->startMonitoringSilentModeHwState(); } void injectBootReason(const std::string& bootReason) { mHandler->mBootReason = bootReason; } void updateSilentModeHwState(bool isSilent) { WriteStringToFd(isSilent ? kValueSilentMode : kValueNonSilentMode, mFileSilentModeHwState.fd); } std::string readKernelSilentMode() { std::string value; if (!ReadFileToString(mFileKernelSilentMode.path, &value)) { return ""; } return Trim(value); } void updateKernelSilentMode(bool isSilent) { mHandler->updateKernelSilentMode(isSilent); } ScopedAStatus setSilentMode(const std::string& silentMode) { return mHandler->setSilentMode(silentMode); } private: SilentModeHandler* mHandler; TemporaryFile mFileSilentModeHwState; TemporaryFile mFileKernelSilentMode; }; } // namespace internal class MockCarPowerPolicyServer : public ISilentModeChangeHandler, public BnCarPowerPolicyServer { public: MOCK_METHOD(ScopedAStatus, getCurrentPowerPolicy, (CarPowerPolicy * aidlReturn), (override)); MOCK_METHOD(ScopedAStatus, getPowerComponentState, (PowerComponent componentId, bool* aidlReturn), (override)); MOCK_METHOD(ScopedAStatus, registerPowerPolicyChangeCallback, (const std::shared_ptr& callback, const CarPowerPolicyFilter& filter), (override)); MOCK_METHOD(ScopedAStatus, unregisterPowerPolicyChangeCallback, (const std::shared_ptr& callback), (override)); MOCK_METHOD(ScopedAStatus, applyPowerPolicy, (const std::string& policyId), (override)); MOCK_METHOD(ScopedAStatus, setPowerPolicyGroup, (const std::string& policyGroupId), (override)); MOCK_METHOD(void, notifySilentModeChange, (const bool silent), (override)); }; class SilentModeHandlerTest : public ::testing::Test { public: SilentModeHandlerTest() { carPowerPolicyServer = ::ndk::SharedRefBase::make(); } std::shared_ptr carPowerPolicyServer; }; TEST_F(SilentModeHandlerTest, TestRebootForForcedSilentMode) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonForcedSilent); handlerPeer.init(); ASSERT_TRUE(handler.isSilentMode()) << "It should be silent mode when booting with forced silent mode"; EXPECT_CALL(*carPowerPolicyServer, notifySilentModeChange(_)).Times(0); handlerPeer.updateSilentModeHwState(/*isSilent=*/false); ASSERT_TRUE(handler.isSilentMode()) << "When booting with forced silent mode, silent mode should not change by HW state"; } TEST_F(SilentModeHandlerTest, TestRebootForForcedNonSilentMode) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonForcedNonSilent); handlerPeer.init(); ASSERT_FALSE(handler.isSilentMode()) << "It should be non-silent mode when booting with forced non-silent mode"; handlerPeer.updateSilentModeHwState(/*isSilent=*/true); ASSERT_FALSE(handler.isSilentMode()) << "When booting with forced non-silent mode, silent mode " "should not change by HW state"; } TEST_F(SilentModeHandlerTest, TestUpdateKernelSilentMode) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonNormal); handlerPeer.init(); handlerPeer.updateKernelSilentMode(true); ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueSilentMode) << "Kernel silent mode file should have 1"; handlerPeer.updateKernelSilentMode(false); ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueNonSilentMode) << "Kernel silent mode file should have 0"; } TEST_F(SilentModeHandlerTest, TestSetSilentModeForForcedSilent) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonNormal); handlerPeer.init(); ScopedAStatus status = handlerPeer.setSilentMode("forced-silent"); ASSERT_TRUE(status.isOk()) << "setSilentMode(\"forced-silent\") should return OK"; ASSERT_TRUE(handler.isSilentMode()) << "When in forced-silent, silent mode should be set to true"; handlerPeer.updateSilentModeHwState(/*isSilent=*/false); ASSERT_TRUE(handler.isSilentMode()) << "When in forced-silent, silent mode should not change by HW state"; } TEST_F(SilentModeHandlerTest, TestSetSilentModeForForcedNonSilent) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonNormal); handlerPeer.init(); ScopedAStatus status = handlerPeer.setSilentMode("forced-non-silent"); ASSERT_TRUE(status.isOk()) << "setSilentMode(\"forced-non-silent\") should return OK"; ASSERT_FALSE(handler.isSilentMode()) << "When in forced-non-silent, silent mode should be set to false"; handlerPeer.updateSilentModeHwState(/*isSilent=*/true); ASSERT_FALSE(handler.isSilentMode()) << "When in forced-non-silent, silent mode should not change by HW state"; } TEST_F(SilentModeHandlerTest, TestSetSilentModeForNonForcedSilent) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonNormal); handlerPeer.init(); ScopedAStatus status = handlerPeer.setSilentMode("forced-non-silent"); status = handlerPeer.setSilentMode("non-forced-silent-mode"); ASSERT_TRUE(status.isOk()) << "setSilentMode(\"non-forced-silent-mode\") should return OK"; ASSERT_FALSE(handler.isSilentMode()) << "Changing to non-forced mode should keep the current silent mode"; handlerPeer.updateSilentModeHwState(/*isSilent=*/true); ASSERT_FALSE(handler.isSilentMode()) << "When in non-forced-silent, silent mode should change by HW state"; } TEST_F(SilentModeHandlerTest, TestSetSilentModeWithErrorMode) { SilentModeHandler handler(carPowerPolicyServer.get()); internal::SilentModeHandlerPeer handlerPeer(&handler); handlerPeer.injectBootReason(kBootReasonNormal); handlerPeer.init(); ScopedAStatus status = handlerPeer.setSilentMode("error-silent-mode"); ASSERT_FALSE(status.isOk()) << "setSilentMode with an erroneous mode should not return OK"; } } // namespace powerpolicy } // namespace automotive } // namespace frameworks } // namespace android