1 /* 2 * Copyright (C) 2022 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 /** 18 * The CameraService watchdog is used to help detect bad states in the 19 * Camera HAL. The threadloop uses cycle counters, assigned to each calling 20 * thread, to monitor the elapsing time and kills the process when the 21 * expected duration has exceeded. 22 * Notes on multi-threaded behaviors: 23 * - The threadloop is blocked/paused when there are no calls being 24 * monitored (when the TID cycle to counter map is empty). 25 * - The start and stop functions handle simultaneous call monitoring 26 * and single call monitoring differently. See function documentation for 27 * more details. 28 * To disable/enable: 29 * - adb shell cmd media.camera set-cameraservice-watchdog [0/1] 30 */ 31 #pragma once 32 #include <chrono> 33 #include <thread> 34 #include <time.h> 35 #include <utils/Thread.h> 36 #include <utils/Log.h> 37 #include <unordered_map> 38 39 // Used to wrap the call of interest in start and stop calls 40 #define WATCH(toMonitor) watchThread([&]() { return toMonitor;}, gettid()) 41 #define WATCH_CUSTOM_TIMER(toMonitor, cycles, cycleLength) \ 42 watchThread([&]() { return toMonitor;}, gettid(), cycles, cycleLength); 43 44 // Default cycles and cycle length values used to calculate permitted elapsed time 45 const static size_t kMaxCycles = 100; 46 const static uint32_t kCycleLengthMs = 100; 47 48 namespace android { 49 50 class CameraServiceWatchdog : public Thread { 51 52 public: CameraServiceWatchdog()53 explicit CameraServiceWatchdog() : mPause(true), mMaxCycles(kMaxCycles), 54 mCycleLengthMs(kCycleLengthMs), mEnabled(true) {}; 55 CameraServiceWatchdog(size_t maxCycles,uint32_t cycleLengthMs,bool enabled)56 explicit CameraServiceWatchdog (size_t maxCycles, uint32_t cycleLengthMs, bool enabled) : 57 mPause(true), mMaxCycles(maxCycles), mCycleLengthMs(cycleLengthMs), mEnabled(enabled) 58 {}; 59 ~CameraServiceWatchdog()60 virtual ~CameraServiceWatchdog() {}; 61 62 virtual void requestExit(); 63 64 /** Enables/disables the watchdog */ 65 void setEnabled(bool enable); 66 67 /** Used to wrap monitored calls in start and stop functions using custom timer values */ 68 template<typename T> watchThread(T func,uint32_t tid,uint32_t cycles,uint32_t cycleLength)69 auto watchThread(T func, uint32_t tid, uint32_t cycles, uint32_t cycleLength) { 70 decltype(func()) res; 71 72 if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) { 73 // Create another instance of the watchdog to prevent disruption 74 // of timer for current monitored calls 75 76 // Lock for mEnabled 77 mEnabledLock.lock(); 78 sp<CameraServiceWatchdog> tempWatchdog = 79 new CameraServiceWatchdog(cycles, cycleLength, mEnabled); 80 mEnabledLock.unlock(); 81 82 status_t status = tempWatchdog->run("CameraServiceWatchdog"); 83 if (status != OK) { 84 ALOGE("Unable to watch thread: %s (%d)", strerror(-status), status); 85 res = watchThread(func, tid); 86 return res; 87 } 88 89 res = tempWatchdog->watchThread(func, tid); 90 tempWatchdog->requestExit(); 91 tempWatchdog.clear(); 92 } else { 93 // If custom timer values are equivalent to set class timer values, use 94 // current thread 95 res = watchThread(func, tid); 96 } 97 98 return res; 99 } 100 101 /** Used to wrap monitored calls in start and stop functions using class timer values */ 102 template<typename T> watchThread(T func,uint32_t tid)103 auto watchThread(T func, uint32_t tid) { 104 decltype(func()) res; 105 AutoMutex _l(mEnabledLock); 106 107 if (mEnabled) { 108 start(tid); 109 res = func(); 110 stop(tid); 111 } else { 112 res = func(); 113 } 114 115 return res; 116 } 117 118 private: 119 120 /** 121 * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused, 122 * start() unblocks and starts the watchdog 123 */ 124 void start(uint32_t tid); 125 126 /** 127 * If there are no calls left to be monitored, stop blocks/pauses threadloop 128 * otherwise stop() erases the cycle counter to end watchdog for the calling thread 129 */ 130 void stop(uint32_t tid); 131 132 virtual bool threadLoop(); 133 134 Mutex mWatchdogLock; // Lock for condition variable 135 Mutex mEnabledLock; // Lock for enabled status 136 Condition mWatchdogCondition; // Condition variable for stop/start 137 bool mPause; // True if tid map is empty 138 uint32_t mMaxCycles; // Max cycles 139 uint32_t mCycleLengthMs; // Length of time elapsed per cycle 140 bool mEnabled; // True if watchdog is enabled 141 142 std::unordered_map<uint32_t, uint32_t> tidToCycleCounterMap; // Thread Id to cycle counter map 143 }; 144 145 } // namespace android 146