• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace android {
32 
33 namespace camera3 {
34 
StatusTracker(wp<Camera3Device> parent)35 StatusTracker::StatusTracker(wp<Camera3Device> parent) :
36         mComponentsChanged(false),
37         mParent(parent),
38         mNextComponentId(0),
39         mIdleFence(new Fence()),
40         mDeviceState(IDLE) {
41 }
42 
~StatusTracker()43 StatusTracker::~StatusTracker() {
44 }
45 
addComponent()46 int 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 
removeComponent(int id)68 void 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 
markComponentIdle(int id,const sp<Fence> & componentFence)86 void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
87     markComponent(id, IDLE, componentFence);
88 }
89 
markComponentActive(int id)90 void StatusTracker::markComponentActive(int id) {
91     markComponent(id, ACTIVE, Fence::NO_FENCE);
92 }
93 
markComponent(int id,ComponentState state,const sp<Fence> & componentFence)94 void 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 
requestExit()110 void StatusTracker::requestExit() {
111     // First mark thread dead
112     Thread::requestExit();
113     // Then exit any waits
114     mPendingChangeSignal.signal();
115 }
116 
getDeviceStateLocked()117 StatusTracker::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 
threadLoop()138 bool 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