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