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