xref: /aosp_15_r20/frameworks/av/services/camera/libcameraservice/CameraServiceWatchdog.h (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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-watchdog [0/1]
30  */
31 #pragma once
32 #include <chrono>
33 #include <set>
34 #include <thread>
35 #include <time.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     = 650;
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:
61 
CameraServiceWatchdog(const std::set<pid_t> & pids,const std::string & cameraId,std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper)62     explicit CameraServiceWatchdog(const std::set<pid_t> &pids, const std::string &cameraId,
63             std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
64                     mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
65                     mCycleLengthMs(kCycleLengthMs), mEnabled(true),
66                     mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
67 
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     explicit CameraServiceWatchdog (const std::set<pid_t> &pids, const std::string &cameraId,
69             size_t maxCycles, uint32_t cycleLengthMs, bool enabled,
70             std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
71                     mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
72                     mCycleLengthMs(cycleLengthMs), mEnabled(enabled),
73                     mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
74 
~CameraServiceWatchdog()75     virtual ~CameraServiceWatchdog() {};
76 
77     virtual void requestExit();
78 
79     /** Enables/disables the watchdog */
80     void setEnabled(bool enable);
81 
82     /** Used to wrap monitored calls in start and stop functions using custom timer values */
83     template<typename T>
watchThread(T func,uint32_t tid,const char * functionName,uint32_t cycles,uint32_t cycleLength)84     auto watchThread(T func, uint32_t tid, const char* functionName, uint32_t cycles,
85             uint32_t cycleLength) {
86         decltype(func()) res;
87 
88         if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) {
89             // Create another instance of the watchdog to prevent disruption
90             // of timer for current monitored calls
91 
92             // Lock for mEnabled
93             mEnabledLock.lock();
94             sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog(
95                     mProviderPids, mCameraId, cycles, cycleLength, mEnabled,
96                     mCameraServiceProxyWrapper);
97             mEnabledLock.unlock();
98 
99             status_t status = tempWatchdog->run("CameraServiceWatchdog");
100             if (status != OK) {
101                 ALOGE("Unable to watch thread: %s (%d)", strerror(-status), status);
102                 res = watchThread(func, tid, functionName);
103                 return res;
104             }
105 
106             res = tempWatchdog->watchThread(func, tid, functionName);
107             tempWatchdog->requestExit();
108             tempWatchdog.clear();
109         } else {
110             // If custom timer values are equivalent to set class timer values, use
111             // current thread
112             res = watchThread(func, tid, functionName);
113         }
114 
115         return res;
116     }
117 
118     /** Used to wrap monitored calls in start and stop functions using class timer values */
119     template<typename T>
watchThread(T func,uint32_t tid,const char * functionName)120     auto watchThread(T func, uint32_t tid, const char* functionName) {
121         decltype(func()) res;
122         AutoMutex _l(mEnabledLock);
123 
124         if (mEnabled) {
125             start(tid, functionName);
126             res = func();
127             stop(tid);
128         } else {
129             res = func();
130         }
131 
132         return res;
133     }
134 
135 private:
136 
137     /**
138      * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused,
139      * start() unblocks and starts the watchdog
140      */
141     void start(uint32_t tid, const char* functionName);
142 
143     /**
144      * If there are no calls left to be monitored, stop blocks/pauses threadloop
145      * otherwise stop() erases the cycle counter to end watchdog for the calling thread
146      */
147     void stop(uint32_t tid);
148 
149     std::string getAbortMessage(const std::string& functionName);
150 
151     virtual bool    threadLoop();
152 
153     Mutex           mWatchdogLock;      // Lock for condition variable
154     Mutex           mEnabledLock;       // Lock for enabled status
155     Condition       mWatchdogCondition; // Condition variable for stop/start
156     std::set<pid_t> mProviderPids;      // Process ID set of camera providers
157     std::string     mCameraId;          // Camera Id the watchdog belongs to
158     bool            mPause;             // True if tid map is empty
159     uint32_t        mMaxCycles;         // Max cycles
160     uint32_t        mCycleLengthMs;     // Length of time elapsed per cycle
161     bool            mEnabled;           // True if watchdog is enabled
162 
163     std::shared_ptr<CameraServiceProxyWrapper> mCameraServiceProxyWrapper;
164 
165     std::unordered_map<uint32_t, MonitoredFunction> mTidMap; // Thread Id to MonitoredFunction type
166                                                              // which retrieves the num of cycles
167                                                              // and name of the function
168 };
169 
170 }   // namespace android
171