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