android闪光灯源码分析

     

目录

一、APP层源码分析

                  二,framework层代码分析

        ​​​​​​​2.1 binder溯源


        这几天撸了android11 aosp闪光灯源码,本着前人栽树后人乘凉的原则,有志于android系统开发的新同学们提供一盏明灯,照亮你们前行。

        本人撸代码风格,喜欢从app撸到kernel,启航出发。

一、APP层源码分析

        下拉状态栏,可见“手电筒”快捷开关,点击后开启手电筒,UI见下图,

这部分代码,在目录:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java,点击按钮回调,

    protected void handleClick() {if (ActivityManager.isUserAMonkey()) {return;}boolean newState = !mState.value;refreshState(newState);//点击“手电筒”核心核数mFlashlightController.setFlashlight(newState);}

通过 mFlashlightController.setFlashlight(newState)走到文件

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java,

    public void setFlashlight(boolean enabled) {boolean pendingError = false;synchronized (this) {if (mCameraId == null) return;if (mFlashlightEnabled != enabled) {mFlashlightEnabled = enabled;try {//核心调用mCameraManager.setTorchMode(mCameraId, enabled);} catch (CameraAccessException e) {Log.e(TAG, "Couldn't set torch mode", e);mFlashlightEnabled = false;pendingError = true;}}}dispatchModeChanged(mFlashlightEnabled);if (pendingError) {dispatchError();}}

通过mCameraManager.setTorchMode(mCameraId, enabled)走到frameworks/base/core/java/android/hardware/camera2/CameraManager.java,

    public void setTorchMode(@NonNull String cameraId, boolean enabled)throws CameraAccessException {if (CameraManagerGlobal.sCameraServiceDisabled) {throw new IllegalArgumentException("No cameras available on device");}CameraManagerGlobal.get().setTorchMode(cameraId, enabled);}

CameraManagerGlobal.get().setTorchMode(cameraId, enabled)走到,

        public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {synchronized(mLock) {if (cameraId == null) {throw new IllegalArgumentException("cameraId was null");}ICameraService cameraService = getCameraService();if (cameraService == null) {throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,"Camera service is currently unavailable");}try {cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);} catch(ServiceSpecificException e) {throwAsPublicException(e);} catch (RemoteException e) {throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,"Camera service is currently unavailable");}}}
        ICameraService cameraService = getCameraService();看到这句是不是很熟悉,android获取系统服务,跨进程调用。只是和我们app开发常用的 不同,这里直接拿到camera服务的proxy。对下面这行代码不理解的,可以学习下android binder机制,本质就是拿到camera服务的proxy
ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);

        原来操作“手电筒”的不是单独模块,而是通过camera模块来控制的,666。

二,framework层代码分析

2.1 binder溯源

        由第一部分分析可知,“手电筒”通过cameraservice来操作,结合binder知识,可以在ICameraService.aidl接口定义中找到,

void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);

aidl文件会自动生成java文件,再通过jni调用到cpp文件,最终在ICameraService.cpp中实现了client的调用,

::android::binder::Status BpCameraService::setTorchMode(const ::android::String16& cameraId, bool enabled, const ::android::sp<::android::IBinder>& clientBinder) {::android::Parcel _aidl_data;::android::Parcel _aidl_reply;::android::status_t _aidl_ret_status = ::android::OK;::android::binder::Status _aidl_status;_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());if (((_aidl_ret_status) != (::android::OK))) {goto _aidl_error;}_aidl_ret_status = _aidl_data.writeString16(cameraId);if (((_aidl_ret_status) != (::android::OK))) {goto _aidl_error;}_aidl_ret_status = _aidl_data.writeBool(enabled);if (((_aidl_ret_status) != (::android::OK))) {goto _aidl_error;}_aidl_ret_status = _aidl_data.writeStrongBinder(clientBinder);if (((_aidl_ret_status) != (::android::OK))) {goto _aidl_error;}_aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 15 /* setTorchMode */, _aidl_data, &_aidl_reply);if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && ICameraService::getDefaultImpl())) {return ICameraService::getDefaultImpl()->setTorchMode(cameraId, enabled, clientBinder);}if (((_aidl_ret_status) != (::android::OK))) {goto _aidl_error;}_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);if (((_aidl_ret_status) != (::android::OK))) {goto _aidl_error;}if (!_aidl_status.isOk()) {return _aidl_status;}_aidl_error:_aidl_status.setFromStatusT(_aidl_ret_status);return _aidl_status;
}

