拍照时闪光灯调用HAL层到driver层流程

本文详细介绍了Android手机拍照时闪光灯从HAL层到Driver层的调用流程,涉及Hal3AIf、Hal3AFlowCtrl、Thread3AImp等组件的实例化与初始化,以及StrobeDrvFlashlight的setOnOff方法,最终在KERNEL层通过led191系列函数控制闪光灯的开关。

平台 MT6739
版本 Android 9.0

HAL层

HAL层闪光灯调用具体函数执行流程

Hal3AIf::getInstance的实现

打开相机APK时调用的初始化函数

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/aaa_hal_if.cpp

Hal3AIf::getInstance(MINT32 const i4SensorOpenIndex, E_FlowControl_Type eType, MINT32 i4SubsampleCount)
{
   
   
    CAM_LOGD("[%s] sensoridx(%d)", __FUNCTION__, i4SensorOpenIndex);
    switch (eType)
    {
   
   
    case Hal3AIf::E_FlowControl_Type_SMVR:
        return Hal3AFlowCtrl_SMVR::getInstance(i4SensorOpenIndex, i4SubsampleCount);
    case Hal3AIf::E_FlowControl_Type_NORMAL:
        return Hal3AFlowCtrl::getInstance(i4SensorOpenIndex);
    default:
        return NULL;
    }
}

Hal3AFlowCtrl::getInstance的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

