1 /*
2 * Copyright (C) 2013 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 #define LOG_TAG "Camera3-Status"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20
21 #include <utils/Log.h>
22 #include <utils/Trace.h>
23 #include <ui/Fence.h>
24
25 #include "device3/StatusTracker.h"
26 #include "device3/Camera3Device.h"
27
28 namespace android {
29
30 namespace camera3 {
31
StatusTracker(wp<Camera3Device> parent)32 StatusTracker::StatusTracker(wp<Camera3Device> parent) :
33 mComponentsChanged(false),
34 mParent(parent),
35 mNextComponentId(0),
36 mIdleFence(new Fence()),
37 mDeviceState(IDLE),
38 mFlushed(true) {
39 }
40
~StatusTracker()41 StatusTracker::~StatusTracker() {
42 }
43
addComponent(std::string componentName)44 int StatusTracker::addComponent(std::string componentName) {
45 int id;
46 ssize_t err;
47 {
48 Mutex::Autolock l(mLock);
49 id = mNextComponentId++;
50 ALOGV("%s: Adding new component %d", __FUNCTION__, id);
51
52 err = mStates.add(id, IDLE);
53 if (componentName.empty()) {
54 componentName = std::to_string(id);
55 }
56 mComponentNames.add(id, componentName);
57 ALOGE_IF(err < 0, "%s: Can't add new component %d (%s): %s (%zd)",
58 __FUNCTION__, id, componentName.c_str(), strerror(-err), err);
59 }
60
61 if (err >= 0) {
62 Mutex::Autolock pl(mPendingLock);
63 mComponentsChanged = true;
64 mPendingChangeSignal.signal();
65 }
66
67 return err < 0 ? err : id;
68 }
69
removeComponent(int id)70 void StatusTracker::removeComponent(int id) {
71 ssize_t idx;
72 {
73 Mutex::Autolock l(mLock);
74 ALOGV("%s: Removing component %d", __FUNCTION__, id);
75 idx = mStates.removeItem(id);
76 mComponentNames.removeItem(id);
77 }
78
79 if (idx >= 0) {
80 Mutex::Autolock pl(mPendingLock);
81 mComponentsChanged = true;
82 mPendingChangeSignal.signal();
83 }
84
85 return;
86 }
87
88
dumpActiveComponents()89 void StatusTracker::dumpActiveComponents() {
90 Mutex::Autolock l(mLock);
91 if (mDeviceState == IDLE) {
92 ALOGI("%s: all components are IDLE", __FUNCTION__);
93 return;
94 }
95 for (size_t i = 0; i < mStates.size(); i++) {
96 if (mStates.valueAt(i) == ACTIVE) {
97 ALOGI("%s: component %d (%s) is active", __FUNCTION__, mStates.keyAt(i),
98 mComponentNames.valueAt(i).c_str());
99 }
100 }
101 }
102
markComponentIdle(int id,const sp<Fence> & componentFence)103 void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
104 markComponent(id, IDLE, componentFence);
105 }
106
markComponentActive(int id)107 void StatusTracker::markComponentActive(int id) {
108 markComponent(id, ACTIVE, Fence::NO_FENCE);
109 }
110
markComponent(int id,ComponentState state,const sp<Fence> & componentFence)111 void StatusTracker::markComponent(int id, ComponentState state,
112 const sp<Fence>& componentFence) {
113 ALOGV("%s: Component %d is now %s", __FUNCTION__, id,
114 state == IDLE ? "idle" : "active");
115
116 // If any component state changes, the status tracker is considered
117 // not flushed.
118 {
119 Mutex::Autolock l(mFlushLock);
120 mFlushed = false;
121 }
122
123 {
124 Mutex::Autolock l(mPendingLock);
125
126 StateChange newState = {
127 id,
128 state,
129 componentFence
130 };
131
132 mPendingChangeQueue.add(newState);
133 mPendingChangeSignal.signal();
134 }
135 }
136
flushPendingStates()137 void StatusTracker::flushPendingStates() {
138 Mutex::Autolock l(mFlushLock);
139 while (!mFlushed && isRunning()) {
140 mFlushCondition.waitRelative(mFlushLock, kWaitDuration);
141 }
142 }
143
requestExit()144 void StatusTracker::requestExit() {
145 // First mark thread dead
146 Thread::requestExit();
147 // Then exit any waits
148 mPendingChangeSignal.signal();
149 mFlushCondition.signal();
150 }
151
getDeviceStateLocked()152 StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() {
153 for (size_t i = 0; i < mStates.size(); i++) {
154 if (mStates.valueAt(i) == ACTIVE) {
155 ALOGV("%s: Component %d not idle", __FUNCTION__,
156 mStates.keyAt(i));
157 return ACTIVE;
158 }
159 }
160 // - If not yet signaled, getSignalTime returns INT64_MAX
161 // - If invalid fence or error, returns -1
162 // - Otherwise returns time of signalling.
163 // Treat -1 as 'signalled', since HAL may not be using fences, and want
164 // to be able to idle in case of errors.
165 nsecs_t signalTime = mIdleFence->getSignalTime();
166 bool fencesDone = signalTime != INT64_MAX;
167
168 ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__);
169
170 return fencesDone ? IDLE : ACTIVE;
171 }
172
threadLoop()173 bool StatusTracker::threadLoop() {
174 status_t res;
175
176 // Wait for state updates
177 {
178 Mutex::Autolock pl(mPendingLock);
179 while (mPendingChangeQueue.size() == 0 && !mComponentsChanged) {
180 res = mPendingChangeSignal.waitRelative(mPendingLock,
181 kWaitDuration);
182 if (exitPending()) return false;
183 if (res != OK) {
184 if (res != TIMED_OUT) {
185 ALOGE("%s: Error waiting on state changes: %s (%d)",
186 __FUNCTION__, strerror(-res), res);
187 }
188 // TIMED_OUT is expected
189 break;
190 }
191 }
192 }
193
194 bool waitForIdleFence = false;
195 // After new pending states appear, or timeout, check if we're idle. Even
196 // with timeout, need to check to account for fences that may still be
197 // clearing out
198 sp<Camera3Device> parent;
199 {
200 Mutex::Autolock pl(mPendingLock);
201 Mutex::Autolock l(mLock);
202
203 // Collect all pending state updates and see if the device
204 // collectively transitions between idle and active for each one
205
206 // First pass for changed components or fence completions
207 ComponentState prevState = getDeviceStateLocked();
208 if (prevState != mDeviceState) {
209 // Only collect changes to overall device state
210 mStateTransitions.add(prevState);
211 }
212 // For each pending component state update, check if we've transitioned
213 // to a new overall device state
214 for (size_t i = 0; i < mPendingChangeQueue.size(); i++) {
215 const StateChange &newState = mPendingChangeQueue[i];
216 ssize_t idx = mStates.indexOfKey(newState.id);
217 // Ignore notices for unknown components
218 if (idx >= 0) {
219 bool validFence = newState.fence != Fence::NO_FENCE;
220 // Update single component state
221 mStates.replaceValueAt(idx, newState.state);
222 mIdleFence = Fence::merge(String8("idleFence"),
223 mIdleFence, newState.fence);
224 // .. and see if overall device state has changed
225 ComponentState newState = getDeviceStateLocked();
226 if (newState != prevState) {
227 mStateTransitions.add(newState);
228 } else if (validFence && !waitForIdleFence) {
229 waitForIdleFence = true;
230 }
231 prevState = newState;
232 }
233 }
234 mPendingChangeQueue.clear();
235 mComponentsChanged = false;
236
237 // Store final state after all pending state changes are done with
238
239 mDeviceState = prevState;
240 parent = mParent.promote();
241 }
242
243 // Notify parent for all intermediate transitions
244 if (mStateTransitions.size() > 0 && parent.get()) {
245 for (size_t i = 0; i < mStateTransitions.size(); i++) {
246 bool idle = (mStateTransitions[i] == IDLE);
247 ALOGV("Camera device is now %s", idle ? "idle" : "active");
248 parent->notifyStatus(idle);
249 }
250 }
251 mStateTransitions.clear();
252
253 // After all pending changes are cleared and notified, mark the tracker
254 // as flushed.
255 {
256 Mutex::Autolock fl(mFlushLock);
257 Mutex::Autolock pl(mPendingLock);
258 if (mPendingChangeQueue.size() == 0) {
259 mFlushed = true;
260 mFlushCondition.signal();
261 }
262 }
263
264 if (waitForIdleFence) {
265 auto ret = mIdleFence->wait(kWaitDuration);
266 if (ret == NO_ERROR) {
267 mComponentsChanged = true;
268 }
269 }
270
271 return true;
272 }
273
274 } // namespace android
275
276 } // namespace camera3
277