StatusTracker.cpp revision e5729fac81c8a984e984fefc90afc64135817d4f
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
28namespace android {
29
30namespace camera3 {
31
32StatusTracker::StatusTracker(wp<Camera3Device> parent) :
33        mComponentsChanged(false),
34        mParent(parent),
35        mNextComponentId(0),
36        mIdleFence(new Fence()),
37        mDeviceState(IDLE) {
38}
39
40StatusTracker::~StatusTracker() {
41}
42
43int 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
65void 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
83void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
84    markComponent(id, IDLE, componentFence);
85}
86
87void StatusTracker::markComponentActive(int id) {
88    markComponent(id, ACTIVE, Fence::NO_FENCE);
89}
90
91void 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
107void StatusTracker::requestExit() {
108    // First mark thread dead
109    Thread::requestExit();
110    // Then exit any waits
111    mPendingChangeSignal.signal();
112}
113
114StatusTracker::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
135bool 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