xref: /aosp_15_r20/frameworks/av/services/camera/libcameraservice/CameraServiceWatchdog.h (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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