blob: e55fa28f93915359b86e9f4e9a4c200177a54a33 [file] [log] [blame]
Ravneetdbd5b242022-03-02 07:22:46 +00001/*
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
Ravneetaeb20dc2022-03-30 05:33:03 +000024 * monitored (when the TID cycle to counter map is empty).
Ravneetdbd5b242022-03-02 07:22:46 +000025 * - The start and stop functions handle simultaneous call monitoring
26 * and single call monitoring differently. See function documentation for
27 * more details.
Ravneetaeb20dc2022-03-30 05:33:03 +000028 * To disable/enable:
29 * - adb shell cmd media.camera set-cameraservice-watchdog [0/1]
Ravneetdbd5b242022-03-02 07:22:46 +000030 */
Jayant Chowdhary620763f2022-05-27 05:37:14 +000031#pragma once
Ravneetdbd5b242022-03-02 07:22:46 +000032#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
45const static size_t kMaxCycles = 100;
46const static uint32_t kCycleLengthMs = 100;
47
48namespace android {
49
50class CameraServiceWatchdog : public Thread {
51
52public:
53 explicit CameraServiceWatchdog() : mPause(true), mMaxCycles(kMaxCycles),
Ravneetaeb20dc2022-03-30 05:33:03 +000054 mCycleLengthMs(kCycleLengthMs), mEnabled(true) {};
Ravneetdbd5b242022-03-02 07:22:46 +000055
Ravneetaeb20dc2022-03-30 05:33:03 +000056 explicit CameraServiceWatchdog (size_t maxCycles, uint32_t cycleLengthMs, bool enabled) :
57 mPause(true), mMaxCycles(maxCycles), mCycleLengthMs(cycleLengthMs), mEnabled(enabled)
58 {};
Ravneetdbd5b242022-03-02 07:22:46 +000059
60 virtual ~CameraServiceWatchdog() {};
61
62 virtual void requestExit();
63
Ravneetaeb20dc2022-03-30 05:33:03 +000064 /** Enables/disables the watchdog */
65 void setEnabled(bool enable);
66
Ravneetdbd5b242022-03-02 07:22:46 +000067 /** Used to wrap monitored calls in start and stop functions using custom timer values */
68 template<typename T>
69 auto watchThread(T func, uint32_t tid, uint32_t cycles, uint32_t cycleLength) {
Jayant Chowdhary620763f2022-05-27 05:37:14 +000070 decltype(func()) res;
Ravneetdbd5b242022-03-02 07:22:46 +000071
72 if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) {
73 // Create another instance of the watchdog to prevent disruption
74 // of timer for current monitored calls
Ravneetaeb20dc2022-03-30 05:33:03 +000075
76 // Lock for mEnabled
77 mEnabledLock.lock();
Ravneetdbd5b242022-03-02 07:22:46 +000078 sp<CameraServiceWatchdog> tempWatchdog =
Ravneetaeb20dc2022-03-30 05:33:03 +000079 new CameraServiceWatchdog(cycles, cycleLength, mEnabled);
80 mEnabledLock.unlock();
81
Ravneetdbd5b242022-03-02 07:22:46 +000082 tempWatchdog->run("CameraServiceWatchdog");
83 res = tempWatchdog->watchThread(func, tid);
84 tempWatchdog->requestExit();
85 tempWatchdog.clear();
86 } else {
87 // If custom timer values are equivalent to set class timer values, use
88 // current thread
89 res = watchThread(func, tid);
90 }
91
92 return res;
93 }
94
95 /** Used to wrap monitored calls in start and stop functions using class timer values */
96 template<typename T>
97 auto watchThread(T func, uint32_t tid) {
Jayant Chowdhary620763f2022-05-27 05:37:14 +000098 decltype(func()) res;
Ravneetaeb20dc2022-03-30 05:33:03 +000099 AutoMutex _l(mEnabledLock);
100
Ravneetaeb20dc2022-03-30 05:33:03 +0000101 if (mEnabled) {
102 start(tid);
103 res = func();
104 stop(tid);
105 } else {
106 res = func();
107 }
Ravneetdbd5b242022-03-02 07:22:46 +0000108
109 return res;
110 }
111
112private:
113
114 /**
115 * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused,
116 * start() unblocks and starts the watchdog
117 */
118 void start(uint32_t tid);
119
120 /**
121 * If there are no calls left to be monitored, stop blocks/pauses threadloop
122 * otherwise stop() erases the cycle counter to end watchdog for the calling thread
123 */
124 void stop(uint32_t tid);
125
126 virtual bool threadLoop();
127
Ravneetaeb20dc2022-03-30 05:33:03 +0000128 Mutex mWatchdogLock; // Lock for condition variable
129 Mutex mEnabledLock; // Lock for enabled status
130 Condition mWatchdogCondition; // Condition variable for stop/start
131 bool mPause; // True if tid map is empty
132 uint32_t mMaxCycles; // Max cycles
133 uint32_t mCycleLengthMs; // Length of time elapsed per cycle
134 bool mEnabled; // True if watchdog is enabled
Ravneetdbd5b242022-03-02 07:22:46 +0000135
136 std::unordered_map<uint32_t, uint32_t> tidToCycleCounterMap; // Thread Id to cycle counter map
137};
138
139} // namespace android