1 /*
2  * Copyright 2019 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 <android-base/logging.h>
18 #include <binder/IPCThreadState.h>
19 #include <binder/IServiceManager.h>
20 #include <binder/ProcessState.h>
21 #include <cutils/native_handle.h>
22 #include <fcntl.h>
23 #include <hidl/HidlTransportSupport.h>
24 #include <hwbinder/ProcessState.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include <SuspendProperties.sysprop.h>
31 
32 #include "SuspendControlService.h"
33 #include "SystemSuspend.h"
34 
35 using android::sp;
36 using android::status_t;
37 using android::base::Socketpair;
38 using android::base::unique_fd;
39 using android::hardware::configureRpcThreadpool;
40 using android::hardware::joinRpcThreadpool;
41 using android::system::suspend::V1_0::ISystemSuspend;
42 using android::system::suspend::V1_0::SleepTimeConfig;
43 using android::system::suspend::V1_0::SuspendControlService;
44 using android::system::suspend::V1_0::SuspendControlServiceInternal;
45 using android::system::suspend::V1_0::SystemSuspend;
46 using namespace std::chrono_literals;
47 using namespace ::android::sysprop;
48 
49 static constexpr size_t kStatsCapacity = 1000;
50 static constexpr char kSysClassWakeup[] = "/sys/class/wakeup";
51 static constexpr char kSysPowerSuspendStats[] = "/sys/power/suspend_stats";
52 static constexpr char kSysPowerWakeupCount[] = "/sys/power/wakeup_count";
53 static constexpr char kSysPowerState[] = "/sys/power/state";
54 // TODO(b/120445600): Use upstream mechanism for wakeup reasons once available
55 static constexpr char kSysKernelWakeupReasons[] = "/sys/kernel/wakeup_reasons/last_resume_reason";
56 static constexpr char kSysKernelSuspendTime[] = "/sys/kernel/wakeup_reasons/last_suspend_time";
57 
58 static constexpr uint32_t kDefaultMaxSleepTimeMillis = 60000;
59 static constexpr uint32_t kDefaultBaseSleepTimeMillis = 100;
60 static constexpr double kDefaultSleepTimeScaleFactor = 2.0;
61 static constexpr uint32_t kDefaultBackoffThresholdCount = 0;
62 static constexpr uint32_t kDefaultShortSuspendThresholdMillis = 0;
63 static constexpr bool kDefaultFailedSuspendBackoffEnabled = true;
64 static constexpr bool kDefaultShortSuspendBackoffEnabled = false;
65 
main()66 int main() {
67     unique_fd wakeupCountFd{TEMP_FAILURE_RETRY(open(kSysPowerWakeupCount, O_CLOEXEC | O_RDWR))};
68     if (wakeupCountFd < 0) {
69         PLOG(ERROR) << "error opening " << kSysPowerWakeupCount;
70     }
71     unique_fd stateFd{TEMP_FAILURE_RETRY(open(kSysPowerState, O_CLOEXEC | O_RDWR))};
72     if (stateFd < 0) {
73         PLOG(ERROR) << "error opening " << kSysPowerState;
74     }
75     unique_fd kernelWakelockStatsFd{
76         TEMP_FAILURE_RETRY(open(kSysClassWakeup, O_DIRECTORY | O_CLOEXEC | O_RDONLY))};
77     if (kernelWakelockStatsFd < 0) {
78         PLOG(ERROR) << "SystemSuspend: Error opening " << kSysClassWakeup;
79     }
80     unique_fd suspendStatsFd{
81         TEMP_FAILURE_RETRY(open(kSysPowerSuspendStats, O_DIRECTORY | O_CLOEXEC | O_RDONLY))};
82     if (suspendStatsFd < 0) {
83         PLOG(ERROR) << "SystemSuspend: Error opening " << kSysPowerSuspendStats;
84     }
85     unique_fd wakeupReasonsFd{
86         TEMP_FAILURE_RETRY(open(kSysKernelWakeupReasons, O_CLOEXEC | O_RDONLY))};
87     if (wakeupReasonsFd < 0) {
88         PLOG(ERROR) << "SystemSuspend: Error opening " << kSysKernelWakeupReasons;
89     }
90     unique_fd suspendTimeFd{TEMP_FAILURE_RETRY(open(kSysKernelSuspendTime, O_CLOEXEC | O_RDONLY))};
91     if (wakeupReasonsFd < 0) {
92         PLOG(ERROR) << "SystemSuspend: Error opening " << kSysKernelSuspendTime;
93     }
94 
95     // If either /sys/power/wakeup_count or /sys/power/state fail to open, we construct
96     // SystemSuspend with blocking fds. This way this process will keep running, handle wake lock
97     // requests, collect stats, but won't suspend the device. We want this behavior on devices
98     // (hosts) where system suspend should not be handles by Android platform e.g. ARC++, Android
99     // virtual devices.
100     if (wakeupCountFd < 0 || stateFd < 0) {
101         // This will block all reads/writes to these fds from the suspend thread.
102         Socketpair(SOCK_STREAM, &wakeupCountFd, &stateFd);
103     }
104 
105     SleepTimeConfig sleepTimeConfig = {
106         .baseSleepTime = std::chrono::milliseconds(
107             SuspendProperties::base_sleep_time_millis().value_or(kDefaultBaseSleepTimeMillis)),
108         .maxSleepTime = std::chrono::milliseconds(
109             SuspendProperties::max_sleep_time_millis().value_or(kDefaultMaxSleepTimeMillis)),
110         .sleepTimeScaleFactor =
111             SuspendProperties::sleep_time_scale_factor().value_or(kDefaultSleepTimeScaleFactor),
112         .backoffThreshold =
113             SuspendProperties::backoff_threshold_count().value_or(kDefaultBackoffThresholdCount),
114         .shortSuspendThreshold =
115             std::chrono::milliseconds(SuspendProperties::short_suspend_threshold_millis().value_or(
116                 kDefaultShortSuspendThresholdMillis)),
117         .failedSuspendBackoffEnabled = SuspendProperties::failed_suspend_backoff_enabled().value_or(
118             kDefaultFailedSuspendBackoffEnabled),
119         .shortSuspendBackoffEnabled = SuspendProperties::short_suspend_backoff_enabled().value_or(
120             kDefaultShortSuspendBackoffEnabled),
121     };
122 
123     configureRpcThreadpool(1, true /* callerWillJoin */);
124 
125     sp<SuspendControlService> suspendControl = new SuspendControlService();
126     auto controlStatus = android::defaultServiceManager()->addService(
127         android::String16("suspend_control"), suspendControl);
128     if (controlStatus != android::OK) {
129         LOG(FATAL) << "Unable to register suspend_control service: " << controlStatus;
130     }
131 
132     sp<SuspendControlServiceInternal> suspendControlInternal = new SuspendControlServiceInternal();
133     controlStatus = android::defaultServiceManager()->addService(
134         android::String16("suspend_control_internal"), suspendControlInternal);
135     if (controlStatus != android::OK) {
136         LOG(FATAL) << "Unable to register suspend_control_internal service: " << controlStatus;
137     }
138 
139     // Create non-HW binder threadpool for SuspendControlService.
140     sp<android::ProcessState> ps{android::ProcessState::self()};
141     ps->startThreadPool();
142 
143     sp<SystemSuspend> suspend = new SystemSuspend(
144         std::move(wakeupCountFd), std::move(stateFd), std::move(suspendStatsFd), kStatsCapacity,
145         std::move(kernelWakelockStatsFd), std::move(wakeupReasonsFd), std::move(suspendTimeFd),
146         sleepTimeConfig, suspendControl, suspendControlInternal, true /* mUseSuspendCounter*/);
147 
148     status_t status = suspend->registerAsService();
149     if (android::OK != status) {
150         LOG(FATAL) << "Unable to register system-suspend service: " << status;
151     }
152 
153     joinRpcThreadpool();
154     std::abort(); /* unreachable */
155 }
156