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 46 static void UpdateWatchdog() REQUIRES(g_watchdog_mutex) { 47 static std::once_flag once; 48 std::call_once(once, []() { 49 signal(SIGALRM, [](int) { 50 execl("/system/bin/reboot", "/system/bin/reboot", "bootloader", nullptr); 51 }); 52 }); 53 54 static bool alarm_set = false; 55 56 static auto Arm = []() { 57 LOG(INFO) << "adb watchdog armed, triggering in " << g_watchdog_timeout_seconds 58 << " seconds"; 59 alarm(g_watchdog_timeout_seconds); 60 alarm_set = true; 61 }; 62 63 static auto Disarm = []() { 64 unsigned int previous = alarm(0); 65 if (previous != 0) { 66 LOG(INFO) << "adb watchdog disarmed with " << previous << " seconds left"; 67 } 68 alarm_set = false; 69 }; 70 71 bool watchdog_enabled = android::base::GetBoolProperty( 72 kAdbWatchdogProperty, android::base::GetBoolProperty(kTestHarnessProperty, false)); 73 if (!watchdog_enabled) { 74 if (alarm_set) { 75 Disarm(); 76 } 77 return; 78 } 79 80 if (g_watchdog_running) { 81 if (!alarm_set) { 82 Arm(); 83 } 84 } else { 85 Disarm(); 86 } 87 } 88 89 namespace watchdog { 90 91 void Start() { 92 std::lock_guard<std::mutex> lock(g_watchdog_mutex); 93 g_watchdog_running = true; 94 UpdateWatchdog(); 95 } 96 97 void Stop() { 98 std::lock_guard<std::mutex> lock(g_watchdog_mutex); 99 g_watchdog_running = false; 100 UpdateWatchdog(); 101 } 102 103 void Initialize() { 104 for (auto& property : {kAdbWatchdogProperty, kTestHarnessProperty}) { 105 g_property_monitor.Add(property, [property](std::string value) { 106 LOG(INFO) << property << " set to '" << value << "'"; 107 108 std::lock_guard<std::mutex> lock(g_watchdog_mutex); 109 UpdateWatchdog(); 110 return true; 111 }); 112 } 113 114 g_property_monitor.Add("persist.adb.watchdog.timeout_secs", [](std::string value) { 115 // This presumably isn't going to change while the watchdog is armed, 116 // so we don't need to recalculate a timer. 117 { 118 std::lock_guard<std::mutex> lock(g_watchdog_mutex); 119 if (!android::base::ParseUint(value, &g_watchdog_timeout_seconds)) { 120 g_watchdog_timeout_seconds = kDefaultAdbWatchdogTimeoutSeconds; 121 } 122 } 123 124 LOG(INFO) << "adb watchdog timeout set to " << g_watchdog_timeout_seconds << " seconds"; 125 return true; 126 }); 127 128 Start(); 129 std::thread([]() { g_property_monitor.Run(); }).detach(); 130 } 131 132 } // namespace watchdog 133