• 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 #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(std::string componentName)43 int StatusTracker::addComponent(std::string componentName) {
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         if (componentName.empty()) {
53             componentName = std::to_string(id);
54         }
55         mComponentNames.add(id, componentName);
56         ALOGE_IF(err < 0, "%s: Can't add new component %d (%s): %s (%zd)",
57                 __FUNCTION__, id, componentName.c_str(), strerror(-err), err);
58     }
59 
60     if (err >= 0) {
61         Mutex::Autolock pl(mPendingLock);
62         mComponentsChanged = true;
63         mPendingChangeSignal.signal();
64     }
65 
66     return err < 0 ? err : id;
67 }
68 
removeComponent(int id)69 void StatusTracker::removeComponent(int id) {
70     ssize_t idx;
71     {
72         Mutex::Autolock l(mLock);
73         ALOGV("%s: Removing component %d", __FUNCTION__, id);
74         idx = mStates.removeItem(id);
75         mComponentNames.removeItem(id);
76     }
77 
78     if (idx >= 0) {
79         Mutex::Autolock pl(mPendingLock);
80         mComponentsChanged = true;
81         mPendingChangeSignal.signal();
82     }
83 
84     return;
85 }
86 
87 
dumpActiveComponents()88 void StatusTracker::dumpActiveComponents() {
89     Mutex::Autolock l(mLock);
90     if (mDeviceState == IDLE) {
91         ALOGI("%s: all components are IDLE", __FUNCTION__);
92         return;
93     }
94     for (size_t i = 0; i < mStates.size(); i++) {
95         if (mStates.valueAt(i) == ACTIVE) {
96             ALOGI("%s: component %d (%s) is active", __FUNCTION__, mStates.keyAt(i),
97                     mComponentNames.valueAt(i).c_str());
98         }
99     }
100 }
101 
markComponentIdle(int id,const sp<Fence> & componentFence)102 void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
103     markComponent(id, IDLE, componentFence);
104 }
105 
markComponentActive(int id)106 void StatusTracker::markComponentActive(int id) {
107     markComponent(id, ACTIVE, Fence::NO_FENCE);
108 }
109 
markComponent(int id,ComponentState state,const sp<Fence> & componentFence)110 void StatusTracker::markComponent(int id, ComponentState state,
111         const sp<Fence>& componentFence) {
112     ALOGV("%s: Component %d is now %s", __FUNCTION__, id,
113             state == IDLE ? "idle" : "active");
114     Mutex::Autolock l(mPendingLock);
115 
116     StateChange newState = {
117         id,
118         state,
119         componentFence
120     };
121 
122     mPendingChangeQueue.add(newState);
123     mPendingChangeSignal.signal();
124 }
125 
requestExit()126 void StatusTracker::requestExit() {
127     // First mark thread dead
128     Thread::requestExit();
129     // Then exit any waits
130     mPendingChangeSignal.signal();
131 }
132 
getDeviceStateLocked()133 StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() {
134     for (size_t i = 0; i < mStates.size(); i++) {
135         if (mStates.valueAt(i) == ACTIVE) {
136             ALOGV("%s: Component %d not idle", __FUNCTION__,
137                     mStates.keyAt(i));
138             return ACTIVE;
139         }
140     }
141     // - If not yet signaled, getSignalTime returns INT64_MAX
142     // - If invalid fence or error, returns -1
143     // - Otherwise returns time of signalling.
144     // Treat -1 as 'signalled', since HAL may not be using fences, and want
145     // to be able to idle in case of errors.
146     nsecs_t signalTime = mIdleFence->getSignalTime();
147     bool fencesDone = signalTime != INT64_MAX;
148 
149     ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__);
150 
151     return fencesDone ? IDLE : ACTIVE;
152 }
153 
threadLoop()154 bool StatusTracker::threadLoop() {
155     status_t res;
156 
157     // Wait for state updates
158     {
159         Mutex::Autolock pl(mPendingLock);
160         while (mPendingChangeQueue.size() == 0 && !mComponentsChanged) {
161             res = mPendingChangeSignal.waitRelative(mPendingLock,
162                     kWaitDuration);
163             if (exitPending()) return false;
164             if (res != OK) {
165                 if (res != TIMED_OUT) {
166                     ALOGE("%s: Error waiting on state changes: %s (%d)",
167                             __FUNCTION__, strerror(-res), res);
168                 }
169                 // TIMED_OUT is expected
170                 break;
171             }
172         }
173     }
174 
175     // After new pending states appear, or timeout, check if we're idle.  Even
176     // with timeout, need to check to account for fences that may still be
177     // clearing out
178     sp<Camera3Device> parent;
179     {
180         Mutex::Autolock pl(mPendingLock);
181         Mutex::Autolock l(mLock);
182 
183         // Collect all pending state updates and see if the device
184         // collectively transitions between idle and active for each one
185 
186         // First pass for changed components or fence completions
187         ComponentState prevState = getDeviceStateLocked();
188         if (prevState != mDeviceState) {
189             // Only collect changes to overall device state
190             mStateTransitions.add(prevState);
191         }
192         // For each pending component state update, check if we've transitioned
193         // to a new overall device state
194         for (size_t i = 0; i < mPendingChangeQueue.size(); i++) {
195             const StateChange &newState = mPendingChangeQueue[i];
196             ssize_t idx = mStates.indexOfKey(newState.id);
197             // Ignore notices for unknown components
198             if (idx >= 0) {
199                 // Update single component state
200                 mStates.replaceValueAt(idx, newState.state);
201                 mIdleFence = Fence::merge(String8("idleFence"),
202                         mIdleFence, newState.fence);
203                 // .. and see if overall device state has changed
204                 ComponentState newState = getDeviceStateLocked();
205                 if (newState != prevState) {
206                     mStateTransitions.add(newState);
207                 }
208                 prevState = newState;
209             }
210         }
211         mPendingChangeQueue.clear();
212         mComponentsChanged = false;
213 
214         // Store final state after all pending state changes are done with
215 
216         mDeviceState = prevState;
217         parent = mParent.promote();
218     }
219 
220     // Notify parent for all intermediate transitions
221     if (mStateTransitions.size() > 0 && parent.get()) {
222         for (size_t i = 0; i < mStateTransitions.size(); i++) {
223             bool idle = (mStateTransitions[i] == IDLE);
224             ALOGV("Camera device is now %s", idle ? "idle" : "active");
225             parent->notifyStatus(idle);
226         }
227     }
228     mStateTransitions.clear();
229 
230     return true;
231 }
232 
233 } // namespace android
234 
235 } // namespace camera3
236