通过remote()->transact()发起IPC请求,事务码FIRST_CALL_TRANSACTION + 15对应setTorchMode方法,数据通过_aidl_dataParcel传递,执行到CameraService.cpp文件,

Status CameraService::setTorchMode(const String16& cameraId, bool enabled,const sp<IBinder>& clientBinder) {Mutex::Autolock lock(mServiceLock);ATRACE_CALL();if (enabled && clientBinder == nullptr) {ALOGE("%s: torch client binder is NULL", __FUNCTION__);return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,"Torch client Binder is null");}String8 id = String8(cameraId.string());int uid = CameraThreadState::getCallingUid();if (shouldRejectSystemCameraConnection(id)) {return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to set torch mode"" for system only device %s: ", id.string());}// verify id is valid.auto state = getCameraState(id);if (state == nullptr) {ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string());return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,"Camera ID \"%s\" is a not valid camera ID", id.string());}StatusInternal cameraStatus = state->getStatus();if (cameraStatus != StatusInternal::PRESENT &&cameraStatus != StatusInternal::NOT_AVAILABLE) {ALOGE("%s: camera id is invalid %s, status %d", __FUNCTION__, id.string(), (int)cameraStatus);return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,"Camera ID \"%s\" is a not valid camera ID", id.string());}{Mutex::Autolock al(mTorchStatusMutex);TorchModeStatus status;status_t err = getTorchStatusLocked(id, &status);if (err != OK) {if (err == NAME_NOT_FOUND) {return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,"Camera \"%s\" does not have a flash unit", id.string());}ALOGE("%s: getting current torch status failed for camera %s",__FUNCTION__, id.string());return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,"Error updating torch status for camera \"%s\": %s (%d)", id.string(),strerror(-err), err);}if (status == TorchModeStatus::NOT_AVAILABLE) {if (cameraStatus == StatusInternal::NOT_AVAILABLE) {ALOGE("%s: torch mode of camera %s is not available because ""camera is in use", __FUNCTION__, id.string());return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,"Torch for camera \"%s\" is not available due to an existing camera user",id.string());} else {ALOGE("%s: torch mode of camera %s is not available due to ""insufficient resources", __FUNCTION__, id.string());return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,"Torch for camera \"%s\" is not available due to insufficient resources",id.string());}}}{// Update UID map - this is used in the torch status changed callbacks, so must be done// before setTorchModeMutex::Autolock al(mTorchUidMapMutex);if (mTorchUidMap.find(id) == mTorchUidMap.end()) {mTorchUidMap[id].first = uid;mTorchUidMap[id].second = uid;} else {// Set the pending UIDmTorchUidMap[id].first = uid;}}status_t err = mFlashlight->setTorchMode(id, enabled);if (err != OK) {int32_t errorCode;String8 msg;switch (err) {case -ENOSYS:msg = String8::format("Camera \"%s\" has no flashlight",id.string());errorCode = ERROR_ILLEGAL_ARGUMENT;break;default:msg = String8::format("Setting torch mode of camera \"%s\" to %d failed: %s (%d)",id.string(), enabled, strerror(-err), err);errorCode = ERROR_INVALID_OPERATION;}ALOGE("%s: %s", __FUNCTION__, msg.string());return STATUS_ERROR(errorCode, msg.string());}{// update the link to client's deathMutex::Autolock al(mTorchClientMapMutex);ssize_t index = mTorchClientMap.indexOfKey(id);if (enabled) {if (index == NAME_NOT_FOUND) {mTorchClientMap.add(id, clientBinder);} else {mTorchClientMap.valueAt(index)->unlinkToDeath(this);mTorchClientMap.replaceValueAt(index, clientBinder);}clientBinder->linkToDeath(this);} else if (index != NAME_NOT_FOUND) {mTorchClientMap.valueAt(index)->unlinkToDeath(this);}}int clientPid = CameraThreadState::getCallingPid();const char *id_cstr = id.c_str();const char *torchState = enabled ? "on" : "off";ALOGI("Torch for camera id %s turned %s for client PID %d", id_cstr, torchState, clientPid);logTorchEvent(id_cstr, torchState , clientPid);return Status::ok();
}

其中,关键句status_t err = mFlashlight->setTorchMode(id, enabled);再由hal层交互可知,‌
最终通过CameraProviderManager查询HAL实现的setTorchMode()接口来控制device。

