You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
6.4 KiB
196 lines
6.4 KiB
4 months ago
|
/*
|
||
|
* 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 <android-base/chrono_utils.h>
|
||
|
#include <android-base/file.h>
|
||
|
#include <android-base/strings.h>
|
||
|
#include <gmock/gmock.h>
|
||
|
#include <utils/StrongPointer.h>
|
||
|
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <cstring>
|
||
|
|
||
|
namespace android {
|
||
|
namespace frameworks {
|
||
|
namespace automotive {
|
||
|
namespace powerpolicy {
|
||
|
|
||
|
using ::android::sp;
|
||
|
using ::android::base::ReadFileToString;
|
||
|
using ::android::base::Trim;
|
||
|
using ::android::base::WriteStringToFd;
|
||
|
using ::android::binder::Status;
|
||
|
using ::testing::_;
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
constexpr const char* kBootReasonNormal = "reboot,shell";
|
||
|
|
||
|
constexpr int kMaxPollingAttempts = 5;
|
||
|
constexpr std::chrono::microseconds kPollingDelayUs = 50ms;
|
||
|
|
||
|
bool waitForSilentMode(SilentModeHandler* handler, bool expectedSilentMode) {
|
||
|
int count = 0;
|
||
|
while (true) {
|
||
|
if (handler->isSilentMode() == expectedSilentMode) {
|
||
|
return true;
|
||
|
}
|
||
|
if (count++; count == kMaxPollingAttempts) {
|
||
|
break;
|
||
|
}
|
||
|
usleep(kPollingDelayUs.count());
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
namespace internal {
|
||
|
|
||
|
class SilentModeHandlerPeer {
|
||
|
public:
|
||
|
explicit SilentModeHandlerPeer(SilentModeHandler* handler) : mHandler(handler) {}
|
||
|
|
||
|
~SilentModeHandlerPeer() {
|
||
|
mHandler->stopMonitoringSilentModeHwState(/*shouldWaitThread=*/true);
|
||
|
}
|
||
|
|
||
|
void init() {
|
||
|
mHandler->mSilentModeHwStateFilename = mFileSilentModeHwState.path;
|
||
|
mHandler->mKernelSilentModeFilename = mFileKernelSilentMode.path;
|
||
|
mHandler->init();
|
||
|
}
|
||
|
|
||
|
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); }
|
||
|
|
||
|
private:
|
||
|
SilentModeHandler* mHandler;
|
||
|
TemporaryFile mFileSilentModeHwState;
|
||
|
TemporaryFile mFileKernelSilentMode;
|
||
|
};
|
||
|
|
||
|
} // namespace internal
|
||
|
|
||
|
class MockCarPowerPolicyServer : public ISilentModeChangeHandler, public BnCarPowerPolicyServer {
|
||
|
public:
|
||
|
MOCK_METHOD(Status, getCurrentPowerPolicy, (CarPowerPolicy * aidlReturn), (override));
|
||
|
MOCK_METHOD(Status, getPowerComponentState, (PowerComponent componentId, bool* aidlReturn),
|
||
|
(override));
|
||
|
MOCK_METHOD(Status, registerPowerPolicyChangeCallback,
|
||
|
(const sp<ICarPowerPolicyChangeCallback>& callback,
|
||
|
const CarPowerPolicyFilter& filter),
|
||
|
(override));
|
||
|
MOCK_METHOD(Status, unregisterPowerPolicyChangeCallback,
|
||
|
(const sp<ICarPowerPolicyChangeCallback>& callback), (override));
|
||
|
MOCK_METHOD(void, notifySilentModeChange, (const bool silent), (override));
|
||
|
};
|
||
|
|
||
|
class SilentModeHandlerTest : public ::testing::Test {
|
||
|
public:
|
||
|
SilentModeHandlerTest() { carPowerPolicyServer = new MockCarPowerPolicyServer(); }
|
||
|
|
||
|
sp<MockCarPowerPolicyServer> carPowerPolicyServer;
|
||
|
};
|
||
|
|
||
|
TEST_F(SilentModeHandlerTest, TestSilentModeHwStateMonitoring) {
|
||
|
SilentModeHandler handler(carPowerPolicyServer.get());
|
||
|
internal::SilentModeHandlerPeer handlerPeer(&handler);
|
||
|
handlerPeer.injectBootReason(kBootReasonNormal);
|
||
|
handlerPeer.init();
|
||
|
|
||
|
handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
|
||
|
|
||
|
ASSERT_TRUE(waitForSilentMode(&handler, /*expectedSilentMode=*/true))
|
||
|
<< "It should be silent mode when HW state is on";
|
||
|
|
||
|
handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
|
||
|
|
||
|
ASSERT_TRUE(waitForSilentMode(&handler, /*expectedSilentMode=*/false))
|
||
|
<< "It should be non-silent mode when HW state is off";
|
||
|
}
|
||
|
|
||
|
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";
|
||
|
}
|
||
|
|
||
|
} // namespace powerpolicy
|
||
|
} // namespace automotive
|
||
|
} // namespace frameworks
|
||
|
} // namespace android
|