1*ec779b8eSAndroid Build Coastguard Worker /* 2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project 3*ec779b8eSAndroid Build Coastguard Worker * 4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*ec779b8eSAndroid Build Coastguard Worker * 8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*ec779b8eSAndroid Build Coastguard Worker * 10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License. 15*ec779b8eSAndroid Build Coastguard Worker */ 16*ec779b8eSAndroid Build Coastguard Worker 17*ec779b8eSAndroid Build Coastguard Worker /** 18*ec779b8eSAndroid Build Coastguard Worker * The CameraService watchdog is used to help detect bad states in the 19*ec779b8eSAndroid Build Coastguard Worker * Camera HAL. The threadloop uses cycle counters, assigned to each calling 20*ec779b8eSAndroid Build Coastguard Worker * thread, to monitor the elapsing time and kills the process when the 21*ec779b8eSAndroid Build Coastguard Worker * expected duration has exceeded. 22*ec779b8eSAndroid Build Coastguard Worker * Notes on multi-threaded behaviors: 23*ec779b8eSAndroid Build Coastguard Worker * - The threadloop is blocked/paused when there are no calls being 24*ec779b8eSAndroid Build Coastguard Worker * monitored (when the TID cycle to counter map is empty). 25*ec779b8eSAndroid Build Coastguard Worker * - The start and stop functions handle simultaneous call monitoring 26*ec779b8eSAndroid Build Coastguard Worker * and single call monitoring differently. See function documentation for 27*ec779b8eSAndroid Build Coastguard Worker * more details. 28*ec779b8eSAndroid Build Coastguard Worker * To disable/enable: 29*ec779b8eSAndroid Build Coastguard Worker * - adb shell cmd media.camera set-watchdog [0/1] 30*ec779b8eSAndroid Build Coastguard Worker */ 31*ec779b8eSAndroid Build Coastguard Worker #pragma once 32*ec779b8eSAndroid Build Coastguard Worker #include <chrono> 33*ec779b8eSAndroid Build Coastguard Worker #include <set> 34*ec779b8eSAndroid Build Coastguard Worker #include <thread> 35*ec779b8eSAndroid Build Coastguard Worker #include <time.h> 36*ec779b8eSAndroid Build Coastguard Worker #include <utils/Thread.h> 37*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h> 38*ec779b8eSAndroid Build Coastguard Worker #include <unordered_map> 39*ec779b8eSAndroid Build Coastguard Worker 40*ec779b8eSAndroid Build Coastguard Worker #include "utils/CameraServiceProxyWrapper.h" 41*ec779b8eSAndroid Build Coastguard Worker 42*ec779b8eSAndroid Build Coastguard Worker // Used to wrap the call of interest in start and stop calls 43*ec779b8eSAndroid Build Coastguard Worker #define WATCH(toMonitor) watchThread([&]() { return toMonitor;}, gettid(), __FUNCTION__) 44*ec779b8eSAndroid Build Coastguard Worker #define WATCH_CUSTOM_TIMER(toMonitor, cycles, cycleLength) \ 45*ec779b8eSAndroid Build Coastguard Worker watchThread([&]() { return toMonitor;}, gettid(), __FUNCTION__, cycles, cycleLength); 46*ec779b8eSAndroid Build Coastguard Worker 47*ec779b8eSAndroid Build Coastguard Worker // Default cycles and cycle length values used to calculate permitted elapsed time 48*ec779b8eSAndroid Build Coastguard Worker const static size_t kMaxCycles = 650; 49*ec779b8eSAndroid Build Coastguard Worker const static uint32_t kCycleLengthMs = 100; 50*ec779b8eSAndroid Build Coastguard Worker 51*ec779b8eSAndroid Build Coastguard Worker namespace android { 52*ec779b8eSAndroid Build Coastguard Worker 53*ec779b8eSAndroid Build Coastguard Worker class CameraServiceWatchdog : public Thread { 54*ec779b8eSAndroid Build Coastguard Worker 55*ec779b8eSAndroid Build Coastguard Worker struct MonitoredFunction { 56*ec779b8eSAndroid Build Coastguard Worker uint32_t cycles; 57*ec779b8eSAndroid Build Coastguard Worker std::string functionName; 58*ec779b8eSAndroid Build Coastguard Worker }; 59*ec779b8eSAndroid Build Coastguard Worker 60*ec779b8eSAndroid Build Coastguard Worker public: 61*ec779b8eSAndroid Build Coastguard Worker CameraServiceWatchdog(const std::set<pid_t> & pids,const std::string & cameraId,std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper)62*ec779b8eSAndroid Build Coastguard Worker explicit CameraServiceWatchdog(const std::set<pid_t> &pids, const std::string &cameraId, 63*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) : 64*ec779b8eSAndroid Build Coastguard Worker mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles), 65*ec779b8eSAndroid Build Coastguard Worker mCycleLengthMs(kCycleLengthMs), mEnabled(true), 66*ec779b8eSAndroid Build Coastguard Worker mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {}; 67*ec779b8eSAndroid Build Coastguard Worker CameraServiceWatchdog(const std::set<pid_t> & pids,const std::string & cameraId,size_t maxCycles,uint32_t cycleLengthMs,bool enabled,std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper)68*ec779b8eSAndroid Build Coastguard Worker explicit CameraServiceWatchdog (const std::set<pid_t> &pids, const std::string &cameraId, 69*ec779b8eSAndroid Build Coastguard Worker size_t maxCycles, uint32_t cycleLengthMs, bool enabled, 70*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) : 71*ec779b8eSAndroid Build Coastguard Worker mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles), 72*ec779b8eSAndroid Build Coastguard Worker mCycleLengthMs(cycleLengthMs), mEnabled(enabled), 73*ec779b8eSAndroid Build Coastguard Worker mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {}; 74*ec779b8eSAndroid Build Coastguard Worker ~CameraServiceWatchdog()75*ec779b8eSAndroid Build Coastguard Worker virtual ~CameraServiceWatchdog() {}; 76*ec779b8eSAndroid Build Coastguard Worker 77*ec779b8eSAndroid Build Coastguard Worker virtual void requestExit(); 78*ec779b8eSAndroid Build Coastguard Worker 79*ec779b8eSAndroid Build Coastguard Worker /** Enables/disables the watchdog */ 80*ec779b8eSAndroid Build Coastguard Worker void setEnabled(bool enable); 81*ec779b8eSAndroid Build Coastguard Worker 82*ec779b8eSAndroid Build Coastguard Worker /** Used to wrap monitored calls in start and stop functions using custom timer values */ 83*ec779b8eSAndroid Build Coastguard Worker template<typename T> watchThread(T func,uint32_t tid,const char * functionName,uint32_t cycles,uint32_t cycleLength)84*ec779b8eSAndroid Build Coastguard Worker auto watchThread(T func, uint32_t tid, const char* functionName, uint32_t cycles, 85*ec779b8eSAndroid Build Coastguard Worker uint32_t cycleLength) { 86*ec779b8eSAndroid Build Coastguard Worker decltype(func()) res; 87*ec779b8eSAndroid Build Coastguard Worker 88*ec779b8eSAndroid Build Coastguard Worker if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) { 89*ec779b8eSAndroid Build Coastguard Worker // Create another instance of the watchdog to prevent disruption 90*ec779b8eSAndroid Build Coastguard Worker // of timer for current monitored calls 91*ec779b8eSAndroid Build Coastguard Worker 92*ec779b8eSAndroid Build Coastguard Worker // Lock for mEnabled 93*ec779b8eSAndroid Build Coastguard Worker mEnabledLock.lock(); 94*ec779b8eSAndroid Build Coastguard Worker sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog( 95*ec779b8eSAndroid Build Coastguard Worker mProviderPids, mCameraId, cycles, cycleLength, mEnabled, 96*ec779b8eSAndroid Build Coastguard Worker mCameraServiceProxyWrapper); 97*ec779b8eSAndroid Build Coastguard Worker mEnabledLock.unlock(); 98*ec779b8eSAndroid Build Coastguard Worker 99*ec779b8eSAndroid Build Coastguard Worker status_t status = tempWatchdog->run("CameraServiceWatchdog"); 100*ec779b8eSAndroid Build Coastguard Worker if (status != OK) { 101*ec779b8eSAndroid Build Coastguard Worker ALOGE("Unable to watch thread: %s (%d)", strerror(-status), status); 102*ec779b8eSAndroid Build Coastguard Worker res = watchThread(func, tid, functionName); 103*ec779b8eSAndroid Build Coastguard Worker return res; 104*ec779b8eSAndroid Build Coastguard Worker } 105*ec779b8eSAndroid Build Coastguard Worker 106*ec779b8eSAndroid Build Coastguard Worker res = tempWatchdog->watchThread(func, tid, functionName); 107*ec779b8eSAndroid Build Coastguard Worker tempWatchdog->requestExit(); 108*ec779b8eSAndroid Build Coastguard Worker tempWatchdog.clear(); 109*ec779b8eSAndroid Build Coastguard Worker } else { 110*ec779b8eSAndroid Build Coastguard Worker // If custom timer values are equivalent to set class timer values, use 111*ec779b8eSAndroid Build Coastguard Worker // current thread 112*ec779b8eSAndroid Build Coastguard Worker res = watchThread(func, tid, functionName); 113*ec779b8eSAndroid Build Coastguard Worker } 114*ec779b8eSAndroid Build Coastguard Worker 115*ec779b8eSAndroid Build Coastguard Worker return res; 116*ec779b8eSAndroid Build Coastguard Worker } 117*ec779b8eSAndroid Build Coastguard Worker 118*ec779b8eSAndroid Build Coastguard Worker /** Used to wrap monitored calls in start and stop functions using class timer values */ 119*ec779b8eSAndroid Build Coastguard Worker template<typename T> watchThread(T func,uint32_t tid,const char * functionName)120*ec779b8eSAndroid Build Coastguard Worker auto watchThread(T func, uint32_t tid, const char* functionName) { 121*ec779b8eSAndroid Build Coastguard Worker decltype(func()) res; 122*ec779b8eSAndroid Build Coastguard Worker AutoMutex _l(mEnabledLock); 123*ec779b8eSAndroid Build Coastguard Worker 124*ec779b8eSAndroid Build Coastguard Worker if (mEnabled) { 125*ec779b8eSAndroid Build Coastguard Worker start(tid, functionName); 126*ec779b8eSAndroid Build Coastguard Worker res = func(); 127*ec779b8eSAndroid Build Coastguard Worker stop(tid); 128*ec779b8eSAndroid Build Coastguard Worker } else { 129*ec779b8eSAndroid Build Coastguard Worker res = func(); 130*ec779b8eSAndroid Build Coastguard Worker } 131*ec779b8eSAndroid Build Coastguard Worker 132*ec779b8eSAndroid Build Coastguard Worker return res; 133*ec779b8eSAndroid Build Coastguard Worker } 134*ec779b8eSAndroid Build Coastguard Worker 135*ec779b8eSAndroid Build Coastguard Worker private: 136*ec779b8eSAndroid Build Coastguard Worker 137*ec779b8eSAndroid Build Coastguard Worker /** 138*ec779b8eSAndroid Build Coastguard Worker * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused, 139*ec779b8eSAndroid Build Coastguard Worker * start() unblocks and starts the watchdog 140*ec779b8eSAndroid Build Coastguard Worker */ 141*ec779b8eSAndroid Build Coastguard Worker void start(uint32_t tid, const char* functionName); 142*ec779b8eSAndroid Build Coastguard Worker 143*ec779b8eSAndroid Build Coastguard Worker /** 144*ec779b8eSAndroid Build Coastguard Worker * If there are no calls left to be monitored, stop blocks/pauses threadloop 145*ec779b8eSAndroid Build Coastguard Worker * otherwise stop() erases the cycle counter to end watchdog for the calling thread 146*ec779b8eSAndroid Build Coastguard Worker */ 147*ec779b8eSAndroid Build Coastguard Worker void stop(uint32_t tid); 148*ec779b8eSAndroid Build Coastguard Worker 149*ec779b8eSAndroid Build Coastguard Worker std::string getAbortMessage(const std::string& functionName); 150*ec779b8eSAndroid Build Coastguard Worker 151*ec779b8eSAndroid Build Coastguard Worker virtual bool threadLoop(); 152*ec779b8eSAndroid Build Coastguard Worker 153*ec779b8eSAndroid Build Coastguard Worker Mutex mWatchdogLock; // Lock for condition variable 154*ec779b8eSAndroid Build Coastguard Worker Mutex mEnabledLock; // Lock for enabled status 155*ec779b8eSAndroid Build Coastguard Worker Condition mWatchdogCondition; // Condition variable for stop/start 156*ec779b8eSAndroid Build Coastguard Worker std::set<pid_t> mProviderPids; // Process ID set of camera providers 157*ec779b8eSAndroid Build Coastguard Worker std::string mCameraId; // Camera Id the watchdog belongs to 158*ec779b8eSAndroid Build Coastguard Worker bool mPause; // True if tid map is empty 159*ec779b8eSAndroid Build Coastguard Worker uint32_t mMaxCycles; // Max cycles 160*ec779b8eSAndroid Build Coastguard Worker uint32_t mCycleLengthMs; // Length of time elapsed per cycle 161*ec779b8eSAndroid Build Coastguard Worker bool mEnabled; // True if watchdog is enabled 162*ec779b8eSAndroid Build Coastguard Worker 163*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<CameraServiceProxyWrapper> mCameraServiceProxyWrapper; 164*ec779b8eSAndroid Build Coastguard Worker 165*ec779b8eSAndroid Build Coastguard Worker std::unordered_map<uint32_t, MonitoredFunction> mTidMap; // Thread Id to MonitoredFunction type 166*ec779b8eSAndroid Build Coastguard Worker // which retrieves the num of cycles 167*ec779b8eSAndroid Build Coastguard Worker // and name of the function 168*ec779b8eSAndroid Build Coastguard Worker }; 169*ec779b8eSAndroid Build Coastguard Worker 170*ec779b8eSAndroid Build Coastguard Worker } // namespace android 171