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 #define LOG_TAG "carpowerpolicyd"
18
19 #include "SilentModeHandler.h"
20
21 #include "CarPowerPolicyServer.h"
22
23 #include <android-base/file.h>
24 #include <android-base/properties.h>
25 #include <android-base/stringprintf.h>
26 #include <android-base/strings.h>
27
28 #include <sys/epoll.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31
32 #include <filesystem>
33
34 namespace android {
35 namespace frameworks {
36 namespace automotive {
37 namespace powerpolicy {
38
39 using ::android::Mutex;
40 using ::android::automotive::SysfsMonitor;
41 using ::android::base::Error;
42 using ::android::base::GetProperty;
43 using ::android::base::ReadFileToString;
44 using ::android::base::Result;
45 using ::android::base::SetProperty;
46 using ::android::base::StringPrintf;
47 using ::android::base::Trim;
48 using ::android::base::unique_fd;
49 using ::android::base::WriteStringToFd;
50
51 namespace {
52
53 constexpr const char kPropertySystemBootReason[] = "sys.boot.reason";
54 constexpr const char kHwStateFilename[] = "pm_silentmode_hw_state";
55 constexpr const char kKernelStateFilename[] = "pm_silentmode_kernel_state";
56 // To prevent boot animation from being started.
57 constexpr const char kPropertyNoBootAnimation[] = "debug.sf.nobootanimation";
58 // To stop boot animation while it is being played.
59 constexpr const char kPropertyBootAnimationExit[] = "service.bootanim.exit";
60 constexpr const char* kSysfsDirForSilentMode[] = {"/sys/kernel/silent_boot", "/sys/power"};
61
fileExists(const char * filename)62 bool fileExists(const char* filename) {
63 struct stat buffer;
64 return stat(filename, &buffer) == 0;
65 }
66
67 // We search for the folder where sysfs files for Silent Mode are located in the following order:
68 // 1. /sys/kernel/silent_boot
69 // 2. /sys/power (only for backward compatibility)
searchForSysfsDir()70 std::string searchForSysfsDir() {
71 std::error_code ec;
72 for (const char* dir : kSysfsDirForSilentMode) {
73 if (std::filesystem::is_directory(dir, ec)) {
74 return std::string(dir) + "/";
75 }
76 }
77 return std::string(kSysfsDirForSilentMode[0]) + "/";
78 }
79
80 } // namespace
81
SilentModeHandler(ISilentModeChangeHandler * handler)82 SilentModeHandler::SilentModeHandler(ISilentModeChangeHandler* handler) :
83 mSilentModeByHwState(false),
84 mSilentModeChangeHandler(handler),
85 mSysfsMonitor(sp<SysfsMonitor>::make()) {
86 mBootReason = GetProperty(kPropertySystemBootReason, "");
87 }
88
init()89 void SilentModeHandler::init() {
90 std::string sysfsDir = searchForSysfsDir();
91 mSilentModeHwStateFilename = sysfsDir + kHwStateFilename;
92 mKernelSilentModeFilename = sysfsDir + kKernelStateFilename;
93 if (mBootReason == kBootReasonForcedSilent) {
94 mForcedMode = true;
95 mSilentModeByHwState = true;
96 } else if (mBootReason == kBootReasonForcedNonSilent) {
97 mForcedMode = true;
98 mSilentModeByHwState = false;
99 }
100 if (mForcedMode) {
101 handleSilentModeChange(mSilentModeByHwState);
102 mSilentModeChangeHandler->notifySilentModeChange(mSilentModeByHwState);
103 ALOGI("Now in forced mode: monitoring %s is disabled", mSilentModeHwStateFilename.c_str());
104 } else {
105 startMonitoringSilentModeHwState();
106 }
107 }
108
release()109 void SilentModeHandler::release() {
110 stopMonitoringSilentModeHwState(/*shouldWaitThread=*/false);
111 }
112
isSilentMode()113 bool SilentModeHandler::isSilentMode() {
114 Mutex::Autolock lock(mMutex);
115 return mSilentModeByHwState;
116 }
117
stopMonitoringSilentModeHwState(bool shouldWaitThread)118 void SilentModeHandler::stopMonitoringSilentModeHwState(bool shouldWaitThread) {
119 if (mIsMonitoring) {
120 mIsMonitoring = false;
121 if (auto ret = mSysfsMonitor->unregisterFd(mFdSilentModeHwState.get()); !ret.ok()) {
122 ALOGW("Unregistering %s from SysfsMonitor failed", mSilentModeHwStateFilename.c_str());
123 }
124 if (shouldWaitThread && mSilentModeMonitoringThread.joinable()) {
125 mSilentModeMonitoringThread.join();
126 }
127 }
128 mFdSilentModeHwState.reset();
129 mSysfsMonitor->release();
130 }
131
dump(int fd,const Vector<String16> &)132 Result<void> SilentModeHandler::dump(int fd, const Vector<String16>& /*args*/) {
133 const char* indent = " ";
134 WriteStringToFd(StringPrintf("%sHW state filename: %s\n", indent,
135 mSilentModeHwStateFilename.c_str()),
136 fd);
137 WriteStringToFd(StringPrintf("%sKernel state filename: %s\n", indent,
138 mKernelSilentModeFilename.c_str()),
139 fd);
140 WriteStringToFd(StringPrintf("%sMonitoring HW state: %s\n", indent,
141 mIsMonitoring ? "true" : "false"),
142 fd);
143 WriteStringToFd(StringPrintf("%sForced silent mode: %s\n", indent,
144 mForcedMode ? "true" : "false"),
145 fd);
146 if (mIsMonitoring) {
147 Mutex::Autolock lock(mMutex);
148 WriteStringToFd(StringPrintf("%sSilent mode by HW state: %s\n", indent,
149 mSilentModeByHwState ? "silent" : "non-silent"),
150 fd);
151 }
152 return {};
153 }
154
startMonitoringSilentModeHwState()155 void SilentModeHandler::startMonitoringSilentModeHwState() {
156 if (mIsMonitoring) {
157 ALOGW("Silent Mode monitoring is already started");
158 return;
159 }
160 const char* filename = mSilentModeHwStateFilename.c_str();
161 if (!fileExists(filename)) {
162 ALOGW("Failed to start monitoring Silent Mode HW state: %s doesn't exist", filename);
163 return;
164 }
165 if (mFdSilentModeHwState == -1) {
166 if (mFdSilentModeHwState.reset(open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
167 mFdSilentModeHwState == -1) {
168 ALOGW("Failed to open %s for monitoring: errno = %d", filename, errno);
169 return;
170 }
171 }
172 auto ret = mSysfsMonitor->init([this](const std::vector<int32_t>& fileDescriptors) {
173 // Only one sysfs file is registered.
174 if (mFdSilentModeHwState != fileDescriptors[0]) {
175 return;
176 }
177 handleSilentModeHwStateChange();
178 });
179 if (!ret.ok()) {
180 ALOGW("Failed to initialize SysfsMonitor: %s", ret.error().message().c_str());
181 return;
182 }
183 if (auto ret = mSysfsMonitor->registerFd(mFdSilentModeHwState.get()); !ret.ok()) {
184 ALOGW("Failed to register %s to SysfsMonitor: %s", filename, ret.error().message().c_str());
185 return;
186 }
187 mIsMonitoring = true;
188 mSilentModeMonitoringThread = std::thread([this, filename]() {
189 if (auto ret = mSysfsMonitor->observe(); !ret.ok()) {
190 ALOGI("Failed to observe %s", filename);
191 return;
192 }
193 ALOGI("Monitoring %s ended", mSilentModeHwStateFilename.c_str());
194 });
195 // Read the current silent mode HW state.
196 handleSilentModeHwStateChange();
197 }
198
handleSilentModeHwStateChange()199 void SilentModeHandler::handleSilentModeHwStateChange() {
200 if (!mIsMonitoring) {
201 return;
202 }
203 std::string buf;
204 if (!ReadFileToString(mSilentModeHwStateFilename.c_str(), &buf)) {
205 ALOGW("Failed to read %s", mSilentModeHwStateFilename.c_str());
206 return;
207 }
208 bool newSilentMode;
209 bool oldSilentMode;
210 {
211 Mutex::Autolock lock(mMutex);
212 oldSilentMode = std::exchange(mSilentModeByHwState, Trim(buf) == kValueSilentMode);
213 newSilentMode = mSilentModeByHwState;
214 }
215 if (newSilentMode != oldSilentMode) {
216 ALOGI("%s is set to %s", mSilentModeHwStateFilename.c_str(),
217 newSilentMode ? "silent" : "non-silent");
218 handleSilentModeChange(newSilentMode);
219 mSilentModeChangeHandler->notifySilentModeChange(newSilentMode);
220 }
221 }
222
handleSilentModeChange(bool silent)223 void SilentModeHandler::handleSilentModeChange(bool silent) {
224 if (auto ret = updateKernelSilentMode(silent); !ret.ok()) {
225 ALOGW("Failed to update kernel silent mode: %s", ret.error().message().c_str());
226 }
227 if (auto ret = enableBootAnimation(!silent); !ret.ok()) {
228 ALOGW("Failed to %s boot animation: %s", mSilentModeByHwState ? "disabling" : "enabling",
229 ret.error().message().c_str());
230 }
231 }
232
enableBootAnimation(bool enabled)233 Result<void> SilentModeHandler::enableBootAnimation(bool enabled) {
234 const std::string value = enabled ? "0" : "1";
235 if (!SetProperty(kPropertyNoBootAnimation, value)) {
236 return Error() << "Failed to set " << kPropertyNoBootAnimation << " property to " << value;
237 }
238 if (!enabled) {
239 if (!SetProperty(kPropertyBootAnimationExit, value)) {
240 return Error() << "Failed to set " << kPropertyBootAnimationExit << " property to "
241 << value;
242 }
243 }
244 return {};
245 }
246
updateKernelSilentMode(bool silent)247 Result<void> SilentModeHandler::updateKernelSilentMode(bool silent) {
248 int fd = open(mKernelSilentModeFilename.c_str(), O_WRONLY | O_NONBLOCK);
249 if (fd < 0) {
250 return Error() << "Failed to open " << mKernelSilentModeFilename;
251 }
252 Result<void> status = {};
253 if (const auto& value = silent ? kValueSilentMode : kValueNonSilentMode;
254 !WriteStringToFd(value, fd)) {
255 status = Error() << "Failed to write " << value << " to fd " << fd;
256 }
257 close(fd);
258 return status;
259 }
260
261 } // namespace powerpolicy
262 } // namespace automotive
263 } // namespace frameworks
264 } // namespace android
265