当前位置: 首页 > ops >正文

三方相机问题分析六:【没用相机,诡异的手电筒不可使用】下拉状态栏,手电筒置灰,无法打开,提提示相机正在使用

【关注我,后续持续新增专题博文,谢谢!!!】

上一篇我们讲了

        这一篇我们开始讲 三方相机问题分析六:【没用相机,诡异的手电筒不可使用】下拉状态栏,点击手电筒,手电筒置灰,无法打开,提提示相机正在使用9348353

目录

一、问题背景

二、:问题分析过程

    2.1:基于原理分析

    2.2 :systemui分析手电筒状态

    2.3 :camera framework分析手电筒回调

    2.4 :继续查看谁在使用手电筒

    2.5 :尝试直接打开手电筒看看会不会调用connect call

    2.6 :camx hal接力分析

    2.7 :相机未打开过,camx flash驱动代码未执行,为什么会回调?why?

    2.8 :查看KMD CAM-FLASH驱动

    2.9 :分析CAM_ACQUIRE_DEV被执行的地方。

    2.10 :全局搜索ReserveTorchForCamera

    2.11 :分析该接口

    2.12 :基于新需求分析猜测,验证场景

    2.13 :解决方案


一、问题背景

【操作步骤】【Operation steps】下拉状态栏,点击手电筒
【实际结果】【Actual results】手电筒置灰,无法打开,提示相机正在使用
【期望结果】【Expected results】手电筒可以正常使用

【出现次数/测试次数】【Occurrence Times/Test Times】偶现,

开发本地无法复现

二、:问题分析过程

    2.1:基于原理分析

  1. 手电筒和相机都是使用的闪光灯驱动。
  2. 手电筒不可使用,要么是闪光灯驱动工作导致闪光灯被占用、要么是systemui上层代码逻辑存在问题。
  3. 而无三方app在使用闪光灯,当前问题便变得扑朔迷离了,优先上层systemui来分析。

     

    2.2 :systemui分析手电筒状态

        由于问题出现在15:47:36左右,systemui搜索onTorchModeUnavailable 关键字,分析到如下日志:

行 123877: 06-13 15:47:36.802 10170 21962 W MIADSFlashLightEventMonitor: onTorchModeUnavailable!

行 123880: 06-13 15:47:36.802  2945  2945 D ScreenOffTorchHelper: onTorchModeUnavailable cameraId is 0

行 123882: 06-13 15:47:36.802  2945  2945 D ScreenOffTorchHelper: onTorchModeUnavailable cameraId is 3

行 123886: 06-13 15:47:36.803  2945  4143 D TorchManagerService: onTorchModeUnavailable, start to setRIOClientInfo.

行 123927: 06-13 15:47:36.805  2945  4143 D TorchManagerService: onTorchModeUnavailable, start to setRIOClientInfo.

行 123977: 06-13 15:47:36.812  4354  4471 I SystemUi--QuickSettings: FlashlightController-->onTorchModeUnavailable cameraId=0

而这个状态是camera framework层回调状态发生变化了,需要查看手电筒回调函数是否有变化,因此需要camera framework组协助。 

    2.3 :camera framework分析手电筒回调

camera framework组接力分析,搜索onTorchStatusChangedLocked关键字,分析到如下日志:

	行 112260: 06-13 15:47:15.802  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=1行 112263: 06-13 15:47:15.804  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=3, newStatus=1行 118905: 06-13 15:47:25.168  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 118986: 06-13 15:47:25.196  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 119951: 06-13 15:47:26.108  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120223: 06-13 15:47:26.905  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120320: 06-13 15:47:27.256  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120487: 06-13 15:47:27.973  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=1行 123803: 06-13 15:47:36.791  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=0行 123825: 06-13 15:47:36.795  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=3, newStatus=0

发现手电筒状态一直在变化,且最终status为0,也就是手电筒不可使用状态。然而java层的相机相关回调函数,一般都是有底层camera HAL来触发回调的,说明并非systemui上层逻辑问题,而是闪光灯驱动工作导致闪光灯被占用。需要camera hal组来接力分析。

    2.4 :继续查看谁在使用手电筒

