You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
7.2 KiB
236 lines
7.2 KiB
/*
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "Camera3-Status"
|
|
#define ATRACE_TAG ATRACE_TAG_CAMERA
|
|
//#define LOG_NDEBUG 0
|
|
|
|
#include <utils/Log.h>
|
|
#include <utils/Trace.h>
|
|
#include <ui/Fence.h>
|
|
|
|
#include "device3/StatusTracker.h"
|
|
#include "device3/Camera3Device.h"
|
|
|
|
namespace android {
|
|
|
|
namespace camera3 {
|
|
|
|
StatusTracker::StatusTracker(wp<Camera3Device> parent) :
|
|
mComponentsChanged(false),
|
|
mParent(parent),
|
|
mNextComponentId(0),
|
|
mIdleFence(new Fence()),
|
|
mDeviceState(IDLE) {
|
|
}
|
|
|
|
StatusTracker::~StatusTracker() {
|
|
}
|
|
|
|
int StatusTracker::addComponent(std::string componentName) {
|
|
int id;
|
|
ssize_t err;
|
|
{
|
|
Mutex::Autolock l(mLock);
|
|
id = mNextComponentId++;
|
|
ALOGV("%s: Adding new component %d", __FUNCTION__, id);
|
|
|
|
err = mStates.add(id, IDLE);
|
|
if (componentName.empty()) {
|
|
componentName = std::to_string(id);
|
|
}
|
|
mComponentNames.add(id, componentName);
|
|
ALOGE_IF(err < 0, "%s: Can't add new component %d (%s): %s (%zd)",
|
|
__FUNCTION__, id, componentName.c_str(), strerror(-err), err);
|
|
}
|
|
|
|
if (err >= 0) {
|
|
Mutex::Autolock pl(mPendingLock);
|
|
mComponentsChanged = true;
|
|
mPendingChangeSignal.signal();
|
|
}
|
|
|
|
return err < 0 ? err : id;
|
|
}
|
|
|
|
void StatusTracker::removeComponent(int id) {
|
|
ssize_t idx;
|
|
{
|
|
Mutex::Autolock l(mLock);
|
|
ALOGV("%s: Removing component %d", __FUNCTION__, id);
|
|
idx = mStates.removeItem(id);
|
|
mComponentNames.removeItem(id);
|
|
}
|
|
|
|
if (idx >= 0) {
|
|
Mutex::Autolock pl(mPendingLock);
|
|
mComponentsChanged = true;
|
|
mPendingChangeSignal.signal();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void StatusTracker::dumpActiveComponents() {
|
|
Mutex::Autolock l(mLock);
|
|
if (mDeviceState == IDLE) {
|
|
ALOGI("%s: all components are IDLE", __FUNCTION__);
|
|
return;
|
|
}
|
|
for (size_t i = 0; i < mStates.size(); i++) {
|
|
if (mStates.valueAt(i) == ACTIVE) {
|
|
ALOGI("%s: component %d (%s) is active", __FUNCTION__, mStates.keyAt(i),
|
|
mComponentNames.valueAt(i).c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
|
|
markComponent(id, IDLE, componentFence);
|
|
}
|
|
|
|
void StatusTracker::markComponentActive(int id) {
|
|
markComponent(id, ACTIVE, Fence::NO_FENCE);
|
|
}
|
|
|
|
void StatusTracker::markComponent(int id, ComponentState state,
|
|
const sp<Fence>& componentFence) {
|
|
ALOGV("%s: Component %d is now %s", __FUNCTION__, id,
|
|
state == IDLE ? "idle" : "active");
|
|
Mutex::Autolock l(mPendingLock);
|
|
|
|
StateChange newState = {
|
|
id,
|
|
state,
|
|
componentFence
|
|
};
|
|
|
|
mPendingChangeQueue.add(newState);
|
|
mPendingChangeSignal.signal();
|
|
}
|
|
|
|
void StatusTracker::requestExit() {
|
|
// First mark thread dead
|
|
Thread::requestExit();
|
|
// Then exit any waits
|
|
mPendingChangeSignal.signal();
|
|
}
|
|
|
|
StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() {
|
|
for (size_t i = 0; i < mStates.size(); i++) {
|
|
if (mStates.valueAt(i) == ACTIVE) {
|
|
ALOGV("%s: Component %d not idle", __FUNCTION__,
|
|
mStates.keyAt(i));
|
|
return ACTIVE;
|
|
}
|
|
}
|
|
// - If not yet signaled, getSignalTime returns INT64_MAX
|
|
// - If invalid fence or error, returns -1
|
|
// - Otherwise returns time of signalling.
|
|
// Treat -1 as 'signalled', since HAL may not be using fences, and want
|
|
// to be able to idle in case of errors.
|
|
nsecs_t signalTime = mIdleFence->getSignalTime();
|
|
bool fencesDone = signalTime != INT64_MAX;
|
|
|
|
ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__);
|
|
|
|
return fencesDone ? IDLE : ACTIVE;
|
|
}
|
|
|
|
bool StatusTracker::threadLoop() {
|
|
status_t res;
|
|
|
|
// Wait for state updates
|
|
{
|
|
Mutex::Autolock pl(mPendingLock);
|
|
while (mPendingChangeQueue.size() == 0 && !mComponentsChanged) {
|
|
res = mPendingChangeSignal.waitRelative(mPendingLock,
|
|
kWaitDuration);
|
|
if (exitPending()) return false;
|
|
if (res != OK) {
|
|
if (res != TIMED_OUT) {
|
|
ALOGE("%s: Error waiting on state changes: %s (%d)",
|
|
__FUNCTION__, strerror(-res), res);
|
|
}
|
|
// TIMED_OUT is expected
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// After new pending states appear, or timeout, check if we're idle. Even
|
|
// with timeout, need to check to account for fences that may still be
|
|
// clearing out
|
|
sp<Camera3Device> parent;
|
|
{
|
|
Mutex::Autolock pl(mPendingLock);
|
|
Mutex::Autolock l(mLock);
|
|
|
|
// Collect all pending state updates and see if the device
|
|
// collectively transitions between idle and active for each one
|
|
|
|
// First pass for changed components or fence completions
|
|
ComponentState prevState = getDeviceStateLocked();
|
|
if (prevState != mDeviceState) {
|
|
// Only collect changes to overall device state
|
|
mStateTransitions.add(prevState);
|
|
}
|
|
// For each pending component state update, check if we've transitioned
|
|
// to a new overall device state
|
|
for (size_t i = 0; i < mPendingChangeQueue.size(); i++) {
|
|
const StateChange &newState = mPendingChangeQueue[i];
|
|
ssize_t idx = mStates.indexOfKey(newState.id);
|
|
// Ignore notices for unknown components
|
|
if (idx >= 0) {
|
|
// Update single component state
|
|
mStates.replaceValueAt(idx, newState.state);
|
|
mIdleFence = Fence::merge(String8("idleFence"),
|
|
mIdleFence, newState.fence);
|
|
// .. and see if overall device state has changed
|
|
ComponentState newState = getDeviceStateLocked();
|
|
if (newState != prevState) {
|
|
mStateTransitions.add(newState);
|
|
}
|
|
prevState = newState;
|
|
}
|
|
}
|
|
mPendingChangeQueue.clear();
|
|
mComponentsChanged = false;
|
|
|
|
// Store final state after all pending state changes are done with
|
|
|
|
mDeviceState = prevState;
|
|
parent = mParent.promote();
|
|
}
|
|
|
|
// Notify parent for all intermediate transitions
|
|
if (mStateTransitions.size() > 0 && parent.get()) {
|
|
for (size_t i = 0; i < mStateTransitions.size(); i++) {
|
|
bool idle = (mStateTransitions[i] == IDLE);
|
|
ALOGV("Camera device is now %s", idle ? "idle" : "active");
|
|
parent->notifyStatus(idle);
|
|
}
|
|
}
|
|
mStateTransitions.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace android
|
|
|
|
} // namespace camera3
|