Mode d’emploi
- Copiez la commande et examinez le paquet avant de l’installer dans votre environnement agent.
- Consultez le document original pour les outils, identifiants et environnements requis.
- Décrivez les entrées et le livrable souhaité ; comparez la sortie aux sources.
npx skills add https://github.com/te-quanbzhang/skills-pool --skill android-camera-bugfix-skillAvant de commencer
- L’installation n’inclut ni abonnement au modèle, ni quota API, ni accès aux fichiers.
- Étoiles et installations reflètent l’activité, pas un test indépendant de qualité ou de sécurité.
Rendu depuis le dépôt source en conservant titres, exemples, code, tableaux, liens et images.
Android Camera Bugfix Skill
适用范围
用于 Android 项目中 camera 相关问题的排查、修复和验证,包括但不限于:
- 相机打不开
- 黑屏 / 花屏 / 绿屏
- 预览卡顿
- 拍照失败
- 拍照后图片异常
- 录像失败
- 前后摄切换异常
- 闪光灯异常
- 对焦异常
- 曝光异常
- 权限异常
- Camera2 / CameraX / HAL 相关问题
- Surface / TextureView / PreviewView 生命周期问题
- 相机被其他 App 占用
- 设备兼容性问题
Bugfix 总体原则
Camera bug 通常和以下因素强相关:
- Camera 权限
- Camera 生命周期
- Surface 生命周期
- Camera session 状态机
- 前后摄切换
- 预览和拍照流配置
- 设备硬件能力
- Android 版本差异
- App 前后台切换
- Camera HAL 稳定性
修复时不要只处理 UI 层异常,必须检查 camera open、session create、surface attach、capture request、callback 全链路。
常见问题分类
1. 相机打不开
重点检查:
- CAMERA 权限是否授予
- 相机是否被其他 App 占用
- cameraId 是否存在
- 是否在后台打开相机
- 是否重复 openCamera
- CameraDevice 是否未释放
- Activity / Fragment 生命周期是否异常
- Android 高版本权限或隐私限制
常见日志关键字:
CameraManager
CameraDevice
CameraCaptureSession
CameraService
CameraProvider
CameraX
Camera2
openCamera
onOpened
onDisconnected
onError
ERROR_CAMERA_IN_USE
ERROR_MAX_CAMERAS_IN_USE
ERROR_CAMERA_DISABLED
ERROR_CAMERA_DEVICE
ERROR_CAMERA_SERVICE2. 预览黑屏
重点检查:
- Surface 是否创建成功
- SurfaceTexture 是否可用
- TextureView / SurfaceView / PreviewView 生命周期
- preview request 是否成功 setRepeatingRequest
- capture session 是否创建成功
- target surface 是否正确
- 页面切换时是否释放过早
- 是否 camera 已打开但 session 未启动
重点 API:
CameraManager.openCamera(...)
CameraDevice.createCaptureSession(...)
CameraCaptureSession.setRepeatingRequest(...)
SurfaceTextureListener
SurfaceHolder.Callback
PreviewView3. 拍照失败
重点检查:
- ImageReader 是否创建
- ImageReader surface 是否加入 session
- CaptureRequest 是否设置正确
- onImageAvailable 是否回调
- 图片是否及时 close
- 是否存在 maxImages 未释放导致阻塞
- 拍照时 session 是否已经关闭
- 是否并发点击多次拍照
常见问题:
maxImages has already been acquired
ImageReader buffer full
Session has been closed
CameraDevice was already closed修复建议:
- 每个 Image 必须 close
- 拍照按钮增加防抖
- session close 后不再提交 request
- capture 回调中检查状态
- 保存图片放到后台线程
4. 前后摄切换异常
重点检查:
- 切换前是否停止 repeating
- 是否 close old session
- 是否 close old camera device
- 是否释放 ImageReader
- 是否重新绑定 Surface
- cameraId 是否正确
- 切换期间 UI 是否允许重复点击
推荐顺序:
stopRepeating
abortCaptures
close CaptureSession
close CameraDevice
release ImageReader if needed
open new CameraDevice
create new CaptureSession
start preview5. 闪光灯 / 对焦 / 曝光异常
重点检查:
- 设备是否支持 flash
- CONTROLAFMODE 是否正确
- CONTROLAEMODE 是否正确
- FLASH_MODE 是否正确
- 是否有触摸对焦区域
- sensor orientation 是否处理正确
- 前摄是否支持对应能力
常见能力查询:
CameraCharacteristics.FLASH_INFO_AVAILABLE
CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES
CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES
CameraCharacteristics.SENSOR_ORIENTATION
CameraCharacteristics.LENS_FACING推荐排查流程
Step 1:确认复现条件
记录:
- 设备型号
- Android 版本
- 前摄还是后摄
- Camera API:Camera1 / Camera2 / CameraX
- 是否首次打开
- 是否前后台切换后出现
- 是否旋转屏幕后出现
- 是否多次快速进入退出
- 是否其他 App 正在使用相机
- 是否权限拒绝后再授权
- 复现概率
Step 2:收集日志
推荐命令:
adb logcat -v time > camera_bug.log
adb shell dumpsys media.camera > dumpsys_camera.txt
adb shell dumpsys activity top > activity_top.txt
adb shell dumpsys package your.package.name > package_info.txt如涉及 native / HAL:
adb logcat | grep -i camera
adb shell ls /data/tombstones/
adb logcat -b crash -v timeCameraX 可重点搜索:
CameraX
UseCaseAttachState
CameraState
Preview
ImageCapture
ProcessCameraProviderCamera2 可重点搜索:
CameraDevice
CameraCaptureSession
CaptureRequest
CameraManager
ImageReaderStep 3:定位层级
按照以下顺序判断:
- App 是否申请并获得 CAMERA 权限
- 是否成功获取 cameraId
- 是否调用 openCamera
- 是否收到 onOpened
- 是否创建 preview surface
- 是否创建 capture session
- 是否调用 setRepeatingRequest
- 是否有预览帧
- 拍照时是否收到 capture callback
- ImageReader 是否收到 image
Step 4:检查代码
重点检查:
- Camera open / close 是否成对
- CaptureSession 生命周期
- Surface 生命周期
- ImageReader 是否释放
- HandlerThread 是否释放
- Activity / Fragment onResume / onPause
- 权限回调
- 前后台切换
- 横竖屏切换
- 快速点击
- 异步回调中的空指针和状态判断
常见修复策略
- 增加 Camera 状态机,避免重复 open / close
- 页面 pause 时主动释放 Camera
- Surface 未 ready 时不要 open session
- session closed 后不再提交 request
- ImageReader image 用完必须 close
- 拍照按钮防重复点击
- 前后摄切换加锁
- 异步回调中判断当前页面是否 still active
- 修复权限拒绝流程
- 针对特定设备降级分辨率或关闭高级能力
- CameraX 中正确 unbind / bindToLifecycle
CameraX 特别检查项
如果项目使用 CameraX,重点检查:
ProcessCameraProvider.getInstance(...)
cameraProvider.bindToLifecycle(...)
cameraProvider.unbindAll()
Preview
ImageCapture
ImageAnalysis
CameraSelector常见问题:
- 重复 bind use case
- 未 unbindAll
- PreviewView 未 attach
- LifecycleOwner 不正确
- ImageAnalysis 未关闭 image
- Executor 泄漏
Camera2 特别检查项
如果项目使用 Camera2,重点检查:
CameraManager.openCamera
CameraDevice.StateCallback
CameraCaptureSession.StateCallback
CaptureRequest.Builder
ImageReader
HandlerThread必须保证:
- CameraDevice close
- CameraCaptureSession close
- ImageReader close
- HandlerThread quitSafely
- Surface 有效
- 回调线程安全
代码审查重点
修复 camera bug 时,必须检查:
- 是否存在资源泄漏
- 是否处理权限拒绝
- 是否处理相机被占用
- 是否处理快速进入退出
- 是否处理横竖屏
- 是否处理前后台切换
- 是否处理异步回调晚于页面销毁
- 是否支持低端设备
- 是否引入 UI 卡顿
- 是否阻塞主线程
验证清单
至少验证:
- 首次打开相机
- 权限拒绝
- 权限授权
- 前摄打开
- 后摄打开
- 前后摄切换
- 拍照
- 连续拍照
- 闪光灯
- 对焦
- 横竖屏切换
- 前后台切换
- 锁屏再解锁
- 快速进入退出页面
- 其他 App 占用相机
- 低端设备
- Android 多版本
输出 Bugfix 结论模板
Root Cause:
- 问题原因:
Fix:
- 修改内容:
Risk:
- 影响范围:
Verification:
- 已验证场景:
- 未覆盖场景:
Logs:
- 关键日志:Heuristics
- For "camera won't open" on a previously-working flow, check whether a prior
openCamerawas abandoned without close — the HAL can refuse subsequent opens until a full process restart. - For "black preview but shutter works" — the preview use case is unconfigured or its
Surfacewas never attached to theCaptureSession; the still-capture path bypasses the preview surface. - For "capture hangs / never returns" — suspect
ImageReaderwithmaxImagesall acquired and noneclosed; the buffer pool is full. CheckonImageAvailablealways callsimage.close(). - For "front/rear switch freezes" — suspect the old
CameraCaptureSessionorCameraDevicewas not closed before the new open, or the session creation raced the old one's close. - For "flash does nothing on front camera" — device capability missing; always query
CameraCharacteristics.FLASH_INFO_AVAILABLEbefore building the flash mode into the request. - For "focus/exposure drift after switching cameras" — the new
CameraDeviceinherited default modes from old request builders; reset AF/AE modes explicitly per camera. - For "works on Pixel but fails on Samsung/Xiaomi" — device HAL differences; check
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVELand degrade gracefully forLIMITED/LEGACY. - For "camera breaks after background/foreground" —
onPauseshould close the session,onResumeshould reopen; any path that leaves the session closed while UI remains bound is a bug. - For CameraX "bind fails after unbindAll" — suspect the LifecycleOwner passed was destroyed or the
ProcessCameraProviderinstance was stale across Activity recreations. - For "tombstone / SIGSEGV in camera HAL" — escalate to device vendor; the app side can only add defensive session/device close and retry logic.
Anti-Patterns
- Opening the camera directly in
onCreatebeforeonResume— Surface may not be ready; session creation can race. - Calling
openCamerawhile an existingCameraDeviceis still open — results inERROR_CAMERA_IN_USEor silent replacement. - Submitting
setRepeatingRequestbefore the session'sonConfiguredcallback has fired — the session is not yet active. - Submitting a new
CaptureRequestafteronClosedhas fired on the session — throws silently or crashes. - Never calling
image.close()on anImageReaderimage — the buffer pool fills and subsequent captures block indefinitely. - Using
Activity's main thread for heavy capture request building — stalls the preview; move to a dedicatedHandlerThreadfor Camera2. - Assuming the front camera has the same capabilities as the rear — always re-query
CameraCharacteristicspercameraId. - Treating a black preview as "UI bug" and adding
setVisibility(View.VISIBLE)— the real bug is upstream in session/Surface binding. - Catching
CameraAccessExceptionbroadly and silently swallowing it — the user sees a broken camera with no path to retry. - Keeping
HandlerThreadfor the camera alive after Activity destroy — leaks a thread and its Looper per recreation. - Logging full
CaptureRequestpayloads — can contain device-identifying data; redact to the request template and relevant fields.
CodeGraph Integration
CodeGraph helps ground the camera diagnosis in the actual codebase structure. Run it before proposing a fix.
When to run CodeGraph:
- After the triage narrows the symptom to a specific camera sub-area (open / preview / capture / switch / flash / focus / device compatibility)
- When tracing the session lifecycle across Activity/Fragment/Compose lifecycle events
- When a fix may change how the camera is shared between screens (e.g., scan → preview → editor)
How:
codegraph explore "<camera-manager entry, e.g., CameraManager.openCamera call site>"
codegraph explore "<camera session / use-case handler class>"
codegraph explore "<ImageReader / capture call site>"What to look for from CodeGraph results (camera-focused):
- Callers of `openCamera` — which Activity/Fragment/ViewModel lifecycle events trigger opening; paired with which callers trigger close.
- Capture session lifecycle — callers of
createCaptureSessionandsetRepeatingRequest; any caller that submits requests without waiting foronConfiguredis suspect. - Surface owner chain — from
SurfaceTexture/TextureView/PreviewViewthrough attach to the session. Missing attach or early detach = black preview. - ImageReader lifecycle — every call site of
onImageAvailablemust have a guaranteedimage.close()path; any early-return without close leaks. - Camera-switch flow — the switch handler's sequence of stop/abort/close/reopen/rebind; out-of-order steps are the root cause of most switch freezes.
- HandlerThread / Executor — who holds the background thread used for camera callbacks; leaked threads appear here.
- Downstream impact — other screens that share camera state (preview → editor → share flow); a fix in one may break the handoff in another.
Scope note: CodeGraph does not reliably index XML layouts, AndroidManifest.xml, or Gradle build scripts. For camera-permission issues or CameraX Gradle dependency mismatches, supplement with rg/find on AndroidManifest.xml and build.gradle.
Fallback: If codegraph explore returns no meaningful results, proceed without it — CodeGraph is an enhancement, not a blocker. Fall back to rg/grep for openCamera / capture session / ImageReader call-site search.
Guardrails
- Run the full triage classification before jumping to a code fix — camera bugs are disproportionately driven by session lifecycle + device hardware capability.
- Always pair every
openCamerawith a confirmedclose, and everycreateCaptureSessionwith a confirmedclose— unmatched pairs are the #1 root cause. - Always call
image.close()on everyImageReaderimage, including on error/early-return paths. - Always query
CameraCharacteristicsper-camerId — never assume rear-camera capabilities apply to front. - Always degrade gracefully for
LIMITED/LEGACYhardware level devices rather than crashing on missing capabilities. - Always test on at least two devices from different OEMs — camera HAL differences are the dominant source of "works on my device".
- Always verify camera behavior across
onPause/onResume,onStop/onStart, and screen rotation — camera bugs hide in lifecycle gaps. - Never log full
CaptureRequestpayloads, camera IDs combined with device serial, or image bytes — redact to the request template andcameraIdalone. - Do not mask
CameraAccessException/IllegalStateExceptionfrom session/device calls — surface them with a user-visible retry path. - If
codegraph explorereturns no meaningful results, proceed without it — CodeGraph is an enhancement, not a blocker. Fall back torg/grep.