闪光灯使用者要么是手电筒,要么是三方相机app,我们搜索connect call关键字,即可知道谁在使用闪光灯:

	行 96633: 06-13 15:47:11.516  2321 24904 I CameraService: CameraService::connect call (PID 21313 "com.camera", camera ID 0) and Camera API version 2行 112260: 06-13 15:47:15.802  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=1行 112263: 06-13 15:47:15.804  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=3, newStatus=1行 118905: 06-13 15:47:25.168  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 118986: 06-13 15:47:25.196  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 119951: 06-13 15:47:26.108  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120223: 06-13 15:47:26.905  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120320: 06-13 15:47:27.256  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120487: 06-13 15:47:27.973  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=1行 123803: 06-13 15:47:36.791  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=0行 123825: 06-13 15:47:36.795  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=3, newStatus=0行 123877: 06-13 15:47:36.802 10170 21962 W MIADSFlashLightEventMonitor: onTorchModeUnavailable!行 123880: 06-13 15:47:36.802  2945  2945 D ScreenOffTorchHelper: onTorchModeUnavailable cameraId is 0行 123882: 06-13 15:47:36.802  2945  2945 D ScreenOffTorchHelper: onTorchModeUnavailable cameraId is 3行 123886: 06-13 15:47:36.803  2945  4143 D TorchManagerService: onTorchModeUnavailable, start to setRIOClientInfo.行 123927: 06-13 15:47:36.805  2945  4143 D TorchManagerService: onTorchModeUnavailable, start to setRIOClientInfo.行 123977: 06-13 15:47:36.812  4354  4471 I SystemUi--QuickSettings: FlashlightController-->onTorchModeUnavailable cameraId=0

发现connect call有在15:47:11时间点有打开过相机,而出现问题的时间是15:47:36,隔了20分钟,所以不太可能是相机app打开相机导致的。由camera hal进一步确认hal流程。

    2.5 :尝试直接打开手电筒看看会不会调用connect call

单独打开手电筒,日志如下:

18844: 06-13 15:47:25.155  1702 22521 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1483 Initialize() Flash[0] [back_pmic_flash] Acquired, pipelineId:0, hCSL: 0x40200, hFlashDevice: 0x70101行 118899: 06-13 15:47:25.167  1702  3368 V CamX    : [ VERB][UNKNOWN] camxflash.cpp:1761 FirePMIC() SENSOR_FLASH_DEBUG: Flash[0] Fire ReqId=1 Operation=1 LEDs=2行 118900: 06-13 15:47:25.167  1702  3368 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1832 FirePMIC() Flash[0] Operation: Low: numberOfFlashs = 2 1:2 = 110 : 110, requestId= 1行 118905: 06-13 15:47:25.168  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 118981: 06-13 15:47:25.195  1702  3370 V CamX    : [ VERB][UNKNOWN] camxflash.cpp:1761 FirePMIC() SENSOR_FLASH_DEBUG: Flash[0] Fire ReqId=2 Operation=1 LEDs=2行 118982: 06-13 15:47:25.195  1702  3370 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1832 FirePMIC() Flash[0] Operation: Low: numberOfFlashs = 2 1:2 = 60 : 60, requestId= 2行 118986: 06-13 15:47:25.196  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 119948: 06-13 15:47:26.107  1702  3371 V CamX    : [ VERB][UNKNOWN] camxflash.cpp:1761 FirePMIC() SENSOR_FLASH_DEBUG: Flash[0] Fire ReqId=3 Operation=1 LEDs=2行 119949: 06-13 15:47:26.107  1702  3371 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1832 FirePMIC() Flash[0] Operation: Low: numberOfFlashs = 2 1:2 = 100 : 100, requestId= 3行 119951: 06-13 15:47:26.108  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120220: 06-13 15:47:26.904  1702  3368 V CamX    : [ VERB][UNKNOWN] camxflash.cpp:1761 FirePMIC() SENSOR_FLASH_DEBUG: Flash[0] Fire ReqId=4 Operation=1 LEDs=2行 120221: 06-13 15:47:26.904  1702  3368 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1832 FirePMIC() Flash[0] Operation: Low: numberOfFlashs = 2 1:2 = 125 : 125, requestId= 4行 120223: 06-13 15:47:26.905  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120317: 06-13 15:47:27.255  1702  3370 V CamX    : [ VERB][UNKNOWN] camxflash.cpp:1761 FirePMIC() SENSOR_FLASH_DEBUG: Flash[0] Fire ReqId=5 Operation=1 LEDs=2行 120318: 06-13 15:47:27.255  1702  3370 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1832 FirePMIC() Flash[0] Operation: Low: numberOfFlashs = 2 1:2 = 160 : 160, requestId= 5行 120320: 06-13 15:47:27.256  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=2行 120424: 06-13 15:47:27.953  1702  3371 V CamX    : [ VERB][UNKNOWN] camxflash.cpp:1761 FirePMIC() SENSOR_FLASH_DEBUG: Flash[0] Fire ReqId=6 Operation=0 LEDs=2行 120425: 06-13 15:47:27.953  1702  3371 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:1821 FirePMIC() Flash[0] Operation: OFF requestId= 6行 120469: 06-13 15:47:27.958  1702  3832 I CamX    : [CORE_CFG][SENSOR ] camxflash.cpp:166 Destroy() Flash[0] Release行 120487: 06-13 15:47:27.973  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=1
  1. 并不会调用connect call
  2. 并不会调用camxhal3.cpp的接口
  3. camxflash.cpp会有闪光灯的调用过程和状态
  4. onTorchStatusChangedLocked也会调用

    2.6 :camx hal接力分析

