1 /*
2  *  Copyright 2021 Google, Inc
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 "lowmemorykiller"
18 
19 #include <errno.h>
20 #include <log/log.h>
21 #include <string.h>
22 
23 #include <processgroup/processgroup.h>
24 
25 #include "watchdog.h"
26 
watchdog_main(void * param)27 static void* watchdog_main(void* param) {
28     Watchdog *watchdog = static_cast<Watchdog*>(param);
29     sigset_t sigset;
30     int signum;
31 
32     // Ensure the thread does not use little cores
33     if (!SetTaskProfiles(gettid(), {"CPUSET_SP_FOREGROUND"}, true)) {
34         ALOGE("Failed to assign cpuset to the watchdog thread");
35     }
36 
37     if (!watchdog->create_timer(sigset)) {
38         ALOGE("Watchdog timer creation failed!");
39         return NULL;
40     }
41 
42     while (true) {
43         if (sigwait(&sigset, &signum) == -1) {
44             ALOGE("sigwait failed: %s", strerror(errno));
45         }
46 
47         watchdog->bite();
48     }
49 
50     return NULL;
51 }
52 
init()53 bool Watchdog::init() {
54     pthread_t thread;
55 
56     if (pthread_create(&thread, NULL, watchdog_main, this)) {
57         ALOGE("pthread_create failed: %s", strerror(errno));
58         return false;
59     }
60     if (pthread_setname_np(thread, "lmkd_watchdog")) {
61         ALOGW("pthread_setname_np failed: %s", strerror(errno));
62     }
63 
64     return true;
65 }
66 
start()67 bool Watchdog::start() {
68     // Start the timer and keep it active until it's disarmed
69     struct itimerspec new_timer;
70 
71     if (!timer_created_) {
72         return false;
73     }
74 
75     new_timer.it_value.tv_sec = timeout_;
76     new_timer.it_value.tv_nsec = 0;
77     new_timer.it_interval.tv_sec = timeout_;
78     new_timer.it_interval.tv_nsec = 0;
79 
80     if (timer_settime(timer_, 0, &new_timer, NULL)) {
81         ALOGE("timer_settime failed: %s", strerror(errno));
82         return false;
83     }
84 
85     return true;
86 }
87 
stop()88 bool Watchdog::stop() {
89     struct itimerspec new_timer = {};
90 
91     if (!timer_created_) {
92         return false;
93     }
94 
95     if (timer_settime(timer_, 0, &new_timer, NULL)) {
96         ALOGE("timer_settime failed: %s", strerror(errno));
97         return false;
98     }
99 
100     return true;
101 }
102 
create_timer(sigset_t & sigset)103 bool Watchdog::create_timer(sigset_t &sigset) {
104     struct sigevent sevent;
105 
106     sigemptyset(&sigset);
107     sigaddset(&sigset, SIGALRM);
108     if (sigprocmask(SIG_BLOCK, &sigset, NULL)) {
109         ALOGE("sigprocmask failed: %s", strerror(errno));
110         return false;
111     }
112 
113     sevent.sigev_notify = SIGEV_THREAD_ID;
114     sevent.sigev_notify_thread_id = gettid();
115     sevent.sigev_signo = SIGALRM;
116     if (timer_create(CLOCK_MONOTONIC, &sevent, &timer_)) {
117         ALOGE("timer_create failed: %s", strerror(errno));
118         return false;
119     }
120 
121     timer_created_ = true;
122     return true;
123 }
124