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