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->mSilentModeHwStateFilename = mFileSilentModeHwState.path;
67 mHandler->mKernelSilentModeFilename = mFileKernelSilentMode.path;
68 mHandler->init();
69 }
70
injectBootReason(const std::string & bootReason)71 void injectBootReason(const std::string& bootReason) { mHandler->mBootReason = bootReason; }
72
updateSilentModeHwState(bool isSilent)73 void updateSilentModeHwState(bool isSilent) {
74 WriteStringToFd(isSilent ? kValueSilentMode : kValueNonSilentMode,
75 mFileSilentModeHwState.fd);
76 }
77
readKernelSilentMode()78 std::string readKernelSilentMode() {
79 std::string value;
80 if (!ReadFileToString(mFileKernelSilentMode.path, &value)) {
81 return "";
82 }
83 return Trim(value);
84 }
85
updateKernelSilentMode(bool isSilent)86 void updateKernelSilentMode(bool isSilent) { mHandler->updateKernelSilentMode(isSilent); }
87
88 private:
89 SilentModeHandler* mHandler;
90 TemporaryFile mFileSilentModeHwState;
91 TemporaryFile mFileKernelSilentMode;
92 };
93
94 } // namespace internal
95
96 class MockCarPowerPolicyServer : public ISilentModeChangeHandler, public BnCarPowerPolicyServer {
97 public:
98 MOCK_METHOD(ScopedAStatus, getCurrentPowerPolicy, (CarPowerPolicy * aidlReturn), (override));
99 MOCK_METHOD(ScopedAStatus, getPowerComponentState,
100 (PowerComponent componentId, bool* aidlReturn), (override));
101 MOCK_METHOD(ScopedAStatus, registerPowerPolicyChangeCallback,
102 (const std::shared_ptr<ICarPowerPolicyChangeCallback>& callback,
103 const CarPowerPolicyFilter& filter),
104 (override));
105 MOCK_METHOD(ScopedAStatus, unregisterPowerPolicyChangeCallback,
106 (const std::shared_ptr<ICarPowerPolicyChangeCallback>& callback), (override));
107 MOCK_METHOD(void, notifySilentModeChange, (const bool silent), (override));
108 };
109
110 class SilentModeHandlerTest : public ::testing::Test {
111 public:
SilentModeHandlerTest()112 SilentModeHandlerTest() {
113 carPowerPolicyServer = ::ndk::SharedRefBase::make<MockCarPowerPolicyServer>();
114 }
115
116 std::shared_ptr<MockCarPowerPolicyServer> carPowerPolicyServer;
117 };
118
TEST_F(SilentModeHandlerTest,TestRebootForForcedSilentMode)119 TEST_F(SilentModeHandlerTest, TestRebootForForcedSilentMode) {
120 SilentModeHandler handler(carPowerPolicyServer.get());
121 internal::SilentModeHandlerPeer handlerPeer(&handler);
122 handlerPeer.injectBootReason(kBootReasonForcedSilent);
123 handlerPeer.init();
124
125 ASSERT_TRUE(handler.isSilentMode())
126 << "It should be silent mode when booting with forced silent mode";
127 EXPECT_CALL(*carPowerPolicyServer, notifySilentModeChange(_)).Times(0);
128
129 handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
130
131 ASSERT_TRUE(handler.isSilentMode())
132 << "When booting with forced silent mode, silent mode should not change by HW state";
133 }
134
TEST_F(SilentModeHandlerTest,TestRebootForForcedNonSilentMode)135 TEST_F(SilentModeHandlerTest, TestRebootForForcedNonSilentMode) {
136 SilentModeHandler handler(carPowerPolicyServer.get());
137 internal::SilentModeHandlerPeer handlerPeer(&handler);
138 handlerPeer.injectBootReason(kBootReasonForcedNonSilent);
139 handlerPeer.init();
140
141 ASSERT_FALSE(handler.isSilentMode())
142 << "It should be non-silent mode when booting with forced non-silent mode";
143
144 handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
145
146 ASSERT_FALSE(handler.isSilentMode()) << "When booting with forced non-silent mode, silent mode "
147 "should not change by HW state";
148 }
149
TEST_F(SilentModeHandlerTest,TestUpdateKernelSilentMode)150 TEST_F(SilentModeHandlerTest, TestUpdateKernelSilentMode) {
151 SilentModeHandler handler(carPowerPolicyServer.get());
152 internal::SilentModeHandlerPeer handlerPeer(&handler);
153 handlerPeer.injectBootReason(kBootReasonNormal);
154 handlerPeer.init();
155
156 handlerPeer.updateKernelSilentMode(true);
157
158 ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueSilentMode)
159 << "Kernel silent mode file should have 1";
160
161 handlerPeer.updateKernelSilentMode(false);
162
163 ASSERT_EQ(handlerPeer.readKernelSilentMode(), kValueNonSilentMode)
164 << "Kernel silent mode file should have 0";
165 }
166
167 } // namespace powerpolicy
168 } // namespace automotive
169 } // namespace frameworks
170 } // namespace android
171