• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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