1 /*
2 * Copyright (c) 2021, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "CarPowerPolicyServer.h"
18 #include "SilentModeHandler.h"
19
20 #include <android-base/chrono_utils.h>
21 #include <android-base/file.h>
22 #include <android-base/strings.h>
23 #include <gmock/gmock.h>
24 #include <utils/StrongPointer.h>
25
26 #include <unistd.h>
27
28 #include <cstring>
29
30 namespace android {
31 namespace frameworks {
32 namespace automotive {
33 namespace powerpolicy {
34
35 using ::android::sp;
36 using ::android::base::ReadFileToString;
37 using ::android::base::Trim;
38 using ::android::base::WriteStringToFd;
39 using ::android::binder::Status;
40 using ::testing::_;
41
42 namespace {
43
44 constexpr const char* kBootReasonNormal = "reboot,shell";
45
46 constexpr int kMaxPollingAttempts = 5;
47 constexpr std::chrono::microseconds kPollingDelayUs = 50ms;
48
49 } // namespace
50
51 namespace internal {
52
53 class SilentModeHandlerPeer {
54 public:
SilentModeHandlerPeer(SilentModeHandler * handler)55 explicit SilentModeHandlerPeer(SilentModeHandler* handler) : mHandler(handler) {}
56
~SilentModeHandlerPeer()57 ~SilentModeHandlerPeer() {
58 mHandler->stopMonitoringSilentModeHwState(/*shouldWaitThread=*/true);
59 }
60
init()61 void init() {
62 mHandler->mSilentModeHwStateFilename = mFileSilentModeHwState.path;
63 mHandler->mKernelSilentModeFilename = mFileKernelSilentMode.path;
64 mHandler->init();
65 }
66
injectBootReason(const std::string & bootReason)67 void injectBootReason(const std::string& bootReason) { mHandler->mBootReason = bootReason; }
68
updateSilentModeHwState(bool isSilent)69 void updateSilentModeHwState(bool isSilent) {
70 WriteStringToFd(isSilent ? kValueSilentMode : kValueNonSilentMode,
71 mFileSilentModeHwState.fd);
72 }
73
readKernelSilentMode()74 std::string readKernelSilentMode() {
75 std::string value;
76 if (!ReadFileToString(mFileKernelSilentMode.path, &value)) {
77 return "";
78 }
79 return Trim(value);
80 }
81
updateKernelSilentMode(bool isSilent)82 void updateKernelSilentMode(bool isSilent) { mHandler->updateKernelSilentMode(isSilent); }
83
84 private:
85 SilentModeHandler* mHandler;
86 TemporaryFile mFileSilentModeHwState;
87 TemporaryFile mFileKernelSilentMode;
88 };
89
90 } // namespace internal
91
92 class MockCarPowerPolicyServer : public ISilentModeChangeHandler, public BnCarPowerPolicyServer {
93 public:
94 MOCK_METHOD(Status, getCurrentPowerPolicy, (CarPowerPolicy * aidlReturn), (override));
95 MOCK_METHOD(Status, getPowerComponentState, (PowerComponent componentId, bool* aidlReturn),
96 (override));
97 MOCK_METHOD(Status, registerPowerPolicyChangeCallback,
98 (const sp<ICarPowerPolicyChangeCallback>& callback,
99 const CarPowerPolicyFilter& filter),
100 (override));
101 MOCK_METHOD(Status, unregisterPowerPolicyChangeCallback,
102 (const sp<ICarPowerPolicyChangeCallback>& callback), (override));
103 MOCK_METHOD(void, notifySilentModeChange, (const bool silent), (override));
104 };
105
106 class SilentModeHandlerTest : public ::testing::Test {
107 public:
SilentModeHandlerTest()108 SilentModeHandlerTest() { carPowerPolicyServer = new MockCarPowerPolicyServer(); }
109
110 sp<MockCarPowerPolicyServer> carPowerPolicyServer;
111 };
112
TEST_F(SilentModeHandlerTest,TestRebootForForcedSilentMode)113 TEST_F(SilentModeHandlerTest, TestRebootForForcedSilentMode) {
114 SilentModeHandler handler(carPowerPolicyServer.get());
115 internal::SilentModeHandlerPeer handlerPeer(&handler);
116 handlerPeer.injectBootReason(kBootReasonForcedSilent);
117 handlerPeer.init();
118
119 ASSERT_TRUE(handler.isSilentMode())
120 << "It should be silent mode when booting with forced silent mode";
121 EXPECT_CALL(*carPowerPolicyServer, notifySilentModeChange(_)).Times(0);
122
123 handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
124
125 ASSERT_TRUE(handler.isSilentMode())
126 << "When booting with forced silent mode, silent mode should not change by HW state";
127 }
128
TEST_F(SilentModeHandlerTest,TestRebootForForcedNonSilentMode)129 TEST_F(SilentModeHandlerTest, TestRebootForForcedNonSilentMode) {
130 SilentModeHandler handler(carPowerPolicyServer.get());
131 internal::SilentModeHandlerPeer handlerPeer(&handler);
132 handlerPeer.injectBootReason(kBootReasonForcedNonSilent);
133 handlerPeer.init();
134
135 ASSERT_FALSE(handler.isSilentMode())
136 << "It should be non-silent mode when booting with forced non-silent mode";
137
138 handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
139
140 ASSERT_FALSE(handler.isSilentMode()) << "When booting with forced non-silent mode, silent mode "
141 "should not change by HW state";
142 }
143
TEST_F(SilentModeHandlerTest,TestUpdateKernelSilentMode)144 TEST_F(SilentModeHandlerTest, TestUpdateKernelSilentMode) {
145 SilentModeHandler handler(carPowerPolicyServer.get());
146 internal::SilentModeHandlerPeer handlerPeer(&handler);
147 handlerPeer.injectBootReason(kBootReasonNormal);
148 handlerPeer.init();
149
150 handlerPeer.updateKernelSilentMode(true);
151
152 ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueSilentMode)
153 << "Kernel silent mode file should have 1";
154
155 handlerPeer.updateKernelSilentMode(false);
156
157 ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueNonSilentMode)
158 << "Kernel silent mode file should have 0";
159 }
160
161 } // namespace powerpolicy
162 } // namespace automotive
163 } // namespace frameworks
164 } // namespace android
165