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 35 StatusTracker::StatusTracker(wp<Camera3Device> parent) : 36 mComponentsChanged(false), 37 mParent(parent), 38 mNextComponentId(0), 39 mIdleFence(new Fence()), 40 mDeviceState(IDLE) { 41 } 42 43 StatusTracker::~StatusTracker() { 44 } 45 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 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 86 void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) { 87 markComponent(id, IDLE, componentFence); 88 } 89 90 void StatusTracker::markComponentActive(int id) { 91 markComponent(id, ACTIVE, Fence::NO_FENCE); 92 } 93 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 110 void StatusTracker::requestExit() { 111 // First mark thread dead 112 Thread::requestExit(); 113 // Then exit any waits 114 mPendingChangeSignal.signal(); 115 } 116 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 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