StatusTracker.cpp revision f1e98d857ec377f2c9b916073d40732e6ebb7ced
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// 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
220