• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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