搜索camxhal3.cpp关键字,发现相机在15:47:15.845就已经关闭,后面再也没有使用过相机。

06-13 15:47:15.845  1702  3832 E CamX    : [ALWAYS_ON   ] camxhal3.cpp:1249 close() HAL3Close end

而出现问题在15:47:36左右,搜索camxflash.cpp,并没有调用,此时有点懵了。

    2.7 :相机未打开过,camx flash驱动代码未执行,为什么会回调?why?

此时我们查看kernel KMD的flash驱动代码看看执行情况,这里才是真正是驱动代码。

    2.8 :查看KMD CAM-FLASH驱动

查看kernel dmesg日志:发现问题出现点,确认又执行CAM_ACQUIRE_DEV:

[31092.104338] CAM_INFO: CAM-FLASH: cam_flash_driver_cmd: 101 CAM_ACQUIRE_DEV for dev_hdl: 0x9e010b

哪到底被谁执行的?

    2.9 :分析CAM_ACQUIRE_DEV被执行的地方。

熟悉camx架构的话,会知道闪光灯流程在camxhal3.cpp open接口里:

  1. 申请使用是调用: HAL3Module::GetInstance()->ReserveTorchForCamera()
  2. 释放资源是使用: HAL3Module::GetInstance()->ReleaseTorchForCamera()

    2.10 :全局搜索ReserveTorchForCamera

发现只有两处使用ReserveTorchForCamera,除了camxhal3.cpp open接口,还有一个preconfig_open接口会调用,我们搜索日志发现:

	行 120487: 06-13 15:47:27.973  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=1行 123776: 06-13 15:47:36.781  1702  3831 E CamX    : [ALWAYS_ON   ] camxpreconfig.cpp:1963 Preconfig() preconfig,openTypes:0,camid:0,operation:0x8001行 123777: 06-13 15:47:36.781  1702  3831 E CamX    : [ALWAYS_ON   ] camxpreconfig.cpp:1183 preconfig_open() HAL3Open begin cameraId: 0 packagename:com..camera行 123803: 06-13 15:47:36.791  2321  4004 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=0, newStatus=0行 123817: 06-13 15:47:36.793  1702  3831 E CamX    : [ALWAYS_ON   ] camxpreconfig.cpp:1283 preconfig_open() HAL3Open end行 123825: 06-13 15:47:36.795  2321 24904 I CameraService: onTorchStatusChangedLocked: Torch status changed for cameraId=3, newStatus=0

果然是因为preconfig_open被调用后,马上onTorchStatusChangedLocked就回调了,newStatus=0 变成了不可使用状态。

    2.11 :分析该接口

经过分析发现该接口是一个性能新需求,意外被开启后,导致此问题。这个需求会在点击桌面相机图标就会下发命令到camx并执行preconfig_open调用ReserveTorchForCamera占用闪光灯资源,并且在camera app oncreate之前就会调用,比opencamera api调用更早。然而点击相机图标就会调用相机,只可能是长按相机图标触发该接口,才不会打开相机。