Hal3AIf*
Hal3AFlowCtrl::
getInstance(MINT32 i4SensorOpenIndex)
{
   
   
    IHalSensorList* const pHalSensorList = MAKE_HalSensorList();
    if (!pHalSensorList) return NULL;

    MINT32 i4SensorDev = pHalSensorList->querySensorDevIdx(i4SensorOpenIndex);

    switch (i4SensorDev)
    {
   
   
        case SENSOR_DEV_MAIN:
        {
   
   
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_SUB:
        {
   
   
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_SUB);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_MAIN_2:
        {
   
   
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN_2);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_SUB_2:
        {
   
   
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_SUB_2);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
        case SENSOR_DEV_MAIN_3:
        {
   
   
            static Hal3AFlowCtrl _singleton(SENSOR_DEV_MAIN_3);
            _singleton.init(i4SensorOpenIndex);
            return &_singleton;
        }
    default:
        CAM_LOGE("Unsupport sensor device ID: %d\n", i4SensorDev);
        AEE_ASSERT_3A_HAL("Unsupport sensor device.");
        return MNULL;
    }
}

Hal3AFlowCtrl::init的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Hal3AFlowCtrl.cpp

MRESULT
Hal3AFlowCtrl::
init(MINT32 i4SensorOpenIndex) //can be called only once by RAW or YUV, no user count
{
   
   
    MY_LOGD("[%s] +", __FUNCTION__);

    m_fgLogEn = ::property_get_int32("vendor.debug.camera.log", 0);
    if ( m_fgLogEn == 0 ) {
   
   
        m_fgLogEn = ::property_get_int32("vendor.debug.camera.log.hal3a", 0);
    }
    m_u4FrmIdFreeze = ::property_get_int32("vendor.debug.3a.freeze", 0);
    m_bRRZDump = 0;
    m_fgDebugLogWEn = DebugUtil::getDebugLevel(DBG_3A);

    IHalSensorList*const pHalSensorList = MAKE_HalSensorList();
    if (!pHalSensorList) return 0;

#if (CAM3_3ATESTLVL <= CAM3_3AUT)
    I3AWrapper::E_TYPE_T eType = I3AWrapper::E_TYPE_DFT;
#else
    MINT32 eSensorType = pHalSensorList->queryType(i4SensorOpenIndex);
    I3AWrapper::E_TYPE_T eType = I3AWrapper::E_TYPE_RAW;
    switch (eSensorType)
    {
   
   
    case NSSensorType::eRAW:
        eType = I3AWrapper::E_TYPE_RAW;
        break;
    case NSSensorType::eYUV:
        eType = I3AWrapper::E_TYPE_YUV;
        break;
    default:
        eType = I3AWrapper::E_TYPE_DFT;
        break;
    }
#endif

    m_i4SensorOpenIdx = i4SensorOpenIndex;

    // create 3A wrapper
    if (m_p3AWrap == NULL)
    {
   
   
        m_p3AWrap = I3AWrapper::getInstance(eType, i4SensorOpenIndex);
        if (m_p3AWrap)
        {
   
   
            MY_LOGD_IF(m_fgLogEn, "[%s] m_p3AWrapper(%p) created OK", __FUNCTION__, m_p3AWrap);
        }
        else
        {
   
   
            CAM_LOGE("m_p3AWrapper created fail!");
            AEE_ASSERT_3A_HAL("m_p3AWrapper created fail!");
        }
    }

    // create Vsync event
    //IEventIrq::ConfigParam IrqConfig(i4SensorDev, i4SensorOpenIndex, 5000, IEventIrq::E_Event_Vsync);
    //m_pEventIrq = IEventIrq::createInstance(IrqConfig, "VSIrq");

    m_SttBufQEnable = property_get_int32("vendor.debug.camera.SttBufQ.enable", 0);
    if (m_SttBufQEnable) {
   
   
        ISttBufQ::createSingleton(m_i4SensorDev, LOG_TAG);
    }

    // create statistic control
#if (CAM3_3ATESTLVL >= CAM3_3ASTTUT)
    if (m_p3ASttCtrl == NULL  && eType == I3AWrapper::E_TYPE_RAW)
    {
   
   
        m_p3ASttCtrl = Hal3ASttCtrl::createInstance(m_i4SensorDev, i4SensorOpenIndex);
        if (m_p3ASttCtrl)
        {
   
   
            MY_LOGD_IF(m_fgLogEn, "[%s] m_p3ASttCtrl(%p) created OK", __FUNCTION__, m_p3ASttCtrl);
        }
        else
        {
   
   
            CAM_LOGE("m_p3ASttCtrl created fail!");
            AEE_ASSERT_3A_HAL("m_p3ASttCtrl created fail!");
        }
    }
#endif

    // create AA thread
    if (m_pThread == NULL)
    {
   
   
    	/* 闪光灯的相关操作在这个线程中实现 */
        m_pThread = IThread3A::createInstance(this);
        if (m_pThread)
        {
   
   
            MY_LOGD_IF(m_fgLogEn, "[%s] m_pThread(%p) created OK", __FUNCTION__, m_pThread);
        }
        else
        {
   
   
            CAM_LOGE("m_pThread created fail!");
            AEE_ASSERT_3A_HAL("m_pThread created fail!");
        }
    }

    // ResultPool - Get result pool object
    if(m_pResultPoolObj == NULL)
        m_pResultPoolObj = IResultPool::getInstance(m_i4SensorDev);
    if(m_pResultPoolObj == NULL)
        CAM_LOGE("ResultPool getInstance fail");

    MY_LOGD("[%s] - eType(%d), sensor(%d), sensorIdx(%d)", __FUNCTION__, eType, m_i4SensorDev, i4SensorOpenIndex);
    return S_3A_OK;
}

IThread3A::createInstance的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

IThread3A*
IThread3A::createInstance(Hal3AIf* pHal3A)
{
   
   
    return Thread3AImp::createInstance(pHal3A);
}

Thread3AImp::createInstance的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

IThread3A*
Thread3AImp::
createInstance(Hal3AIf* pHal3A)
{
   
   
    //static Thread3AImp singleton(pHal3A);
    //singleton.createThread();   // user count protected
    //return &singleton;
    Thread3AImp* pThd3A = new Thread3AImp(pHal3A);
    //if (pThd3A)
        //pThd3A->createThread();
    return pThd3A;
}

Thread3AImp::Thread3AImp的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

Thread3AImp::
Thread3AImp(Hal3AIf* pHal3A)
    : mpHal3A(pHal3A)
    , mu4LogEn(MFALSE)
    , mbListenUpdate(MFALSE)
    , mbSetFromP1(MFALSE)
    , mLock()
{
   
   
    MY_LOGD("[%s] Enter (%d)", __FUNCTION__, pHal3A->getSensorDev());
    createThread();
}

Thread3AImp::createThread的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

MVOID
Thread3AImp::createThread()
{
   
   
    //Mutex::Autolock lock(mLock);  // Nelson : mutual exclusive by atomic_flag

    GET_PROP("vendor.debug.3a.log", 0, mu4LogEn);
    mu4DebugLogWEn = DebugUtil::getDebugLevel(DBG_3A);

    if (!thread_alive.test_and_set())
    {
   
   
        MY_LOGD("[%s] +", __FUNCTION__);
        sem_init(&mSem, 0, 0);
        //pthread_create(&mThread, NULL, onThreadLoop, this);
        create3Athread = thread(onThreadLoop, this);
        MY_LOGD("[%s] -", __FUNCTION__);
    }
}

在打开相机APK后,会通过 Thread3AImp::createThread() 函数创建并执行了线程 create3Athread ,它最终会调用 Thread3AImp::onThreadLoop() 方法

Thread3AImp::onThreadLoop的实现

./vendor/mediatek/proprietary/hardware/mtkcam/aaa/source/common/hal3a/v1.0/Thread3AImp.cpp

MVOID*
Thread3AImp::onThreadLoop(MVOID *arg)
{
   
   
    MY_LOGD("+");

    CmdQ_T rCmd(ECmd_Update, ParamIspProfile_T());
    Thread3AImp *_this = reinterpret_cast<Thread3AImp*>(arg);
//    AaaTimer ccTimer;
    MBOOL bGetCmd;
    MBOOL fgLogEn = (_this->mu4LogEn & EN_LOG_3A_THREAD) ? MTRUE : MFALSE;
    MUINT32 cmdQSize = 0;

    // (1) change thread setting
    _this->changeThreadSetting();

    // (2) thread-in-loop
    while (_this->getCommand(rCmd, bGetCmd, MFALSE)) /* 从 getCommand() 中获取rCmd的值 */
    {
   
   
        //MY_LOGD_IF(1, "rCmd(%d)+", rCmd);
        //
        DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 0);
        switch (rCmd.eCmd)
        {
   
   
            case ECmd_Update:
                if (!_this->mbListenUpdate)
                {
   
   
                    MY_LOGD("[%s] Exit 3A thread", __FUNCTION__);
                    break;
                }
                MY_LOGD_IF(fgLogEn, "rCmd(%d)+", rCmd.eCmd);
                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 1);

                /* 在这函数里不断通过 post_commnad 发送 ECmd_Update 命令 */
                if (!_this->mpHal3A->doUpdateCmd(&rCmd.rParamIspProfile))//on3aprocfinish
                {
   
   
                    char strErr[512] = {
   
   '\0'};
                    sprintf(strErr, "ECmd_Update failed #(%d)", rCmd.rParamIspProfile.i4MagicNum);
                    CAM_LOGE("%s", strErr);
                    AEE_ASSERT_3A_HAL(strErr);
                }

                if (!_this->mbSetFromP1) //only check before first set from MW
                {
   
   
                    if (rCmd.rParamIspProfile.iValidateOpt != ParamIspProfile_T::EParamValidate_None)
                    {
   
   
                        MY_LOGD("[%s] First command from P1",__FUNCTION__);
                        _this->mbSetFromP1 = MTRUE;
                    }
                }
                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 2);

                _this->mpHal3A->on3AProcSet(_this->mbSetFromP1);//vsync callback

                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 3);
                {
   
   
                    Mutex::Autolock autoLock(_this->mModuleMtx);
                    cmdQSize = _this->mCmdQ.size();
                }
                if (cmdQSize)
                {
   
   
                    MY_LOGD_IF(fgLogEn, "[%s] Cmd from P1", __FUNCTION__);
                }
                else
                {
   
   
                    if (_this->mbSetFromP1)
                    {
   
   
                        _this->mpHal3A->doUpdateCmdDummy();
                        MY_LOGD_IF(fgLogEn, "[%s] Dummy cmd from 3A Thread", __FUNCTION__);
                    }
                }

                MY_LOGD_IF(fgLogEn, "rCmd(%d), magic#(%d)-", rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
            break;

            default:
                AAA_TRACE_HAL(Thread3A_CmdDefault);
                MY_LOGD_IF(fgLogEn, "rCmd(%d)+", rCmd.eCmd);
                //
                DebugUtil::getInstance(_this->mpHal3A->getSensorDev())->update(LOG_TAG, "onThreadLoop", 4);
                if ( ! _this->mpHal3A->postCommand(rCmd.eCmd, &rCmd.rParamIspProfile))
                {
   
   
                    CAM_LOGE("Cmd(%d) failed", rCmd.eCmd);
                    AEE_ASSERT_3A_HAL("onThreadLoop postCommand fail(2).");
                }
                //
                if (rCmd.eCmd != ECmd_PrecaptureStart && rCmd.eCmd != ECmd_PrecaptureEnd)
                {
   
   
                    ::sem_post(&_this->mSem);
                }
                MY_LOGD_IF(fgLogEn, "rCmd(%d), magic#(%d)-", rCmd.eCmd, rCmd.rParamIspProfile.i4MagicNum);
                AAA_TRACE_END_HAL;
    
<think>我们正在处理一个关于MTK平台双光灯日志分析的问题,特别是如何确定闪光灯被触发的总次数。根据用户的问题,我们需要关注如何从日志中提取闪光灯触发事件并计数。 在MTK平台中,闪光灯的使用通常会在内核日志(dmesg)和系统日志(logcat)中留下痕迹。我们可以通过以下步骤来分析: 1. **确定日志来源**: - **内核日志 (dmesg)**:闪光灯驱动通常会在这里打印控制信息,比如打开/关闭操作。 - **系统日志 (logcat)**:HAL和框架(如CameraService)也会记录闪光灯状态变化。 2. **关键日志标识**: - 在驱动,我们可以搜索与闪光灯设备相关的关键字,例如`flashlight`、`leds`、`torch`等。 - 在HAL和框架,可以搜索`Flashlight`、`setTorch`、`turnOnFlash`等。 3. **具体分析步骤**: **步骤1:获取日志** - 使用`adb logcat -b all > logcat.txt`获取所有系统日志。 - 使用`adb shell dmesg > dmesg.txt`获取内核日志。 **步骤2:过滤闪光灯相关日志** - 在logcat中搜索关键字: ```bash grep -iE "flashlight|torch|flash" logcat.txt ``` - 在dmesg中搜索关键字: ```bash grep -iE "flashlight|leds" dmesg.txt ``` **步骤3:识别触发事件** - 在驱动,每次闪光灯打开操作通常会有日志,例如: ``` [mtk_flash_set] set brightness: 255 ``` - 在框架,每次调用`setTorchMode`会有记录,例如: ``` CameraService: setTorchMode: cameraId=0, enabled=1 ``` **步骤4:计数触发次数** - 统计打开操作的日志行数。例如,在过滤后的日志中,统计包含`brightness: 255`(或具体亮度值)或`enabled=1`的行数。 **步骤5:考虑去重** - 注意:一次闪光灯使用可能产生多条日志(如驱动和框架都有记录),需要根据间戳和调用链判断是否为同一次触发。 4. **自动化脚本示例**: 我们可以编写一个简单的shell脚本来统计触发次数: ```bash #!/bin/bash # 统计内核日志中闪光灯打开次数(根据实际日志调整关键字) dmesg_count=$(grep "set brightness: 255" dmesg.txt | wc -l) # 统计logcat中CameraService打开闪光灯次数 logcat_count=$(grep "setTorchMode.*enabled=1" logcat.txt | wc -l) # 由于日志可能重复,取最大值或根据实际情况选择 total_count=$((dmesg_count > logcat_count ? dmesg_count : logcat_count)) echo "Estimated total flash trigger count: $total_count" ``` 5. **注意事项**: - **日志覆盖**:如果系统运行间长,旧日志可能被覆盖,因此最好在每次测试后立即抓取日志。 - **多闪光灯支持**:对于双光灯(如主闪光灯和辅助闪光灯),需要分别统计,关键字可能不同(例如`flashlight_main`和`flashlight_sub`)。 - **调试符号**:如果驱动日志没有明显信息,可能需要开启调试选项(重新编译内核或模块)。 6. **开启详细日志**: 如果默认日志信息不足,可以尝试在驱动中增加调试打印: ```c // 在驱动文件(如leds-mtk-flash.c)中添加 #define DEBUG printk(KERN_DEBUG "Flash triggered: %d\n", brightness); ``` 然后重新编译并刷入内核。 7. **使用MTK专属工具**: MTK提供`logcat`的增强版本`alog`,可以捕获更多底日志。使用`adb shell alog`获取。 8. **参考日志示例**: - **驱动日志**: ``` <6>[ 123.456789] leds-mtk-flash: set flashlight brightness to 255 ``` - **框架日志**: ``` 10-25 15:30:00.123 1234 5678 I CameraService: setTorchMode: cameraId=0, enabled=1 ``` 通过以上步骤,我们可以从日志中分析出闪光灯触发的总次数。 **生成相关问题**: §§相关问题§§ 1. 如何增加MTK闪光灯驱动的调试日志? 2. MTK双光灯(主/辅)的日志关键字有什么区别? 3. 如何通过ADB命令实监控闪光灯触发事件?</think>### MTK平台双光灯触发次数日志分析方法 要分析MTK双光灯日志中闪光灯触发总次数,需结合内核驱动日志、HAL日志和系统事件日志,以下是详细步骤: --- #### 1. **关键日志来源** | 日志级 | 日志路径/命令 | 关键标识符 | |-----------------|----------------------------------|-------------------------------------| | **内核驱动** | `dmesg \| grep "flash\|leds"` | `mtk_flash_set`, `brightness change` | | **HAL** | `logcat \| grep "HalFlash"` | `setTorchMode`, `turnOnFlash` | | **框架** | `logcat \| grep "CameraService"` | `FLASH_MODE_`, `FLASH_FIRED` | | **硬件事件** | `/sys/kernel/debug/flashlight/` | `trigger_count` (部分驱动支持) | --- #### 2. **触发次数分析流程** **步骤1:收集完整日志** ```bash adb logcat -b all -v time > full_logcat.txt # 获取所有系统日志 adb shell dmesg > dmesg.log # 获取内核日志 ``` **步骤2:过滤闪光灯事件** ```bash # 搜索关键事件(联合过滤) grep -iE "flash|torch|leds|HalFlash|CameraService" full_logcat.txt > flash_events.log grep -iE "mtk_flash_set|brightness" dmesg.log > driver_events.log ``` **步骤3:识别触发标志** - **驱动触发证据**: ```log <6>[timestamp] leds-mtk-flash: set brightness=255 # 触发闪光 <6>[timestamp] leds-mtk-flash: set brightness=0 # 关闭闪光 ``` 每对`255→0`的切换计为**1次触发**。 - **HAL调用证据**: ```log I HalFlash: setTorchMode(camId=0, enable=1) # 触发命令 ``` - **框架事件证据**: ```log D CameraService: FLASH_FIRED event for camera 0 ``` **步骤4:统计触发次数** ```bash # 统计驱动触发次数(基于亮度切换) grep "brightness=255" driver_events.log | wc -l # 统计HAL调用次数 grep "setTorchMode.*enable=1" flash_events.log | wc -l # 统计框架FLASH_FIRED事件 grep "FLASH_FIRED" flash_events.log | wc -l ``` **步骤5:交叉验证** 比较三日志的统计结果: - 若三数据一致 → 结果可靠 - 若驱动 < HAL → 存在未执行的调用(需检查错误日志) - 若驱动 > HAL → 可能存在硬件误触发(检查GPIO干扰) --- #### 3. **高级调试方法** **1. 启用详细调试日志** 在驱动文件(如`leds-mtk-flash.c`)添加: ```c printk(KERN_DEBUG "FLASH_TRIGGER_COUNT: %d\n", trigger_counter++); ``` 重新编译驱动后,日志将直接输出计数。 **2. 实监控触发** ```bash watch -n 0.5 "cat /sys/kernel/debug/flashlight/stats" ``` 输出示例: ``` Total triggers: 27 Last trigger: 2023-10-25 14:30:45 ``` **3. 解析sysfs节点** 若驱动暴露统计节点: ```bash adb shell "echo 1 > /sys/class/leds/flashlight/trigger_count_reset" # 重置计数 adb shell cat /sys/class/leds/flashlight/trigger_count # 读取当前值 ``` --- #### 4. **典型日志案例分析** **场景:相机连拍3张照片** ```log # 框架 10-25 14:30:00.123 D CameraService: FLASH_MODE_TORCH start 10-25 14:30:01.456 D CameraService: FLASH_FIRED (1) 10-25 14:30:02.789 D CameraService: FLASH_FIRED (2) 10-25 14:30:03.012 D CameraService: FLASH_FIRED (3) # HAL 10-25 14:30:00.125 I HalFlash: setTorchMode(camId=0, enable=1) # 驱动 <6>[14:30:01.457] leds-mtk-flash: set brightness=255 # 触发1 <6>[14:30:01.460] leds-mtk-flash: set brightness=0 <6>[14:30:02.790] leds-mtk-flash: set brightness=255 # 触发2 <6>[14:30:02.793] leds-mtk-flash: set brightness=0 <6>[14:30:03.013] leds-mtk-flash: set brightness=255 # 触发3 ``` **结论**:三日志均记录**3次触发**,数据一致[^1]。 --- #### 5. **常见问题诊断** - **计数缺失**: 检查`logcat`中`Flashlight`相关的`ERROR`标签,常见于: ```log E HalFlash: GPIO write failed (err=-13) ``` - **异常重复触发**: 对比`dmesg`中GPIO状态变化频率,排查硬件干扰: ```bash adb shell "cat /sys/kernel/debug/gpio | grep flash" ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值