status_t CameraProviderManager::setTorchMode(const std::string &id, bool enabled) {std::lock_guard<std::mutex> lock(mInterfaceMutex);auto deviceInfo = findDeviceInfoLocked(id);if (deviceInfo == nullptr) return NAME_NOT_FOUND;// Pass the camera ID to start interface so that it will save it to the map of ICameraProviders// that are currently in use.sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();if (parentProvider == nullptr) {return DEAD_OBJECT;}const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();if (interface == nullptr) {return DEAD_OBJECT;}saveRef(DeviceMode::TORCH, deviceInfo->mId, interface);return deviceInfo->setTorchMode(enabled);
}

最终,通过deviceInfo->setTorchMode(enabled)来实现对硬件的操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/90554.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/90554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文心一言4.5开源部署指南及文学领域测评

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、引言 二、文心一言开源模型 2.1 MoE架构 2.2 文心一言MoE架构 三、文心一言稠密模型部署 3.1 产品选择 3.2 环境选择 3.3 Python3.12安装 3.3 PaddlePaddle-GPU安装 3.4 FastDeploy-GPU安装 ​编辑3.…

深入探讨 C++ 中的浮点数数据类型

核心概念&#xff1a;IEEE 754 标准 C 中的浮点数&#xff08;float, double, long double&#xff09;在绝大多数现代系统上遵循 IEEE 754 标准。这个标准定义了浮点数在内存中的二进制表示方式、运算规则、特殊值&#xff08;如无穷大、NaN&#xff09;等。数据类型与精度 fl…

相机:以鼠标点为中心缩放(使用OpenGL+QT开发三维CAD)

很多软件中&#xff08;Auto CAD、ODA等&#xff09;支持以鼠标点为中心进行放缩操作&#xff0c;有什么黑科技吗&#xff1f; 本章节为相机原理和实现的补充内容&#xff0c;支持鼠标放缩时以鼠标点为中心进行放缩。 对应视频课程已上线&#xff0c;欢迎观看和支持~ https:…

​​XAMPP安全升级指南:修复CVE-2024-4577漏洞,从PHP 8.2.12升级至PHP 8.4.10​​

