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/String8.h> 36 #include <utils/Thread.h> 37 #include <utils/Log.h> 38 #include <unordered_map> 39 40 #include "utils/CameraServiceProxyWrapper.h" 41 42 // Used to wrap the call of interest in start and stop calls 43 #define WATCH(toMonitor) watchThread([&]() { return toMonitor;}, gettid(), __FUNCTION__) 44 #define WATCH_CUSTOM_TIMER(toMonitor, cycles, cycleLength) \ 45 watchThread([&]() { return toMonitor;}, gettid(), __FUNCTION__, cycles, cycleLength); 46 47 // Default cycles and cycle length values used to calculate permitted elapsed time 48 const static size_t kMaxCycles = 100; 49 const static uint32_t kCycleLengthMs = 100; 50 51 namespace android { 52 53 class CameraServiceWatchdog : public Thread { 54 55 struct MonitoredFunction { 56 uint32_t cycles; 57 std::string functionName; 58 }; 59 60 public: CameraServiceWatchdog(const String8 & cameraId,std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper)61 explicit CameraServiceWatchdog(const String8 &cameraId, 62 std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) : 63 mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles), 64 mCycleLengthMs(kCycleLengthMs), mEnabled(true), 65 mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {}; 66 CameraServiceWatchdog(const String8 & cameraId,size_t maxCycles,uint32_t cycleLengthMs,bool enabled,std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper)67 explicit CameraServiceWatchdog (const String8 &cameraId, size_t maxCycles, 68 uint32_t cycleLengthMs, bool enabled, 69 std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) : 70 mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles), 71 mCycleLengthMs(cycleLengthMs), mEnabled(enabled), 72 mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {}; 73 ~CameraServiceWatchdog()74 virtual ~CameraServiceWatchdog() {}; 75 76 virtual void requestExit(); 77 78 /** Enables/disables the watchdog */ 79 void setEnabled(bool enable); 80 81 /** Used to wrap monitored calls in start and stop functions using custom timer values */ 82 template<typename T> watchThread(T func,uint32_t tid,const char * functionName,uint32_t cycles,uint32_t cycleLength)83 auto watchThread(T func, uint32_t tid, const char* functionName, uint32_t cycles, 84 uint32_t cycleLength) { 85 decltype(func()) res; 86 87 if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) { 88 // Create another instance of the watchdog to prevent disruption 89 // of timer for current monitored calls 90 91 // Lock for mEnabled 92 mEnabledLock.lock(); 93 sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog( 94 mCameraId, cycles, cycleLength, mEnabled, mCameraServiceProxyWrapper); 95 mEnabledLock.unlock(); 96 97 status_t status = tempWatchdog->run("CameraServiceWatchdog"); 98 if (status != OK) { 99 ALOGE("Unable to watch thread: %s (%d)", strerror(-status), status); 100 res = watchThread(func, tid, functionName); 101 return res; 102 } 103 104 res = tempWatchdog->watchThread(func, tid, functionName); 105 tempWatchdog->requestExit(); 106 tempWatchdog.clear(); 107 } else { 108 // If custom timer values are equivalent to set class timer values, use 109 // current thread 110 res = watchThread(func, tid, functionName); 111 } 112 113 return res; 114 } 115 116 /** Used to wrap monitored calls in start and stop functions using class timer values */ 117 template<typename T> watchThread(T func,uint32_t tid,const char * functionName)118 auto watchThread(T func, uint32_t tid, const char* functionName) { 119 decltype(func()) res; 120 AutoMutex _l(mEnabledLock); 121 122 if (mEnabled) { 123 start(tid, functionName); 124 res = func(); 125 stop(tid); 126 } else { 127 res = func(); 128 } 129 130 return res; 131 } 132 133 private: 134 135 /** 136 * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused, 137 * start() unblocks and starts the watchdog 138 */ 139 void start(uint32_t tid, const char* functionName); 140 141 /** 142 * If there are no calls left to be monitored, stop blocks/pauses threadloop 143 * otherwise stop() erases the cycle counter to end watchdog for the calling thread 144 */ 145 void stop(uint32_t tid); 146 147 std::string getAbortMessage(const std::string& functionName); 148 149 virtual bool threadLoop(); 150 151 Mutex mWatchdogLock; // Lock for condition variable 152 Mutex mEnabledLock; // Lock for enabled status 153 Condition mWatchdogCondition; // Condition variable for stop/start 154 String8 mCameraId; // Camera Id the watchdog belongs to 155 bool mPause; // True if tid map is empty 156 uint32_t mMaxCycles; // Max cycles 157 uint32_t mCycleLengthMs; // Length of time elapsed per cycle 158 bool mEnabled; // True if watchdog is enabled 159 160 std::shared_ptr<CameraServiceProxyWrapper> mCameraServiceProxyWrapper; 161 162 std::unordered_map<uint32_t, MonitoredFunction> mTidMap; // Thread Id to MonitoredFunction type 163 // which retrieves the num of cycles 164 // and name of the function 165 }; 166 167 } // namespace android 168