三方相机问题分析六:【没用相机,诡异的手电筒不可使用】下拉状态栏,手电筒置灰,无法打开,提提示相机正在使用
【关注我,后续持续新增专题博文,谢谢!!!】
上一篇我们讲了:
这一篇我们开始讲: 三方相机问题分析六:【没用相机,诡异的手电筒不可使用】下拉状态栏,点击手电筒,手电筒置灰,无法打开,提提示相机正在使用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:基于原理分析
- 手电筒和相机都是使用的闪光灯驱动。
- 手电筒不可使用,要么是闪光灯驱动工作导致闪光灯被占用、要么是systemui上层代码逻辑存在问题。
- 而无三方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
- 并不会调用connect call
- 并不会调用camxhal3.cpp的接口
- camxflash.cpp会有闪光灯的调用过程和状态
- 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接口里:
- 申请使用是调用: HAL3Module::GetInstance()->ReserveTorchForCamera()
- 释放资源是使用: 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 :基于新需求分析猜测,验证场景
长按和短按桌面相机图标发现:
- 长按不会调用connect call,不会调用camx hal3接口,会调用preconfig_open,接着调用CAM_ACQUIRE_DEV。但并不会打开相机,会显示app info等菜单。此时去下拉systemui,会发现手电筒变得不可使用。
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
- 短按点击会调用connect call,会调用camx hal3接口,会调用preconfig_open,会同时调用CAM_ACQUIRE_DEV和CAM_START_DEV。此时去下拉systemui,会发现手电筒也变得不可使用。但这个场景是正常,毕竟相机已经打开,其他三方APP不可抢占。
- 所以长按这种情况下,相机没有使用,而手电筒变得不可使用,显示是严重bug。
2.13 :解决方案
- preconfig_open新需求明显存在严重漏洞,长按桌面相机图标提前调用preconfig_open,可提升相机性能,但如果不打开相机时,将没有地方释放闪光灯资源,会长期持有,手电筒一直无法使用,且功耗一直增加。因此需要修改当前新需求。
- 新需求修改和验证时间周期长,也可以关闭此需求。
- 也可长按不触发preconfig_open,改成长按不触发,短按触发。
- 保留此需求,可设置长按相机图标,实现定时器,若超过5秒不打开相机,主动调用camera hal3 close接口关闭相机。方案如下:
@@ -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;
【关注我,后续持续新增专题博文,谢谢!!!】
下一篇讲解: