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