1 /*
2  * Copyright (C) 2020 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 <signal.h>
18 #include <sys/time.h>
19 #include <unistd.h>
20 
21 #include <algorithm>
22 #include <mutex>
23 #include <thread>
24 
25 #include <android-base/logging.h>
26 #include <android-base/parsebool.h>
27 #include <android-base/parseint.h>
28 #include <android-base/properties.h>
29 #include <android-base/thread_annotations.h>
30 
31 #include "property_monitor.h"
32 
33 static constexpr char kAdbWatchdogProperty[] = "persist.adb.watchdog";
34 static constexpr char kTestHarnessProperty[] = "persist.sys.test_harness";
35 
36 static constexpr unsigned int kDefaultAdbWatchdogTimeoutSeconds = 600;
37 static unsigned int g_watchdog_timeout_seconds;
38 
39 static std::mutex g_watchdog_mutex [[clang::no_destroy]];
40 
41 // The watchdog is "running" when it's enabled via property and there are no connected clients.
42 static bool g_watchdog_running GUARDED_BY(g_watchdog_mutex) = false;
43 
44 static PropertyMonitor g_property_monitor [[clang::no_destroy]];
45 
UpdateWatchdog()46 static void UpdateWatchdog() REQUIRES(g_watchdog_mutex) {
47     static std::once_flag once;
48     std::call_once(once, []() {
49         signal(SIGALRM, [](int) {
50             LOG(WARNING) << "adbd watchdog expired; rebooting...";
51             execl("/system/bin/reboot", "/system/bin/reboot", "bootloader", nullptr);
52         });
53     });
54 
55     static bool alarm_set = false;
56 
57     static auto Arm = []() {
58         LOG(INFO) << "adb watchdog armed, triggering in " << g_watchdog_timeout_seconds
59                   << " seconds";
60         alarm(g_watchdog_timeout_seconds);
61         alarm_set = true;
62     };
63 
64     static auto Disarm = []() {
65         unsigned int previous = alarm(0);
66         if (previous != 0) {
67             LOG(INFO) << "adb watchdog disarmed with " << previous << " seconds left";
68         }
69         alarm_set = false;
70     };
71 
72     bool watchdog_enabled = android::base::GetBoolProperty(
73             kAdbWatchdogProperty, android::base::GetBoolProperty(kTestHarnessProperty, false));
74     if (!watchdog_enabled) {
75         if (alarm_set) {
76             Disarm();
77         }
78         return;
79     }
80 
81     if (g_watchdog_running) {
82         if (!alarm_set) {
83             Arm();
84         }
85     } else {
86         Disarm();
87     }
88 }
89 
90 namespace watchdog {
91 
Start()92 void Start() {
93     std::lock_guard<std::mutex> lock(g_watchdog_mutex);
94     g_watchdog_running = true;
95     UpdateWatchdog();
96 }
97 
Stop()98 void Stop() {
99     std::lock_guard<std::mutex> lock(g_watchdog_mutex);
100     g_watchdog_running = false;
101     UpdateWatchdog();
102 }
103 
Initialize()104 void Initialize() {
105     for (auto& property : {kAdbWatchdogProperty, kTestHarnessProperty}) {
106         g_property_monitor.Add(property, [property](std::string value) {
107             LOG(INFO) << property << " set to '" << value << "'";
108 
109             std::lock_guard<std::mutex> lock(g_watchdog_mutex);
110             UpdateWatchdog();
111             return true;
112         });
113     }
114 
115     g_property_monitor.Add("persist.adb.watchdog.timeout_secs", [](std::string value) {
116         // This presumably isn't going to change while the watchdog is armed,
117         // so we don't need to recalculate a timer.
118         {
119             std::lock_guard<std::mutex> lock(g_watchdog_mutex);
120             if (!android::base::ParseUint(value, &g_watchdog_timeout_seconds)) {
121                 g_watchdog_timeout_seconds = kDefaultAdbWatchdogTimeoutSeconds;
122             }
123         }
124 
125         LOG(INFO) << "adb watchdog timeout set to " << g_watchdog_timeout_seconds << " seconds";
126         return true;
127     });
128 
129     Start();
130     std::thread([]() { g_property_monitor.Run(); }).detach();
131 }
132 
133 }  // namespace watchdog
134