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