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