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