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 ::aidl::android::frameworks::automotive::powerpolicy::BnCarPowerPolicyServer;
36 using ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicy;
37 using ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicyFilter;
38 using ::aidl::android::frameworks::automotive::powerpolicy::ICarPowerPolicyChangeCallback;
39 using ::aidl::android::frameworks::automotive::powerpolicy::PowerComponent;
40
41 using ::android::sp;
42 using ::android::base::ReadFileToString;
43 using ::android::base::Trim;
44 using ::android::base::WriteStringToFd;
45 using ::ndk::ScopedAStatus;
46 using ::testing::_;
47
48 namespace {
49
50 constexpr const char* kBootReasonNormal = "reboot,shell";
51
52 constexpr int kMaxPollingAttempts = 5;
53 constexpr std::chrono::microseconds kPollingDelayUs = 50ms;
54
55 } // namespace
56
57 namespace internal {
58
59 class SilentModeHandlerPeer {
60 public:
SilentModeHandlerPeer(SilentModeHandler * handler)61 explicit SilentModeHandlerPeer(SilentModeHandler* handler) : mHandler(handler) {}
62
~SilentModeHandlerPeer()63 ~SilentModeHandlerPeer() { mHandler->stopMonitoringSilentModeHwState(); }
64
init()65 void init() {
66 mHandler->init();
67 mHandler->stopMonitoringSilentModeHwState();
68 mHandler->mSilentModeHwStateFilename = mFileSilentModeHwState.path;
69 mHandler->mKernelSilentModeFilename = mFileKernelSilentMode.path;
70 mHandler->startMonitoringSilentModeHwState();
71 }
72
injectBootReason(const std::string & bootReason)73 void injectBootReason(const std::string& bootReason) { mHandler->mBootReason = bootReason; }
74
updateSilentModeHwState(bool isSilent)75 void updateSilentModeHwState(bool isSilent) {
76 WriteStringToFd(isSilent ? kValueSilentMode : kValueNonSilentMode,
77 mFileSilentModeHwState.fd);
78 }
79
readKernelSilentMode()80 std::string readKernelSilentMode() {
81 std::string value;
82 if (!ReadFileToString(mFileKernelSilentMode.path, &value)) {
83 return "";
84 }
85 return Trim(value);
86 }
87
updateKernelSilentMode(bool isSilent)88 void updateKernelSilentMode(bool isSilent) { mHandler->updateKernelSilentMode(isSilent); }
89
setSilentMode(const std::string & silentMode)90 ScopedAStatus setSilentMode(const std::string& silentMode) {
91 return mHandler->setSilentMode(silentMode);
92 }
93
94 private:
95 SilentModeHandler* mHandler;
96 TemporaryFile mFileSilentModeHwState;
97 TemporaryFile mFileKernelSilentMode;
98 };
99
100 } // namespace internal
101
102 class MockCarPowerPolicyServer : public ISilentModeChangeHandler, public BnCarPowerPolicyServer {
103 public:
104 MOCK_METHOD(ScopedAStatus, getCurrentPowerPolicy, (CarPowerPolicy * aidlReturn), (override));
105 MOCK_METHOD(ScopedAStatus, getPowerComponentState,
106 (PowerComponent componentId, bool* aidlReturn), (override));
107 MOCK_METHOD(ScopedAStatus, registerPowerPolicyChangeCallback,
108 (const std::shared_ptr<ICarPowerPolicyChangeCallback>& callback,
109 const CarPowerPolicyFilter& filter),
110 (override));
111 MOCK_METHOD(ScopedAStatus, unregisterPowerPolicyChangeCallback,
112 (const std::shared_ptr<ICarPowerPolicyChangeCallback>& callback), (override));
113 MOCK_METHOD(ScopedAStatus, applyPowerPolicy, (const std::string& policyId), (override));
114 MOCK_METHOD(ScopedAStatus, setPowerPolicyGroup, (const std::string& policyGroupId), (override));
115 MOCK_METHOD(void, notifySilentModeChange, (const bool silent), (override));
116 };
117
118 class SilentModeHandlerTest : public ::testing::Test {
119 public:
SilentModeHandlerTest()120 SilentModeHandlerTest() {
121 carPowerPolicyServer = ::ndk::SharedRefBase::make<MockCarPowerPolicyServer>();
122 }
123
124 std::shared_ptr<MockCarPowerPolicyServer> carPowerPolicyServer;
125 };
126
TEST_F(SilentModeHandlerTest,TestRebootForForcedSilentMode)127 TEST_F(SilentModeHandlerTest, TestRebootForForcedSilentMode) {
128 SilentModeHandler handler(carPowerPolicyServer.get());
129 internal::SilentModeHandlerPeer handlerPeer(&handler);
130 handlerPeer.injectBootReason(kBootReasonForcedSilent);
131 handlerPeer.init();
132
133 ASSERT_TRUE(handler.isSilentMode())
134 << "It should be silent mode when booting with forced silent mode";
135 EXPECT_CALL(*carPowerPolicyServer, notifySilentModeChange(_)).Times(0);
136
137 handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
138
139 ASSERT_TRUE(handler.isSilentMode())
140 << "When booting with forced silent mode, silent mode should not change by HW state";
141 }
142
TEST_F(SilentModeHandlerTest,TestRebootForForcedNonSilentMode)143 TEST_F(SilentModeHandlerTest, TestRebootForForcedNonSilentMode) {
144 SilentModeHandler handler(carPowerPolicyServer.get());
145 internal::SilentModeHandlerPeer handlerPeer(&handler);
146 handlerPeer.injectBootReason(kBootReasonForcedNonSilent);
147 handlerPeer.init();
148
149 ASSERT_FALSE(handler.isSilentMode())
150 << "It should be non-silent mode when booting with forced non-silent mode";
151
152 handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
153
154 ASSERT_FALSE(handler.isSilentMode()) << "When booting with forced non-silent mode, silent mode "
155 "should not change by HW state";
156 }
157
TEST_F(SilentModeHandlerTest,TestUpdateKernelSilentMode)158 TEST_F(SilentModeHandlerTest, TestUpdateKernelSilentMode) {
159 SilentModeHandler handler(carPowerPolicyServer.get());
160 internal::SilentModeHandlerPeer handlerPeer(&handler);
161 handlerPeer.injectBootReason(kBootReasonNormal);
162 handlerPeer.init();
163
164 handlerPeer.updateKernelSilentMode(true);
165
166 ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueSilentMode)
167 << "Kernel silent mode file should have 1";
168
169 handlerPeer.updateKernelSilentMode(false);
170
171 ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueNonSilentMode)
172 << "Kernel silent mode file should have 0";
173 }
174
TEST_F(SilentModeHandlerTest,TestSetSilentModeForForcedSilent)175 TEST_F(SilentModeHandlerTest, TestSetSilentModeForForcedSilent) {
176 SilentModeHandler handler(carPowerPolicyServer.get());
177 internal::SilentModeHandlerPeer handlerPeer(&handler);
178 handlerPeer.injectBootReason(kBootReasonNormal);
179 handlerPeer.init();
180
181 ScopedAStatus status = handlerPeer.setSilentMode("forced-silent");
182
183 ASSERT_TRUE(status.isOk()) << "setSilentMode(\"forced-silent\") should return OK";
184 ASSERT_TRUE(handler.isSilentMode())
185 << "When in forced-silent, silent mode should be set to true";
186
187 handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
188
189 ASSERT_TRUE(handler.isSilentMode())
190 << "When in forced-silent, silent mode should not change by HW state";
191 }
192
TEST_F(SilentModeHandlerTest,TestSetSilentModeForForcedNonSilent)193 TEST_F(SilentModeHandlerTest, TestSetSilentModeForForcedNonSilent) {
194 SilentModeHandler handler(carPowerPolicyServer.get());
195 internal::SilentModeHandlerPeer handlerPeer(&handler);
196 handlerPeer.injectBootReason(kBootReasonNormal);
197 handlerPeer.init();
198
199 ScopedAStatus status = handlerPeer.setSilentMode("forced-non-silent");
200
201 ASSERT_TRUE(status.isOk()) << "setSilentMode(\"forced-non-silent\") should return OK";
202 ASSERT_FALSE(handler.isSilentMode())
203 << "When in forced-non-silent, silent mode should be set to false";
204
205 handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
206
207 ASSERT_FALSE(handler.isSilentMode())
208 << "When in forced-non-silent, silent mode should not change by HW state";
209 }
210
TEST_F(SilentModeHandlerTest,TestSetSilentModeForNonForcedSilent)211 TEST_F(SilentModeHandlerTest, TestSetSilentModeForNonForcedSilent) {
212 SilentModeHandler handler(carPowerPolicyServer.get());
213 internal::SilentModeHandlerPeer handlerPeer(&handler);
214 handlerPeer.injectBootReason(kBootReasonNormal);
215 handlerPeer.init();
216
217 ScopedAStatus status = handlerPeer.setSilentMode("forced-non-silent");
218 status = handlerPeer.setSilentMode("non-forced-silent-mode");
219
220 ASSERT_TRUE(status.isOk()) << "setSilentMode(\"non-forced-silent-mode\") should return OK";
221 ASSERT_FALSE(handler.isSilentMode())
222 << "Changing to non-forced mode should keep the current silent mode";
223
224 handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
225
226 ASSERT_FALSE(handler.isSilentMode())
227 << "When in non-forced-silent, silent mode should change by HW state";
228 }
229
TEST_F(SilentModeHandlerTest,TestSetSilentModeWithErrorMode)230 TEST_F(SilentModeHandlerTest, TestSetSilentModeWithErrorMode) {
231 SilentModeHandler handler(carPowerPolicyServer.get());
232 internal::SilentModeHandlerPeer handlerPeer(&handler);
233 handlerPeer.injectBootReason(kBootReasonNormal);
234 handlerPeer.init();
235
236 ScopedAStatus status = handlerPeer.setSilentMode("error-silent-mode");
237 ASSERT_FALSE(status.isOk()) << "setSilentMode with an erroneous mode should not return OK";
238 }
239
240 } // namespace powerpolicy
241 } // namespace automotive
242 } // namespace frameworks
243 } // namespace android
244