​​1. 背景与漏洞概述​​ 近期,PHP官方披露了一个高危漏洞 ​​CVE-2024-4577​​,该漏洞影响PHP 8.2.x及更早版本,可能导致远程代码执行(RCE)或信息泄露。由于XAMPP默认捆绑的PHP版本(如8.2.12)可能受此漏洞影响,建议用户尽快升级至最新的​​PHP 8.4.10​​(或官…

ES 压缩包安装

以下是 Elasticsearch (ES) 通过 .tar.gz 压缩包安装的详细步骤&#xff08;适用于 Linux/macOS 系统&#xff09;&#xff1a; 1. 准备工作 1.1 检查系统依赖 Java 环境&#xff1a;ES 需要 JDK&#xff0c;推荐 OpenJDK 11/17&#xff08;ES 7.x/8.x 兼容版本&#xff09;。…

RoboRefer:面向机器人视觉-语言模型推理的空间参考

25年6月来自北航、北大和北京智源的论文“RoboRefer: Towards Spatial Referring with Reasoning in Vision-Language Models for Robotics”。 空间参考是实体机器人与三维物理世界交互的基本能力。然而&#xff0c;即使有了强大的预训练视觉-语言模型 (VLM)&#xff0c;近期方…

【Unity】MiniGame编辑器小游戏(十)连连看【Link】

更新日期:2025年7月9日。 项目源码:获取项目源码 索引 连连看【Link】一、游戏最终效果二、玩法简介三、正式开始1.定义游戏窗口类2.规划游戏窗口、视口区域3.方块 Block①.定义方块类②.生成方块所有类型③.生成连连看棋盘④.绘制方块阵列4.连线 Line①.点击方块连线②.尝试…

Enable ADB Debugging Before Connect

If you don’t enable Developer Options and turn on USB Debugging before plugging in the cable, adb devices won’t detect the phone because the Android system doesn’t trust the connection yet. Here’s what you need to do step-by-step to fix this:✅ 1. Enab…

从互联网电脑迁移Dify到内网部署Dify方法记录

一、在互联网电脑上准备迁移文件1. 保存 Docker 镜像# 获取所有 Dify 相关镜像&#xff08;根据实际容器名调整&#xff09; docker ps --filter "namedify" --format "{{.Image}}" | sort -u > dify-images.list# 保存镜像为 .tar 文件 docker save $(…

【EGSR2025】材质+扩散模型+神经网络相关论文整理随笔(一)

MatSwap: Light-aware material transfers in images介绍任务&#xff1a;输入一张拍摄图像、示例材质纹理图像&#xff08;这里跟BRDF无关&#xff0c;通常我们讲到材质一般指的是SVBRDF&#xff0c;但是这里的材质指的只是纹理&#xff09;、用户为拍摄图像指定的遮罩区域&am…

饿了么el-upload上传组件报错:TypeError: ***.upload.addEventListener is not a function

在本地上传没有报这个错误&#xff0c;部署到服务器后会报这个错误&#xff0c;一开始以为是服务器配置等什么原因&#xff0c;但是一想这个报错应该还是在前端&#xff0c;接口都还没请求&#xff0c;不可能到后台去&#xff0c;后面搜了好几个AI也没有找到想要的答案或解决方…

淘宝直播与开源链动2+1模式AI智能名片S2B2C商城小程序的融合发展研究

摘要&#xff1a;本文聚焦于淘宝直播这一以“网红”内容为主的社交电商平台&#xff0c;深入分析其特点与流量入口优势。同时&#xff0c;引入开源链动21模式AI智能名片S2B2C商城小程序这一新兴概念&#xff0c;探讨二者融合的可能性与潜在价值。通过分析融合过程中的技术、市场…

【macos用镜像站体验】Claude Code入门使用教程和常用命令

一、下载安装nodejs # macOS 用户安装nodejs brew update brew install node二、安装官方Claude Code # 安装 Claude Code npm install -g anthropic-ai/claude-code # 查看版本 claude --version三、正式使用&#xff08;国内镜像站&#xff09; 今天发现的一个镜像站&…

算法学习笔记:11.冒泡排序——从原理到实战,涵盖 LeetCode 与考研 408 例题

在排序算法的大家族中&#xff0c;冒泡排序是最基础也最经典的算法之一。它的核心思想简单易懂&#xff0c;通过重复地走访待排序序列&#xff0c;一次比较两个相邻的元素&#xff0c;若它们的顺序错误就把它们交换过来&#xff0c;直到没有需要交换的元素为止。虽然冒泡排序的…

Linux小白学习基础内容

记录第一天重新学习2025/7/10 15&#xff1a;467/10 17&#xff1a;02这里面一个命令带多个参数举例&#xff08;多个参数之间用空格隔开&#xff09;ls&#xff08;命令&#xff09; ~ / /etc/&#xff08;参数&#xff09; :这里就是同时查看主机的家目录&#xff0c;根目…

从零开始搭建深度学习大厦系列-2.卷积神经网络基础(5-9)

(1)本人挑战手写代码验证理论&#xff0c;获得一些AI工具无法提供的收获和思考&#xff0c;对于一些我无法回答的疑问请大家在评论区指教&#xff1b; (2)本系列文章有很多细节需要弄清楚&#xff0c;但是考虑到读者的吸收情况和文章篇幅限制&#xff0c;选择重点进行分享&…

【iOS设计模式】深入理解MVC架构 - 重构你的第一个App

目录 一、MVC模式概述 二、创建Model层 1. 新建Person模型类 2. 实现Person类 三、重构ViewController 1. 修改ViewController.h 2. 重构ViewController.m 四、MVC组件详解 1. Model&#xff08;Person类&#xff09; 2. View&#xff08;Storyboard中的UI元素&#x…

前端项目集成lint-staged

lint-staged (lint-staged) 这个插件可以只针对进入git暂存区中的代码进行代码格式检查与修复&#xff0c;极大提升效率&#xff0c;避免扫描整个项目文件&#xff0c;代码风格控制 eslint prettier stylelint 看这两篇文章 前端项目vue3项目集成eslint9.x跟prettier 前端项…

李宏毅genai笔记:模型编辑

0 和post training的区别直接用post training的方法是有挑战的&#xff0c;因为通常训练资料只有一笔而且之后不管问什么问题&#xff0c;都有可能只是这个答案了1 模型编辑的评估方案 reliability——同样的问题&#xff0c;需要是目标答案generalization——问题&#xff08;…

Oracle:union all和union区别

UNION ALL和UNION在Oracle中的主要区别体现在处理重复记录、性能及结果排序上&#xff1a;处理重复记录‌UNION‌&#xff1a;自动去除重复记录&#xff0c;确保最终结果唯一。‌UNION ALL‌&#xff1a;保留所有记录&#xff0c;包括完全重复的行。性能表现‌UNION‌&#xff…