static int preconfig_open(void)
{// Reserve the Torch resource for camera.// If torch already switched on, then turn it off and reserve for camera.HAL3Module::GetInstance()->ReserveTorchForCamera(GetCHIAppCallbacks()->chi_remap_camera_id(cameraId, IdRemapTorch).first, cameraId);if (CamxResultSuccess != result){// If open fails, then release the Torch resource that we reserved.HAL3Module::GetInstance()->ReleaseTorchForCamera(GetCHIAppCallbacks()->chi_remap_camera_id(cameraId, IdRemapTorch).first, cameraId);}CAMX_LOG_CORE_CFG(CamxLogGroupHAL, "HalOp: End OPEN, logicalCameraId: %d, cameraId: %d",logicalCameraId, cameraId);
}

    2.12 :基于新需求分析猜测,验证场景

长按和短按桌面相机图标发现:

  1. 长按不会调用connect call,不会调用camx hal3接口,会调用preconfig_open,接着调用CAM_ACQUIRE_DEV。但并不会打开相机,会显示app info等菜单。此时去下拉systemui,会发现手电筒变得不可使用。
  2. 01-02 00:58:26.671  3422  3804 E CamX    : [ALWAYS_ON   ] camxpreconfig.cpp:1183 preconfig_open() HAL3Open begin cameraId: 0 packagename:com..camera
    01-02 00:58:26.675  3422  3804 I CamX    : [CORE_CFG][HAL    ] camxpreconfig.cpp:1219 preconfig_open() HalOp: Begin OPEN, logicalCameraId: 0, cameraId: 0
    01-02 00:58:26.677  3422  3804 I CamX    : [CORE_CFG][HAL    ] camxpreconfig.cpp:1279 preconfig_open() HalOp: End OPEN, logicalCameraId: 0, cameraId: 0
    01-02 00:58:26.677  3422  3804 E CamX    : [ALWAYS_ON   ] camxpreconfig.cpp:1283 preconfig_open() HAL3Open end
  3. 短按点击会调用connect call,会调用camx hal3接口,会调用preconfig_open,会同时调用CAM_ACQUIRE_DEV和CAM_START_DEV。此时去下拉systemui,会发现手电筒也变得不可使用。但这个场景是正常,毕竟相机已经打开,其他三方APP不可抢占。
  4. 所以长按这种情况下,相机没有使用,而手电筒变得不可使用,显示是严重bug。

    2.13 :解决方案

  1. preconfig_open新需求明显存在严重漏洞,长按桌面相机图标提前调用preconfig_open,可提升相机性能,但如果不打开相机时,将没有地方释放闪光灯资源,会长期持有,手电筒一直无法使用,且功耗一直增加。因此需要修改当前新需求。
  2. 新需求修改和验证时间周期长,也可以关闭此需求。
  3. 也可长按不触发preconfig_open,改成长按不触发,短按触发。
  4. 保留此需求,可设置长按相机图标,实现定时器,若超过5秒不打开相机,主动调用camera hal3 close接口关闭相机。方案如下:
  5. @@ -10,6 +10,10 @@
    +#include <stdio.h>
    +#include <signal.h>
    +#include <sys/time.h>
    +#include <unistd.h>+static INT32 preconfigTimeout = 5;
    +static INT32 preconfigDefCameraID = 0;+int call_close(
    +    struct hw_device_t* pHwDeviceAPI)
    +{
    +    return close(pHwDeviceAPI);
    +}
    +int call_flush(
    +    const struct camera3_device* pCamera3DeviceAPI)
    +{
    +    return flush(pCamera3DeviceAPI);
    +}
    +int preconfig_close(struct hw_device_t* pHwDeviceAPI)
    +{
    +    int resultOut = 0;
    +    resultOut = call_close(pHwDeviceAPI);
    +    return resultOut;
    +}
    +int preconfig_flush(const struct camera3_device * pCamera3DeviceAPI)
    +{
    +    int resultOut = 0;
    +    resultOut = call_flush(pCamera3DeviceAPI);
    +    return resultOut;
    +}
    +static struct itimerval timer;
    +static BOOL hal3Opend = FALSE;
    +extern void timer_handler(int signum);
    +void stop_timer(void)
    +{
    +    timer.it_value.tv_sec = 0;
    +    timer.it_value.tv_usec = 0;
    +    timer.it_interval.tv_sec = 0;
    +    timer.it_interval.tv_usec = 0;
    +
    +	setitimer(ITIMER_REAL, &timer, NULL);
    +}
    +
    +int start_timer(void)
    +{
    +    signal(SIGALRM, timer_handler);
    +
    +    timer.it_value.tv_sec = preconfigTimeout;
    +    timer.it_value.tv_usec = 0;
    +    timer.it_interval.tv_sec = 0;
    +    timer.it_interval.tv_usec = 0;
    +
    +    if (setitimer(ITIMER_REAL, &timer, NULL) == -1) {
    +        CAMX_LOG_ERROR(CamxLogGroupHAL, "start_timer fail");
    +        return 1;
    +    }
    +    return 0;
    +}
    +void timer_handler(int signum) {
    +    if((isPreopenDone() || isPreconfigDone()) && !hal3Opend)
    +    {
    +        CAMX_LOG_ALWAYS_ON(CamxLogGroupHAL, "Long press the camera icon, timeout to preconfig_close, Status = 0x%x",getGlobalStatus());
    +        if (0 != preconfig_flush(GetCameraDeviceAPI()))
    +        {
    +            CAMX_LOG_ALWAYS_ON(CamxLogGroupHAL, "preconfig cameraid error, do flush fail");
    +        }
    +        if (0 != preconfig_close(&(GetCameraDeviceAPI()->common)))
    +        {
    +            CAMX_LOG_ALWAYS_ON(CamxLogGroupHAL, "preconfig cameraid error, do close camera fail");
    +        }
    +        hal3Opend = FALSE;
    +    }
    +
    +    stop_timer();
    +}
    +@@ -1298,6 +1334,8 @@ static int preconfig_open(void)
    +    start_timer();
    +    hal3Opend = FALSE;@@ -2049,6 +2109,7 @@ :CamxResult OpenStart(   {
    +    hal3Opend = TRUE;

【关注我,后续持续新增专题博文,谢谢!!!】

下一篇讲解

http://www.xdnf.cn/news/17660.html

相关文章:

  • 模型驱动的自动驾驶AI系统全生命周期安全保障
  • 论文Review 激光SLAM VoxelMap | RAL 2022 港大MARS出品!| 经典平面特征体素激光SLAM
  • .NET 应用程序 Linux下守护进程脚本编写
  • 基于.Net Framework4.5 Web API 引用Swagger
  • JavaWeb核心:HttpServletRequest与HttpServletResponse详解
  • mac环境下安装git并配置密钥等
  • 从行业场景到视觉呈现:3ds Max 与 C4D 效果图的本质分野
  • Pycharm现有conda环境有对应env,但是添加后没反应
  • 学习嵌入式的第十九天——Linux——文件编程
  • Spring Boot 使用 @NotBlank + @Validated 优雅校验参数
  • 疯狂星期四文案网第38天运营日记
  • TorchDynamo - API
  • 互联网大厂Java求职面试实录:Spring Boot到微服务与AI的技术问答
  • 【Unity开发】Unity核心学习(一)
  • 如何在 Ubuntu 24.04 LTS Noble Linux 上安装 FileZilla Server
  • MyBatis 中 XML 与 DAO 接口的位置关系及扫描机制详解
  • react与vue的对比,来实现标签内部类似v-for循环,v-if等功能
  • 万字详解C++11列表初始化与移动语义
  • 如何把ubuntu 22.04下安装的mysql 8 的 数据目录迁移到另一个磁盘目录
  • 基于深度学习的苹果品质智能检测算法研究
  • Kubernetes(K8S)中,kubectl describe node与kubectl top pod命令显示POD资源的核心区别
  • .net\c#web、小程序、安卓开发之基于asp.net家用汽车销售管理系统的设计与实现
  • Android Activity 的对话框(Dialog)样式
  • LaTeX(排版系统)Texlive(环境)Vscode(编辑器)环境配置与安装
  • PostgreSQL——索引
  • SpringBoot工程妙用:不启动容器也能享受Fat Jar的便利
  • Redis:是什么、能做什么?
  • 第十三节:后期处理:效果增强
  • MySQL优化常用的几个方法
  • 使用 Python Selenium 和 Requests 实现歌曲网站批量下载实战