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