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