blob: ab5419f42c9090b4130c15cec22f9f71e8ea990c [file] [log] [blame]
Eino-Ville Talvalaf1e98d82013-09-06 09:32:43 -07001/*
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// This is needed for stdint.h to define INT64_MAX in C++
22#define __STDC_LIMIT_MACROS
23
24#include <utils/Log.h>
25#include <utils/Trace.h>
26#include <ui/Fence.h>
27
28#include "device3/StatusTracker.h"
29#include "device3/Camera3Device.h"
30
31namespace android {
32
33namespace camera3 {
34
35StatusTracker::StatusTracker(wp<Camera3Device> parent) :
36 mComponentsChanged(false),
37 mParent(parent),
38 mNextComponentId(0),
39 mIdleFence(new Fence()),
40 mDeviceState(IDLE) {
41}
42
43StatusTracker::~StatusTracker() {
44}
45
46int StatusTracker::addComponent() {
47 int id;
48 ssize_t err;
49 {
50 Mutex::Autolock l(mLock);
51 id = mNextComponentId++;
52 ALOGV("%s: Adding new component %d", __FUNCTION__, id);
53
54 err = mStates.add(id, IDLE);
55 ALOGE_IF(err < 0, "%s: Can't add new component %d: %s (%d)",
56 __FUNCTION__, id, strerror(-err), err);
57 }
58
59 if (err >= 0) {
60 Mutex::Autolock pl(mPendingLock);
61 mComponentsChanged = true;
62 mPendingChangeSignal.signal();
63 }
64
65 return err < 0 ? err : id;
66}
67
68void StatusTracker::removeComponent(int id) {
69 ssize_t idx;
70 {
71 Mutex::Autolock l(mLock);
72 ALOGV("%s: Removing component %d", __FUNCTION__, id);
73 idx = mStates.removeItem(id);
74 }
75
76 if (idx >= 0) {
77 Mutex::Autolock pl(mPendingLock);
78 mComponentsChanged = true;
79 mPendingChangeSignal.signal();
80 }
81
82 return;
83}
84
85
86void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
87 markComponent(id, IDLE, componentFence);
88}
89
90void StatusTracker::markComponentActive(int id) {
91 markComponent(id, ACTIVE, Fence::NO_FENCE);
92}
93
94void StatusTracker::markComponent(int id, ComponentState state,
95 const sp<Fence>& componentFence) {
96 ALOGV("%s: Component %d is now %s", __FUNCTION__, id,
97 state == IDLE ? "idle" : "active");
98 Mutex::Autolock l(mPendingLock);
99
100 StateChange newState = {
101 id,
102 state,
103 componentFence
104 };
105
106 mPendingChangeQueue.add(newState);
107 mPendingChangeSignal.signal();
108}
109
110void StatusTracker::requestExit() {
111 // First mark thread dead
112 Thread::requestExit();
113 // Then exit any waits
114 mPendingChangeSignal.signal();
115}
116
117StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() {
118 for (size_t i = 0; i < mStates.size(); i++) {
119 if (mStates.valueAt(i) == ACTIVE) {
120 ALOGV("%s: Component %d not idle", __FUNCTION__,
121 mStates.keyAt(i));
122 return ACTIVE;
123 }
124 }
125 // - If not yet signaled, getSignalTime returns INT64_MAX
126 // - If invalid fence or error, returns -1
127 // - Otherwise returns time of signalling.
128 // Treat -1 as 'signalled', since HAL may not be using fences, and want
129 // to be able to idle in case of errors.
130 nsecs_t signalTime = mIdleFence->getSignalTime();
131 bool fencesDone = signalTime != INT64_MAX;
132
133 ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__);
134
135 return fencesDone ? IDLE : ACTIVE;
136}
137
138bool StatusTracker::threadLoop() {
139 status_t res;
140
141 // Wait for state updates
142 {
143 Mutex::Autolock pl(mPendingLock);
144 while (mPendingChangeQueue.size() == 0 && !mComponentsChanged) {
145 res = mPendingChangeSignal.waitRelative(mPendingLock,
146 kWaitDuration);
147 if (exitPending()) return false;
148 if (res != OK) {
149 if (res != TIMED_OUT) {
150 ALOGE("%s: Error waiting on state changes: %s (%d)",
151 __FUNCTION__, strerror(-res), res);
152 }
153 // TIMED_OUT is expected
154 break;
155 }
156 }
157 }
158
159 // After new pending states appear, or timeout, check if we're idle. Even
160 // with timeout, need to check to account for fences that may still be
161 // clearing out
162 sp<Camera3Device> parent;
163 {
164 Mutex::Autolock pl(mPendingLock);
165 Mutex::Autolock l(mLock);
166
167 // Collect all pending state updates and see if the device
168 // collectively transitions between idle and active for each one
169
170 // First pass for changed components or fence completions
171 ComponentState prevState = getDeviceStateLocked();
172 if (prevState != mDeviceState) {
173 // Only collect changes to overall device state
174 mStateTransitions.add(prevState);
175 }
176 // For each pending component state update, check if we've transitioned
177 // to a new overall device state
178 for (size_t i = 0; i < mPendingChangeQueue.size(); i++) {
179 const StateChange &newState = mPendingChangeQueue[i];
180 ssize_t idx = mStates.indexOfKey(newState.id);
181 // Ignore notices for unknown components
182 if (idx >= 0) {
183 // Update single component state
184 mStates.replaceValueAt(idx, newState.state);
185 mIdleFence = Fence::merge(String8("idleFence"),
186 mIdleFence, newState.fence);
187 // .. and see if overall device state has changed
188 ComponentState newState = getDeviceStateLocked();
189 if (newState != prevState) {
190 mStateTransitions.add(newState);
191 }
192 prevState = newState;
193 }
194 }
195 mPendingChangeQueue.clear();
196 mComponentsChanged = false;
197
198 // Store final state after all pending state changes are done with
199
200 mDeviceState = prevState;
201 parent = mParent.promote();
202 }
203
204 // Notify parent for all intermediate transitions
205 if (mStateTransitions.size() > 0 && parent.get()) {
206 for (size_t i = 0; i < mStateTransitions.size(); i++) {
207 bool idle = (mStateTransitions[i] == IDLE);
208 ALOGV("Camera device is now %s", idle ? "idle" : "active");
209 parent->notifyStatus(idle);
210 }
211 }
212 mStateTransitions.clear();
213
214 return true;
215}
216
217} // namespace android
218
219} // namespace camera3