blob: fbdac42f85343df05d4847da1e3c63da5d2a21c9 [file] [log] [blame]
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#define LOG_TAG "QCameraPerf"
// To remove
#include <cutils/properties.h>
#include <utils/Errors.h>
// System dependencies
#include <stdlib.h>
#include <dlfcn.h>
#include <utils/Timers.h>
// Camera dependencies
#include "QCameraPerf.h"
#include "QCameraTrace.h"
#include <android-base/properties.h>
extern "C" {
#include "mm_camera_dbg.h"
}
namespace qcamera {
using android::hidl::base::V1_0::IBase;
using android::hardware::hidl_death_recipient;
static std::mutex gPowerHalMutex;
static sp<IPower> gPowerHal = nullptr;
static void getPowerHalLocked();
// struct PowerHalDeathRecipient;
struct PowerHalDeathRecipient : virtual public hidl_death_recipient {
// hidl_death_recipient interface
virtual void serviceDied(uint64_t, const wp<IBase>&) override {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
ALOGE("PowerHAL just died");
gPowerHal = nullptr;
getPowerHalLocked();
}
};
sp<PowerHalDeathRecipient> gPowerHalDeathRecipient = nullptr;
// The caller must be holding gPowerHalMutex.
static void getPowerHalLocked() {
if (gPowerHal != nullptr) {
return;
}
gPowerHal = IPower::getService();
if (gPowerHal == nullptr) {
ALOGE("Unable to get Power service.");
} else {
if (gPowerHalDeathRecipient == nullptr) {
gPowerHalDeathRecipient = new PowerHalDeathRecipient();
}
hardware::Return<bool> linked = gPowerHal->linkToDeath(
gPowerHalDeathRecipient, 0x451F /* cookie */);
if (!linked.isOk()) {
ALOGE("Transaction error in linking to PowerHAL death: %s",
linked.description().c_str());
gPowerHal = nullptr;
} else if (!linked) {
ALOGW("Unable to link to PowerHal death notifications");
gPowerHal = nullptr;
} else {
ALOGD("Link to death notification successful");
}
}
}
typedef enum {
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0 = 0x40800000,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_1 = 0x40800010,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_2 = 0x40800020,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_3 = 0x40800030,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0 = 0x40800100,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_1 = 0x40800110,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_2 = 0x40800120,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_3 = 0x40800130,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0 = 0x40804000,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_1 = 0x40804010,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_2 = 0x40804020,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_3 = 0x40804030,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0 = 0x40804100,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_1 = 0x40804110,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_2 = 0x40804120,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_3 = 0x40804130,
MPCTLV3_MIN_ONLINE_CPU_CLUSTER_BIG = 0x41000000,
MPCTLV3_MIN_ONLINE_CPU_CLUSTER_LITTLE = 0x41000100,
MPCTLV3_MAX_ONLINE_CPU_CLUSTER_BIG = 0x41004000,
MPCTLV3_MAX_ONLINE_CPU_CLUSTER_LITTLE = 0x41004100,
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS = 0x40400000,
MPCTLV3_CPUBW_HWMON_MIN_FREQ = 0x41800000,
MPCTLV3_CPUBW_HWMON_HYST_OPT = 0x4180C000
} perf_lock_params;
static int32_t perfLockParamsOpenCamera[] = {
// Disable power collapse and set CPU cloks to turbo
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF
};
static int32_t perfLockParamsCloseCamera[] = {
// Disable power collapse and set CPU cloks to turbo
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF
};
static int32_t perfLockParamsStartPreview[] = {
// Disable power collapse and set CPU cloks to turbo
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF
};
static int32_t perfLockParamsTakeSnapshot[] = {
// Disable power collapse and set CPU cloks to turbo
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_CPUBW_HWMON_HYST_OPT, 0x0,
MPCTLV3_CPUBW_HWMON_MIN_FREQ, 0x8C
};
PerfLockInfo QCameraPerfLock::mPerfLockInfo[] = {
{ //PERF_LOCK_OPEN_CAMERA
perfLockParamsOpenCamera,
sizeof(perfLockParamsOpenCamera)/sizeof(int32_t) },
{ //PERF_LOCK_CLOSE_CAMERA
perfLockParamsCloseCamera,
sizeof(perfLockParamsCloseCamera)/sizeof(int32_t) },
{ //PERF_LOCK_START_PREVIEW
perfLockParamsStartPreview,
sizeof(perfLockParamsStartPreview)/sizeof(int32_t) },
{ //PERF_LOCK_TAKE_SNAPSHOT
perfLockParamsTakeSnapshot,
sizeof(perfLockParamsTakeSnapshot)/sizeof(int32_t) },
{ //PERF_LOCK_POWERHINT_PREVIEW
NULL, 0},
{ //PERF_LOCK_POWERHINT_ENCODE
NULL, 0}
};
Mutex QCameraPerfLockIntf::mMutex;
QCameraPerfLockIntf* QCameraPerfLockIntf::mInstance = NULL;
/*===========================================================================
* FUNCTION : QCameraPerfLockMgr constructor
*
* DESCRIPTION: Initialize the perf locks
*
* PARAMETERS : None
*
* RETURN : void
*
*==========================================================================*/
QCameraPerfLockMgr::QCameraPerfLockMgr() :
mState(LOCK_MGR_STATE_UNINITIALIZED)
{
for (int i = 0; i < PERF_LOCK_COUNT; ++i) {
mPerfLock[i] = QCameraPerfLock::create((PerfLockEnum)i);
if (mPerfLock[i] == NULL) {
mState = LOCK_MGR_STATE_ERROR;
LOGE("Could not allocate perf locks");
// Set the remaining perf locks to NULL
for (int j = i+1; j < PERF_LOCK_COUNT; ++j) {
mPerfLock[j] = NULL;
}
return;
}
}
mState = LOCK_MGR_STATE_READY;
}
/*===========================================================================
* FUNCTION : QCameraPerfLockMgr destructor
*
* DESCRIPTION: class destructor
*
* PARAMETERS : None
*
* RETURN : void
*
*==========================================================================*/
QCameraPerfLockMgr::~QCameraPerfLockMgr()
{
for (int i = 0; i < PERF_LOCK_COUNT; ++i) {
if (mPerfLock[i]) {
delete mPerfLock[i];
}
}
}
/*===========================================================================
* FUNCTION : acquirePerfLock
*
* DESCRIPTION: Call acquirePerfLock function for the requested perf lock
*
* PARAMETERS :
* @perfLockType: Perf lock enum
* @timer: Timer value in ms
*
* RETURN : true on success
* false on failure
*==========================================================================*/
bool QCameraPerfLockMgr::acquirePerfLock(
PerfLockEnum perfLockType,
uint32_t timer)
{
bool ret = false;
if ((mState == LOCK_MGR_STATE_READY) &&
isValidPerfLockEnum(perfLockType)) {
ret = mPerfLock[perfLockType]->acquirePerfLock(true, timer);
}
return ret;
}
/*===========================================================================
* FUNCTION : acquirePerfLockIfExpired
*
* DESCRIPTION: Call acquirePerfLock function for the requested perf lock
*
* PARAMETERS :
* @perfLockType: Type of perf lock
* @timer: Timer value in ms
*
* RETURN : true on success
* false on failure
*==========================================================================*/
bool QCameraPerfLockMgr::acquirePerfLockIfExpired(
PerfLockEnum perfLockType,
uint32_t timer)
{
bool ret = false;
if ((mState == LOCK_MGR_STATE_READY) &&
isValidPerfLockEnum(perfLockType)) {
ret = mPerfLock[perfLockType]->acquirePerfLock(false, timer);
}
return ret;
}
/*===========================================================================
* FUNCTION : releasePerfLock
*
* DESCRIPTION: Call releasePerfLock function for the requested perf lock
*
* PARAMETERS :
* @perfLockType: Enum of perf lock
*
* RETURN : true on success
* false on failure
*==========================================================================*/
bool QCameraPerfLockMgr::releasePerfLock(
PerfLockEnum perfLockType)
{
bool ret = false;
if ((mState == LOCK_MGR_STATE_READY) &&
isValidPerfLockEnum(perfLockType)) {
ret = mPerfLock[perfLockType]->releasePerfLock();
}
return ret;
}
/*===========================================================================
* FUNCTION : powerHintInternal
*
* DESCRIPTION: Calls the appropriate perf lock's powerHintInternal function
*
* PARAMETERS :
* @perfLockType: Type of perf lock
* @hint : Power hint
* @enable : Enable power hint if set to 1. Disable if set to 0.
*
* RETURN : void
*
*==========================================================================*/
void QCameraPerfLockMgr::powerHintInternal(
PerfLockEnum perfLockType,
PowerHint powerHint,
int32_t time_out)
{
if ((mState == LOCK_MGR_STATE_READY) &&
isValidPerfLockEnum(perfLockType)) {
mPerfLock[perfLockType]->powerHintInternal(powerHint, time_out);
}
}
/*===========================================================================
* FUNCTION : create
*
* DESCRIPTION: This is a static method to create perf lock object. It calls
* protected constructor of the class and only returns a valid object
* if it can successfully initialize the perf lock.
*
* PARAMETERS : None
*
* RETURN : QCameraPerfLock object pointer on success
* NULL on failure
*
*==========================================================================*/
QCameraPerfLock* QCameraPerfLock::create(
PerfLockEnum perfLockType)
{
QCameraPerfLock *perfLock = NULL;
if (perfLockType < PERF_LOCK_COUNT) {
QCameraPerfLockIntf *perfLockIntf = QCameraPerfLockIntf::createSingleton();
if (perfLockIntf) {
perfLock = new QCameraPerfLock(perfLockType, perfLockIntf);
}
}
return perfLock;
}
/*===========================================================================
* FUNCTION : QCameraPerfLock constructor
*
* DESCRIPTION: Initialize member variables
*
* PARAMETERS : None
*
* RETURN : void
*
*==========================================================================*/
QCameraPerfLock::QCameraPerfLock(
PerfLockEnum perfLockType,
QCameraPerfLockIntf *perfLockIntf) :
mHandle(0),
mRefCount(0),
mTimeOut(0),
mPerfLockType(perfLockType),
mPerfLockIntf(perfLockIntf)
{
mIsPerfdEnabled = android::base::GetBoolProperty("persist.camera.perfd.enable", false);
}
/*===========================================================================
* FUNCTION : QCameraPerfLock destructor
*
* DESCRIPTION: class destructor
*
* PARAMETERS : None
*
* RETURN : void
*
*==========================================================================*/
QCameraPerfLock::~QCameraPerfLock()
{
if (mHandle > 0) {
(*mPerfLockIntf->perfLockRel())(mHandle);
}
QCameraPerfLockIntf::deleteInstance();
}
/*===========================================================================
* FUNCTION : isTimedOut
*
* DESCRIPTION: Check if the perf lock is timed out
*
* PARAMETERS : None
*
* RETURN : boolean indicating if the perf lock is timed out
*
*==========================================================================*/
bool QCameraPerfLock::isTimedOut()
{
if (mTimeOut && (systemTime() > mTimeOut)) {
return true;
}
return false;
}
/*===========================================================================
* FUNCTION : restartTimer
*
* DESCRIPTION: Restart the timer for the duration specified
*
* PARAMETERS :
* @timer : timer duration in milliseconds
*
* RETURN : void
*
*==========================================================================*/
void inline QCameraPerfLock::restartTimer(
uint32_t timer)
{
if (timer > 0) {
mTimeOut = systemTime() + ms2ns(timer);
}
}
/*===========================================================================
* FUNCTION : acquirePerfLock
*
* DESCRIPTION: Acquires the perf lock for the duration specified. Do not acquire
* the perf lock is reacquire flag is set to false provided the perf
* lock is already acquired.
*
* PARAMETERS :
* @forceReaquirePerfLock: Reacquire
* @timer : Duration of the perf lock
*
* RETURN : true on success
* false on failure
*
*==========================================================================*/
bool QCameraPerfLock::acquirePerfLock(
bool forceReaquirePerfLock,
uint32_t timer)
{
bool ret = true;
Mutex::Autolock lock(mMutex);
switch (mPerfLockType) {
case PERF_LOCK_POWERHINT_PREVIEW:
case PERF_LOCK_POWERHINT_ENCODE:
powerHintInternal(PowerHint::VIDEO_ENCODE, true);
return true;
case PERF_LOCK_OPEN_CAMERA:
case PERF_LOCK_CLOSE_CAMERA:
powerHintInternal(PowerHint::CAMERA_LAUNCH, timer);
return true;
case PERF_LOCK_START_PREVIEW:
powerHintInternal(PowerHint::CAMERA_STREAMING, timer);
return true;
case PERF_LOCK_TAKE_SNAPSHOT:
powerHintInternal(PowerHint::CAMERA_SHOT, timer);
return true;
default:
LOGE("Unknown powerhint %d",(int)mPerfLockType);
return false;
}
if (!mIsPerfdEnabled) return ret;
if (isTimedOut()) {
mHandle = 0;
mRefCount = 0;
}
if ((mRefCount == 0) || forceReaquirePerfLock) {
mHandle = (*mPerfLockIntf->perfLockAcq())(
mHandle, timer,
mPerfLockInfo[mPerfLockType].perfLockParams,
mPerfLockInfo[mPerfLockType].perfLockParamsCount);
if (mHandle > 0) {
++mRefCount;
restartTimer(timer);
LOGD("perfLockHandle %d, updated refCount: %d, perfLockType: %d",
mHandle, mRefCount, mPerfLockType);
} else {
LOGE("Failed to acquire the perf lock");
ret = false;
}
} else {
LOGD("Perf lock already acquired, not re-aquiring");
}
return ret;
}
/*===========================================================================
* FUNCTION : releasePerfLock
*
* DESCRIPTION: Releases the perf lock
*
* PARAMETERS : None
*
* RETURN : true on success
* false on failure
*
*==========================================================================*/
bool QCameraPerfLock::releasePerfLock()
{
bool ret = true;
Mutex::Autolock lock(mMutex);
switch (mPerfLockType) {
case PERF_LOCK_POWERHINT_PREVIEW:
case PERF_LOCK_POWERHINT_ENCODE:
powerHintInternal(PowerHint::VIDEO_ENCODE, false);
return true;
case PERF_LOCK_OPEN_CAMERA:
case PERF_LOCK_CLOSE_CAMERA:
powerHintInternal(PowerHint::CAMERA_LAUNCH, false);
return true;
case PERF_LOCK_START_PREVIEW:
powerHintInternal(PowerHint::CAMERA_STREAMING, false);
return true;
case PERF_LOCK_TAKE_SNAPSHOT:
powerHintInternal(PowerHint::CAMERA_SHOT, false);
return true;
default:
LOGE("Unknown powerhint %d",(int)mPerfLockType);
return false;
}
if (!mIsPerfdEnabled) return ret;
if (mHandle > 0) {
LOGD("perfLockHandle %d, refCount: %d, perfLockType: %d",
mHandle, mRefCount, mPerfLockType);
if (isTimedOut()) {
mHandle = 0;
mRefCount = 0;
} else if (--mRefCount == 0) {
int32_t rc = (*mPerfLockIntf->perfLockRel())(mHandle);
mHandle = 0;
mTimeOut = 0;
if (rc < 0) {
LOGE("Failed to release the perf lock");
ret = false;
}
}
} else {
LOGW("Perf lock %d either not acquired or already released", mPerfLockType);
}
return ret;
}
/*===========================================================================
* FUNCTION : powerHintInternal
*
* DESCRIPTION: Sets the requested power hint and state to power HAL.
*
* PARAMETERS :
* @hint : Power hint
* @enable : Enable power hint if set to 1. Disable if set to 0.
*
* RETURN : void
*
*==========================================================================*/
void QCameraPerfLock::powerHintInternal(
PowerHint powerHint,
int32_t time_out)
{
#ifdef HAS_MULTIMEDIA_HINTS
if (!mPerfLockIntf->powerHint(powerHint, time_out)) {
LOGE("Send powerhint to PowerHal failed");
}
#endif
}
/*===========================================================================
* FUNCTION : createSingleton
*
* DESCRIPTION: Open the perf lock library, query the function pointers and
* create a singleton object upon success
*
* PARAMETERS : None
*
* RETURN : QCameraPerfLockIntf object pointer on success
* NULL on failure
*
*==========================================================================*/
QCameraPerfLockIntf* QCameraPerfLockIntf::createSingleton()
{
bool error = true;
Mutex::Autolock lock(mMutex);
if (mInstance == NULL) {
// Open perflock library and query for the function pointers
uint32_t perfLockEnable = 0;
char value[PROPERTY_VALUE_MAX];
property_get("persist.camera.perflock.enable", value, "1");
perfLockEnable = atoi(value);
if (perfLockEnable) {
mInstance = new QCameraPerfLockIntf();
if (mInstance) {
#ifdef HAS_MULTIMEDIA_HINTS
std::lock_guard<std::mutex> lock(gPowerHalMutex);
getPowerHalLocked();
if (gPowerHal == nullptr) {
ALOGE("Couldn't load PowerHAL module");
}
else
#endif
{
/* Retrieve the name of the vendor extension library */
void *dlHandle = NULL;
if ((property_get("ro.vendor.extension_library", value, NULL) > 0) &&
(dlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL))) {
perfLockAcquire pLockAcq = (perfLockAcquire)dlsym(dlHandle, "perf_lock_acq");
perfLockRelease pLockRel = (perfLockRelease)dlsym(dlHandle, "perf_lock_rel");
if (pLockAcq && pLockRel) {
mInstance->mDlHandle = dlHandle;
mInstance->mPerfLockAcq = pLockAcq;
mInstance->mPerfLockRel = pLockRel;
error = false;
} else {
LOGE("Failed to link the symbols- perf_lock_acq, perf_lock_rel");
bool IsPerfdEnabled = android::base::GetBoolProperty("persist.camera.perfd.enable", false);
if (!IsPerfdEnabled) {
mInstance->mDlHandle = nullptr;
mInstance->mPerfLockAcq = nullptr;
mInstance->mPerfLockRel = nullptr;
error = false;
}
}
} else {
LOGE("Unable to load lib: %s", value);
}
}
if (error && mInstance) {
delete mInstance;
mInstance = NULL;
}
}
}
}
if (mInstance) {
++(mInstance->mRefCount);
}
return mInstance;
}
/*===========================================================================
* FUNCTION : deleteInstance
*
* DESCRIPTION: Delete the object if refCount is 0
*
* PARAMETERS : None
*
* RETURN : void
*
*==========================================================================*/
void QCameraPerfLockIntf::deleteInstance()
{
Mutex::Autolock lock(mMutex);
if (mInstance && (--(mInstance->mRefCount) == 0)) {
delete mInstance;
mInstance = NULL;
}
}
/*===========================================================================
* FUNCTION : QCameraPerfLockIntf destructor
*
* DESCRIPTION: class destructor
*
* PARAMETERS : None
*
* RETURN : void
*
*==========================================================================*/
QCameraPerfLockIntf::~QCameraPerfLockIntf()
{
if (mDlHandle) {
dlclose(mDlHandle);
}
}
bool QCameraPerfLockIntf::powerHint(PowerHint hint, int32_t data) {
std::lock_guard<std::mutex> lock(gPowerHalMutex);
getPowerHalLocked();
if (gPowerHal == nullptr) {
ALOGE("Couldn't do powerHint because of HAL error.");
return false;
}
auto ret = gPowerHal->powerHintAsync_1_2(hint, data);
if (!ret.isOk()) {
ALOGE("powerHint failed error: %s", ret.description().c_str());
}
return ret.isOk();
}
}; // namespace qcamera