• 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/inotify.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::base::Error;
39 using ::android::base::GetProperty;
40 using ::android::base::ReadFileToString;
41 using ::android::base::Result;
42 using ::android::base::SetProperty;
43 using ::android::base::StringPrintf;
44 using ::android::base::Trim;
45 using ::android::base::unique_fd;
46 using ::android::base::WriteStringToFd;
47 
48 namespace {
49 
50 constexpr const char kPropertySystemBootReason[] = "sys.boot.reason";
51 constexpr const char kSilentModeHwStateFilename[] = "/sys/power/pm_silentmode_hw_state";
52 constexpr const char kKernelSilentModeFilename[] = "/sys/power/pm_silentmode_kernel";
53 // To prevent boot animation from being started.
54 constexpr const char kPropertyNoBootAnimation[] = "debug.sf.nobootanimation";
55 // To stop boot animation while it is being played.
56 constexpr const char kPropertyBootAnimationExit[] = "service.bootanim.exit";
57 constexpr int kEventBufferSize = 512;
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       mFdInotify(-1) {
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", kSilentModeHwStateFilename);
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         inotify_rm_watch(mFdInotify, mWdSilentModeHwState);
105         mWdSilentModeHwState = -1;
106         if (shouldWaitThread && mSilentModeMonitoringThread.joinable()) {
107             mSilentModeMonitoringThread.join();
108         }
109     }
110     mFdInotify.reset(-1);
111 }
112 
dump(int fd,const Vector<String16> &)113 Result<void> SilentModeHandler::dump(int fd, const Vector<String16>& /*args*/) {
114     const char* indent = "  ";
115     WriteStringToFd(StringPrintf("%sMonitoring HW state: %s\n", indent,
116                                  mIsMonitoring ? "true" : "false"),
117                     fd);
118     WriteStringToFd(StringPrintf("%sForced silent mode: %s\n", indent,
119                                  mForcedMode ? "true" : "false"),
120                     fd);
121     if (mIsMonitoring) {
122         Mutex::Autolock lock(mMutex);
123         WriteStringToFd(StringPrintf("%sSilent mode by HW state: %s\n", indent,
124                                      mSilentModeByHwState ? "silent" : "non-silent"),
125                         fd);
126     }
127     return {};
128 }
129 
startMonitoringSilentModeHwState()130 void SilentModeHandler::startMonitoringSilentModeHwState() {
131     if (mIsMonitoring) {
132         ALOGW("Silent Mode monitoring is already started");
133         return;
134     }
135     if (mFdInotify < 0) {
136         mFdInotify.reset(inotify_init1(IN_CLOEXEC));
137         if (mFdInotify < 0) {
138             ALOGE("Failed to start monitoring Silent Mode HW state: creating inotify instance "
139                   "failed (errno = %d)",
140                   errno);
141             return;
142         }
143     }
144     const char* filename = mSilentModeHwStateFilename.c_str();
145     if (!fileExists(filename)) {
146         ALOGW("Failed to start monitoring Silent Mode HW state: %s doesn't exist", filename);
147         mFdInotify.reset(-1);
148         return;
149     }
150     // TODO(b/178843534): Additional masks might be needed to detect sysfs change.
151     const uint32_t masks = IN_MODIFY;
152     mWdSilentModeHwState = inotify_add_watch(mFdInotify, filename, masks);
153     mIsMonitoring = true;
154     mSilentModeMonitoringThread = std::thread([this]() {
155         char eventBuf[kEventBufferSize];
156         struct inotify_event* event;
157         constexpr size_t inotifyEventSize = sizeof(*event);
158         ALOGI("Monitoring %s started", mSilentModeHwStateFilename.c_str());
159         while (mIsMonitoring) {
160             int eventPos = 0;
161             int numBytes = read(mFdInotify, eventBuf, sizeof(eventBuf));
162             if (numBytes < static_cast<int>(inotifyEventSize)) {
163                 if (errno == EINTR) {
164                     ALOGW("System call interrupted. Wait for inotify event again.");
165                     continue;
166                 }
167                 mIsMonitoring = false;
168                 inotify_rm_watch(mFdInotify, mWdSilentModeHwState);
169                 mWdSilentModeHwState = -1;
170                 mFdInotify.reset(-1);
171                 ALOGW("Failed to wait for change at %s (errno = %d)",
172                       mSilentModeHwStateFilename.c_str(), errno);
173                 return;
174             }
175             while (numBytes >= static_cast<int>(inotifyEventSize)) {
176                 int eventSize;
177                 event = (struct inotify_event*)(eventBuf + eventPos);
178                 if (event->wd == mWdSilentModeHwState && (event->mask & masks)) {
179                     handleSilentModeHwStateChange();
180                 }
181                 eventSize = inotifyEventSize + event->len;
182                 numBytes -= eventSize;
183                 eventPos += eventSize;
184             }
185         }
186         ALOGI("Monitoring %s ended", mSilentModeHwStateFilename.c_str());
187     });
188     // Read the current silent mode HW state.
189     handleSilentModeHwStateChange();
190 }
191 
handleSilentModeHwStateChange()192 void SilentModeHandler::handleSilentModeHwStateChange() {
193     if (!mIsMonitoring) {
194         return;
195     }
196     std::string buf;
197     if (!ReadFileToString(mSilentModeHwStateFilename.c_str(), &buf)) {
198         ALOGW("Failed to read %s", mSilentModeHwStateFilename.c_str());
199         return;
200     }
201     bool newSilentMode;
202     bool oldSilentMode;
203     {
204         Mutex::Autolock lock(mMutex);
205         oldSilentMode = std::exchange(mSilentModeByHwState, Trim(buf) == kValueSilentMode);
206         newSilentMode = mSilentModeByHwState;
207     }
208     if (newSilentMode != oldSilentMode) {
209         ALOGI("%s is set to %s", mSilentModeHwStateFilename.c_str(),
210               newSilentMode ? "silent" : "non-silent");
211         handleSilentModeChange(newSilentMode);
212         mSilentModeChangeHandler->notifySilentModeChange(newSilentMode);
213     }
214 }
215 
handleSilentModeChange(bool silent)216 void SilentModeHandler::handleSilentModeChange(bool silent) {
217     if (auto ret = updateKernelSilentMode(silent); !ret.ok()) {
218         ALOGW("Failed to update kernel silent mode: %s", ret.error().message().c_str());
219     }
220     if (auto ret = enableBootAnimation(!silent); !ret.ok()) {
221         ALOGW("Failed to %s boot animation: %s", mSilentModeByHwState ? "disabling" : "enabling",
222               ret.error().message().c_str());
223     }
224 }
225 
enableBootAnimation(bool enabled)226 Result<void> SilentModeHandler::enableBootAnimation(bool enabled) {
227     const std::string value = enabled ? "0" : "1";
228     if (!SetProperty(kPropertyNoBootAnimation, value)) {
229         return Error() << "Failed to set " << kPropertyNoBootAnimation << " property to " << value;
230     }
231     if (!enabled) {
232         if (!SetProperty(kPropertyBootAnimationExit, value)) {
233             return Error() << "Failed to set " << kPropertyBootAnimationExit << " property to "
234                            << value;
235         }
236     }
237     return {};
238 }
239 
updateKernelSilentMode(bool silent)240 Result<void> SilentModeHandler::updateKernelSilentMode(bool silent) {
241     int fd = open(mKernelSilentModeFilename.c_str(), O_WRONLY | O_NONBLOCK);
242     if (fd < 0) {
243         return Error() << "Failed to open " << mKernelSilentModeFilename;
244     }
245     Result<void> status = {};
246     if (const auto& value = silent ? kValueSilentMode : kValueNonSilentMode;
247         !WriteStringToFd(value, fd)) {
248         status = Error() << "Failed to write " << value << " to fd " << fd;
249     }
250     close(fd);
251     return status;
252 }
253 
254 }  // namespace powerpolicy
255 }  // namespace automotive
256 }  // namespace frameworks
257 }  // namespace android
258