从LED硬件控制流程认识Android架构!

news2024/9/20 8:37:58

0.Android架构图

一上来就是一张框架图,发明了框架图的天才真是个天才!

简单点评一下:

1.对于安卓应用开发来说:App层以下都是操作系统,反正我只关心Android Studio(其实是SDK)给我什么包,包里有哪些API,直接调库!

2.对于linux驱动开发者来说:设备节点以上都是应用层,我只要把xxx_open,xxx_write,xxx_read,xxx_ioctrl这些fops做好,给应用层设备节点就算完事!

3.对于安卓驱动开发来说:苦逼,不仅!要给app层写服务层接口、理解服务层蕴含的C/S模型,还要用JNI映射表来映射java接口和C语言接口,还要在hal层对设备节点的open/write/read/ioctrl封装!来写保密、复杂设备的驱动也就是camera、wifi等驱动!java、c++、c语言都要会你敢信??而且还有一堆编译脚本要处理,而且编译android系统还贼慢,而且!电脑内存根本不够用!everyone,全体起立给安卓驱动开发工程师致敬!

简单解释一下上面的框图:

1.APP层:没什么好说的,调库画界面,和我们嵌入式关系不大;

2.Framework&&Lib&&Runtime:这个是功能框图,大概点出了层次以及作用,中文名就是应用程序框架层(先简单理解,就是提供服务)、系统运行时库层(两种虚拟机,简单理解就是让java程序能跑在C/C++构建的环境上)、C库层(库更好理解嘛,一堆别人写好的东西等你去调!);但是对于我们具体要动手编程的还是有点太抽象了,现在我可以明确的讲,按 框架层(系统服务层+具体硬件服务层)---->>JNI层---->>HAL层 来划分“安卓应用--linux驱动"之间的这些东西,后面会比较清晰~暂且叫这坨东西叫安卓驱动好了。

3.linux kernel:这个就不用讲了吧,linux驱动呐,描述硬件信息的设备树,标准化的字符设备驱动、spi/i2c/input/v4l2等等各种驱动框架,最终就是要暴露出设备节点给到应用层,应用层(相对于Linux驱动来说安卓驱动也是应用层)都是操作设备节点来操作硬件,在安卓驱动开发暂且就不用关心linux驱动了,只需要知道open/write/read/ioctrl这些系统调用就够了。

1.以ledctrl为例子,介绍实际代码的层次结构

1.0 层次概况:

层次概述
APP层在Android Studio进行开发的人,调Java包的API,就是调API
框架层Java API的提供者,它提供了被称为“服务”的东西,
就是应用层你调某个API,我帮你做操作并给你返回值
思考这里需要思考一个问题,例如硬件只有一个,那如果多个应用程序都要控制它,怎么办?这就要提到“服务”这个东西,就是安卓系统做主,它去建立一个进程访问硬件(上服务),然后应用层的进程要控制硬件,都给系统服务(下服务)发请求,“系统服务”会建立队列让它们排队使用这个硬件服务(上服务)。这里重点是分清楚上服务下服务,上服务指的是LED服务、串口服务等等根据具体硬件的功能提供接口的进程,每个硬件都有一个服务下服务指的就是安卓系统建立的那个系统服务进程,它是帮忙运行维护LED服务/串口服务这些一系列服务的。
JNI层框架层的“服务”进程有些操作要控制硬件,我们知道驱动都是C语言写的,
JNI就是把做了个表,把java操作硬件的函数和C操作硬件的函数映射起来。
比如java层有个函数叫native_ioctrl(),C语言层有个函数叫ioctrl(),JNI的功能就是提供映射表,将native_ioctrl()和ioctrl()映射起来。
思考可能会有疑问,有JNI层了还要HAL层干嘛?JNI层不也可以用open/write/read/
ioctrl这些系统调用去通过设备节点来控制硬件嘛?其实多了HAL层最大的好处就是可以
把公司保密的代码写在HAL层,然后编译成库给到JNI层使用。原理如下:我们知道hal层是C语言写的,可以编译成so库文件,然后JNI层是C++写的,可以链接so库文件从而调用HAL层的函数。
HAL层把JNI层的xxx_open/xxx_w/xxx_r/xxx_ioctrl等函数给具体实现出来,这里就是真正的使用了open/w/r/ioctrl这些系统调用来操控硬件
总结再下层就是linux驱动了,可以看到安卓驱动确实是利用了linux驱动暴露出的设备节点,但是由于linux的系统调用是标准化的,所以我们也不需要太多的Linux驱动的知识也能做安卓驱动
linux驱动层

利用设备树描述硬件信息,利用字符设备驱动、SPI/I2C/INPUT/V4L2等驱动框架开发

linux驱动,最终暴露出设备节点/dev/xxx给到应用层调用

        下面就从下层到上层来介绍一下,linux驱动、安卓驱动、安卓应用层怎么从无到有,造出一个led控制函数。也就是说最终的效果是安卓应用层,有一个api可以控制开发板上的led灯。 

 1.1 linux驱动层的ledctrl

        最简单的字符设备驱动:

"

入:模块入口

号:获得主、次设备号

注:cdev_init,cdev_add把这个字符设备注册进系统,包括fops

节:创建类,创建设备节点/dev/led

硬:硬件相关的操作,比如led具体是哪个GPIO控制寄存器,一些寄存器的初始化和配置

操:实现fops,比如xxx_open,xxx_write,xxx_ioctrl,这里就是控制寄存器让led亮灭

"

linux驱动层的效果:

        生成了/dev/led这个设备节点,然后应用层可以通过ioctrl(fd,on/off,which)来控制这个led灯的亮灭。

1.2 HAL层的ledctrl

          这里就简单了,就是调用ioctrl来控制Led嘛,如下:

static int led_ctrl(struct led_device_t* dev, int which, int status)
{
	int ret = ioctl(fd, status, which);
	ALOGI("led_ctrl : %d, %d, %d", which, status, ret);//打印信息
	return ret;
}

        hal层对led的控制就是这样,但是hal层本身也有一些规范要遵守,其实就是硬件操作的一个组织规范,看下面就知道了:

hal层规范1:struct hw_device_t

把硬件操作都用结构体 struct led_device_t 来维护:

static struct led_device_t led_dev = {
	.common = {
		.tag   = HARDWARE_DEVICE_TAG,
		.close = led_close,
	},
	.led_open  = led_open,
	.led_ctrl  = led_ctrl,
};

这个结构体其实是我们自己定义的,只是对第一个成员有要求,看注释:

struct led_device_t {
    struct hw_device_t common;//第一个成员必须是struct hw_device_t,其他随意

	int (*led_open)(struct led_device_t* dev);
	int (*led_ctrl)(struct led_device_t* dev, int which, int status);
};

hal层规范2:struct hw_module_t

        要把上面的包含了硬件操作的结构体led_dev,给放到这个结构体的一个成员中,也就是放到hw_module_t->methods->open这个成员里面,其实都是一些固定的东西,照抄就行了:

先是hw_module_t->methods:

struct hw_module_t HAL_MODULE_INFO_SYM = {
	.tag = HARDWARE_MODULE_TAG,
    .id = "led",//这个id要记下来,是JNI层乃至框架层链接到HAL层的关键
    .methods = &led_module_methods,//这里,有个成员要包含硬件操作的结构体
};

然后是methods->open:

static struct hw_module_methods_t led_module_methods = {
    .open = led_device_open,
};
static int led_device_open(const struct hw_module_t* module, const char* id,
        struct hw_device_t** device)
{
	*device = &led_dev;//看,操作硬件的结构体在这里
	return 0;
}

这个规范不用过多纠结,抄就完事了

hal层的编译:

因为hal层是要编译出库给JNI层调用嘛,所以还是讲一讲hal层的编译:

hal_led.c和hal_led.h放在这里:

hardware/libhardware/include/hardware/led_hal.h
hardware/libhardware/modules/led/led_hal.c
hardware/libhardware/modules/led/Android.mk  //这个makefile文件去参考参考别的hal文件就行了

编译指令:

$ mmm hardware/libhardware/modules/led

这样hal_led.c和.h就会被编译成动态链接库,例如led.default.so,生成的位置是hardware/libhardware,这个库会被安卓自动包含,不用我们操心的。

hal层的效果:

        JNI层链接了led.default.so这个库,就可以调用hal层封装好的函数,led_ctrl去控制led灯的亮灭了。

1.3 JNI层的ledctrl

        JNI层的文件名是com_android_server_LedService.cpp,很明显是C++写的哈,也叫native层,叫法不一样无所谓。但是需要注意的是这个文件名,里面有LedService的字样,我们前面说到JNI层的上一层,其实就是框架层了,框架层的核心就是“服务”,即下服务(系统服务层)和上服务(具体硬件服务层),现在我们这个文件其实就是上服务的基础,之后会有一个LedService.java(具体硬件服务之Led服务)会来调用我们这个JNI文件的函数,并且会有一个SystemServer.java(系统服务层),来管理LedService.java(Led服务)。

        还是一样,先看看JNI层怎么调用hal层的函数来实现led的控制,再来介绍JNI层的一些比较固定的东西,也就是规范之类的。

JNI层调用流程:

        首先,引入hal_led.h的这个头文件:

#include <hardware/led_hal.h>

        然后在这里也造了一个自定义的操作硬件结构体,和hal层的一毛一样哈:

        下面注释里我标注了注意1和注意2的地方,其实就是对hal层规范的解析,通过hw_get_module这个接口就可以同步JNI层和HAL层的操作硬件结构体led_device_t的内容,使得JNI层可以去调用hal层已经实现了的函数。

static led_device_t* led_device;

jint ledOpen(JNIEnv *env, jobject cls)
{
	jint err;
    hw_module_t* module;
	hw_device_t* device;

	ALOGI("native ledOpen ...");

	/* 1. hw_get_module */
    err = hw_get_module("led", (hw_module_t const**)&module);//注意这里1
    if (err == 0) { 
		/* 2. get device : module->methods->open */
	    err = module->methods->open(module, NULL, &device);//注意这里2
	    if (err == 0) {
			/* 3. call led_open */
	        led_device = (led_device_t *)device;
			return led_device->led_open(led_device);
	    } else {
	        return -1;
    	}
    }
	
    return -1;	
} 

        接着就能愉快地调用led_ctrl来控制led的亮灭了!

jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
	ALOGI("native ledCtrl %d, %d", which, status);
	return led_device->led_ctrl(led_device, which, status);//调用hal层的led控制函数
}

        接下来是一些JNI的规范,同时捏,也说明了java程序怎么去调用c语言编写的函数

JNI规范1:java接口和c语言接口的映射表

static const JNINativeMethod methods[] = {
	{"native_ledOpen", "()I", (void *)ledOpen},
	{"native_ledClose", "()V", (void *)ledClose},
	{"native_ledCtrl", "(II)I", (void *)ledCtrl},
};

举一个例子哈,例如第三行:

native_ledCtrl这个就是java层实现的函数名

ledCtrl这个就是我们在JNI层实现的函数名

"(II)I",里面的II指明函数是有两个参数的,后面的I指明函数的返回类型是int型!

JNI规范2:注册这个JNI接口到安卓系统中

int register_android_server_LedService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/LedService",
            methods, NELEM(methods));
}

从这个com/android/server/LedService我们能获得很多信息:

把斜杠换成下划线,com_android_server_LedService.cpp就变成了我们JNI文件名

把com去掉,android/server/LedService.java就指明了框架层的上服务(led服务)文件所在路径,接下来我们要看框架层,首先要看的就是这个上服务。

JNI层的效果:

        JNI层用C++,构造了一个表格,将ledCtrl(JNI层)和native_ledCtrl(java层)映射了起来,JNI层的主要作用就是让java语言能够调用C程序编写的接口,接下来就都是用java写的了,也就是框架层(上服务和下服务),以及APP层。

1.4 框架层的ledctrl

        接下来要讲的调用关系虽然不复杂,但是文件比较多,所以先看看下面的框图:

        我们刚刚是讲到了JNI层,现在要讲的就是下服务,也就是系统服务层。

系统服务层(下服务):

        从小了来看,对于LED来说,JNI层主要就是要执行com_android_server_LedService.cpp文件里的函数register_android_server_LedService,从而建立java接口和c语言接口的映射。

        但是我们的板子,不止有LED,还有light,还有串口等外设,所以会有很多硬件的register_android_server_xxxService,这些映射表的注册操作,被集中到onload.cpp文件里的JNI_OnLoad函数中。所以从大了来说,JNI层的核心任务就是提供JNI_OnLoad函数,给上层调用。

        JNI的上层是系统服务层,它会执行这条语句:

//file :SystemServer.java

System.loadLibrary(“android_servers”)

        上面的android_servers实际上是一个C语言动态库,load这个库之后就会自动执行JNI_OnLoad函数,来注册所有硬件的java和c函数的映射表。

//file :onload.cpp

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");

    register_android_server_PowerManagerService(env);
    register_android_server_LightsService(env);
    register_android_server_VibratorService(env);
    register_android_server_LedService(env); //我们的led服务
    register_android_server_SystemServer(env);
    //... ...
}

具体硬件服务层(上服务):

        那么JNI层的ledctrl被映射到java层的native_ledCtrl函数后,是谁调用呢?答案就是java版的native_ledCtrl接口会被上服务(具体硬件服务)即LED服务调用(LedService.java),如下代码所示:

//file :LedService.java

public class LedService extends ILedService.Stub {
    private static final String TAG = "LedService";

	/* call native c function to access hardware */
	public int ledCtrl(int which, int status) throws android.os.RemoteException
	{
		return native_ledCtrl(which, status);//是不是很熟悉,就是java版的ledCtrl接口
                                    //封装native_ledCtrl来实现LedService->ledCtrl()
	}

	public LedService() {
		native_ledOpen();
	}

	public static native int native_ledOpen();
	public static native void native_ledClose();
	public static native int native_ledCtrl(int which, int status);
}

        LedService实际是继承于ILedService,这个I是interface即接口的意思,是结合了Binder通信机制的一种产物,这里先mark一下ILedService,等一会就讲这个。

上、下服务与APP层调用关系:

        这里值得重点说一下app层和框架层交互的一个流程,这样我们就能够理解系统服务层、具体硬件服务层、app层之间的一个关系。

①app层:getService("led"),系统服务层请求,我要用led辣。

②系统服务层:收到请求,查看现在led有没有别的app进程在用。没有就把ILedService类实例给到请求led服务的app进程。可以理解为Led服务是系统服务的小弟,系统服务安排Led服务(具体硬件服务层)去响应app进程的操作。

③app层:调用mService.led_ctrl() 控制led,实际就是调用了LedService->ledCtrl(),即Led服务在响应app进程的调用

ILedService.java和LedService.java

        ILedService.java可以理解为也是上服务(具体硬件服务)的一部分,但是不是由我们编写的,是可以生成的,我们前面说I的内涵其实就是结合Binder机制,生成的代码的过程其实就是在构建Binder机制相关的代码。简单理解即可,主要是掌握怎么生成ILedService.java,步骤如下:

1.新建一个文件ILedService.aidl,放在/frameworks/base/core/java/android/os目录里。

   只需要把需要的硬件操作接口声明出来就行。

//file :ILedService.aidl

package android.os;

/** {@hide} */
interface ILedService
{
	int ledCtrl(int which, int status);
}

2. 修改/frameworks/base的Android.mk,模仿别的把这个的编译项加进去:

core/java/android/os/ILedservice.aidl

3.编译

        执行mmm .就会生成ILedService.java,目录路径是在

        out/target/common/ob/JAV_LIBRARIES/framework intermediates/src/core/iava/android/os

ILedService.java里面都是生成的代码,拉到最下面会发现我们刚刚声明的led控制函数:

static final int TRANSACTION_ledCtrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int ledCtrl(int which, int status) throws android.os.RemoteException;
}

         ILedService.java中的ledCtrl函数,实际是在具体硬件服务层LedService.java中实现的,具体是通过调用java版的JNI接口来操控硬件。

框架层的效果:

1.实现多个app进程访问同一个硬件的解决机制(即系统服务+具体硬件服务,系统服务使用等待队列管理app进程使用具体硬件服务的请求)

2.实现了server和client的模型(就是app层进程是client,负责发请求,框架层作server负责响应请求)

1.5 APP层的ledctrl

        永远都不要忘记最初的目标,无论是linux驱动也好,安卓驱动也好,作为驱动工程师最终的目的都是为了让应用层能够控制led灯的亮灭,有时候我们觉得我们掌握的技术很复杂,仿佛在技术上有优越感,但实际在生活中,掌握技术本身往往不是目的,实现产品功能才是老板想要的,尽管最后一步通常是简单的,容易让人忽略前边驱动的努力和工作量......

        框架层的最顶部就是具体硬件服务层(上服务),它控制led的最顶层就是ILedService.java里面生成的接口ledCtrl,参考上面“上、下服务与APP层调用关系”,我们知道app层是这样控制led的:

APP层编程流程:

①引入包:import android.os

②app层:getService("led"),向系统服务层请求,我要用led辣。

③app层:框架层返回了ILedService类实例,现在我们可以调用ILedService.ledCtrl() 控制led了。

APP层的效果:

        led亮灭的控制命令,经过安卓框架(框架层---->>JNI层---->>HAL层)、linux驱动框架等多个层次,一层一层往下,最终改变了GPIO的寄存器,让led闪烁起来。

1.6 总结

        到这里整条控制链就打通了,这就是所谓的安卓驱动...看到这里,我们再回过头来看这个框图,是不是能透过表面的文字,看到更多深层次的逻辑呢~

(完~)

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

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

相关文章

字节-人工智能编辑代码方向面试-题目记录

问的都是自己简历里写的&#xff01;不会就不要写 简述一下几个排序算法 二分查找的时间复杂度&#xff08;是O&#xff08;log2n&#xff09;!!!&#xff09; find函数和count函数的时间复杂度都是O&#xff08;n&#xff09;&#xff0c;因为都是遍历整个数组来找的&#x…

Ubuntu Linux Server安装Kubernetes

本文主要描述在Ubuntu Linux Server操作系统中安装Kubernetes云原生对应的microk8s组件。 sudo snap install microk8s --classic 如上所示&#xff0c;在Ubuntu服务器中安装microk8s组件完成&#xff0c;对应的版本是microk8s v1.30版本 microk8s enable dashboard 如上所…

Java小白一文讲清Java中集合相关的知识点(二)

List List接口和常用方法 基本介绍 List接口是Collection接口的子接口 List集合类中的元素有序–即添加顺序和取出顺序一致、且可重复 public class Journey {SuppressWarnings({"all"})public static void main(String[] args) {List list new ArrayList();li…

基于Video-Retalking-Gradio的AI数字人

随着数字内容的普及,如何在视频中实现高精度的音频与唇形同步成为一个重要课题。传统方法通常需要大量的人工干预和调整,效果也往往不尽如人意。为了应对这一挑战,VideoReTalking 系统应运而生。由西安电子科技大学和腾讯AI实验室的研究人员联合开发,VideoReTalking 是一个…

【微信小程序】微信小程序如何使用 MobX 进行状态管理?

微信小程序官方在 2019 年针对小程序发布了 MobX 辅助绑定库&#xff0c;可以让我们在微信小程序中使用 Mobx 进行状态管理&#xff1a; mobx-miniprogram&#xff1a;相当于 MobX&#xff1b;mobx-miniprogram-bindings&#xff1a;针对小程序的 MobX 辅助绑定库&#xff0c;…

【全志H616】【开源】 ARM-Linux 智能分拣项目:阿里云、网络编程、图像识别

【全志H616】【开源】 ARM-Linux 智能分拣项目&#xff1a;阿里云、网络编程、图像识 文章目录 【全志H616】【开源】 ARM-Linux 智能分拣项目&#xff1a;阿里云、网络编程、图像识1、实现功能2、软件及所需环境3、逻辑流程图及简述3.1 完整逻辑流程图3.2 硬件接线3.3 功能简述…

【TomCat】安装部署

首先得进行Java的安装和部署java1.8对应tomcat9 TomCat下载Apache Tomcat - Apache Tomcat 10 Software Downloads

Vue(四) 组件、单文件组件、非单文件组件,重要的内置关系

文章目录 1. 组件2. 非单文件组件2.1 定义组件2.2 注册组件2.3 使用组件2.4 组件命名、标签等注意点2.5 组件嵌套2.6 VueComponent构造&#xff08;这部分看视频更易理解&#xff09;2.7 内置关系 3. 单文件组件 1. 组件 组件是实现局部功能代码和资源的集合 传统方式&#x…

unreal engine5.4.3动画重定向

UE5系列文章目录 文章目录 UE5系列文章目录前言 前言 ue5.4和ue3动画重定向之间存在差异&#xff0c;跟ue5.2差别更大一点&#xff0c;总之ue5.4越来越简化动画重定向&#xff0c;不想之前还需要制作RTG文件 这是ue5.3.2的制作动画重定向的界面 这是ue5.4.2的制作动画重定向…

华芯邦获AEC-Q车规级系列认证与AQG324认证的双重背书,碳化硅SiC-MOSFET半导体功率器件器件已在重点头部新能源汽车厂商模块验证中。

在获得AEC-Q车规级系列认证与AQG324认证的双重背书后&#xff0c;华芯邦的碳化硅SiC-MOSFET器件不仅巩固了其在新能源汽车领域的领先地位&#xff0c;更进一步加速了其在全球汽车供应链中的深度布局。这款车规级产品凭借其卓越的耐高温、低导通电阻及高开关频率等特性&#xff…

kubernetes里面那些事——————OpenEBS

OpenEBS存储 一&#xff0c;OpenEBS简介二&#xff0c;卷类型三&#xff0c;本地卷存储引擎类型四&#xff0c;复制卷存储引擎类型&#xff08;副本卷&#xff09;4.1 复制卷实现原理4.2 复制卷的优势 五&#xff0c;openebs存储引擎技术选型六&#xff0c;k8s中部署openebs服务…

项目延期,怎么有效调整计划,追赶进度

在项目管理过程中&#xff0c;项目延期是一个令人头疼但又无法完全避免的问题。无论是由内部因素还是外部因素导致&#xff0c;都会对项目的整体进度、成本和质量产生影响。 面对延期&#xff0c;关键在于如何迅速而有效地调整项目计划&#xff0c;以确保项目能够尽快回到正轨…

新版IDEA配置前进和后退、打开资源管理器等快捷按钮

新版IDEA&#xff0c;好像是IDEA2024版本开始就默认隐藏了工具条&#xff0c;这时一些很常用的快捷按钮&#xff0c;如前进、后退、打开资源管理器就无法使用。这里图文介绍&#xff0c;如何把这些配置出来。 具体操作如下&#xff1a; 1、选择 File / Settings(windows版)&am…

关于contextmenu-ui组件库

关于这个组件库把&#xff0c;主要用在个人博客制作中&#xff0c;而且由于作者很懒&#xff0c;已经一个多月没有更新了&#xff0c;甚至第二次更新都忘了修改md文件了。 这个组件库是使用vue3和TS来写的&#xff0c;关于引用&#xff0c;看这里 都有介绍的&#xff0c;直接…

计算机网络(八股文)

这里写目录标题 计算机网络一、网络分层模型1. TCP/IP四层架构和OSI七层架构⭐️⭐️⭐️⭐️⭐️2. 为什么网络要分层&#xff1f;⭐️⭐️⭐️3. 各层都有那些协议&#xff1f;⭐️⭐️⭐️⭐️ 二、HTTP【重要】1. http状态码&#xff1f;⭐️⭐️⭐️2. 从输入URL到页面展示…

边缘计算工业网关可以为工业企业生产提供哪些价值应用?天拓四方

在数字化、网络化、智能化高度融合的今天&#xff0c;工业领域正迎来一场深刻的变革。边缘计算工业网关&#xff0c;作为这场变革中的关键角色&#xff0c;以其强大的数据处理能力、高效的通信效率和灵活的部署方式&#xff0c;为智能制造注入了新的活力。本文将结合一个实际应…

【安卓13】解决HDMI OUT和耳机等设备接入时会解除静音问题

安卓原生定义了部分外部设备接入时是否静音&#xff0c;比如耳机、有线扬声器、HDMIOUT设备等&#xff0c;这些设备接入时&#xff0c;安卓会设置AudioSystem.STREAM_MUSIC为非静音状态 从代码里可以看出&#xff0c;当一个newDevice 接入时&#xff0c;会携带一个deviceID&am…

Java基于微信小程序的超市购物管理系统

1 简介 Java基于微信小程序的超市购物管理系统&#xff0c;此超市购物系统利用当下成熟完善的springboot框架&#xff0c;使用跨平台的可开发大型商业网站的Java语言&#xff0c;以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了收货地址管理、购物车管理、…

Win11 / Win10 系统极化工具,降低游戏延迟效果明显

Win11 / Win10 系统优化工具,降低游戏延迟效果明显 Windows 系统优化就是精简系统一些功能组件、对一些系统功能进行设置等&#xff0c;这样可以减少不必要的硬件资源占用。 全面的系统优化功能外&#xff0c;据不少网友表示通过优化后 CS GO 游戏降低输入延迟效果明显。 免费…

领夹麦克风哪个牌子音质好?西圣、博雅、枫笛领夹麦克风对比

当今的直播、短视频已经深深的融入到了我们的生活当中&#xff0c;很多小伙伴会通过拍摄短视频、Vlog来分享自己生活精彩的瞬间。不过录制视频时&#xff0c;如果单纯靠手机拾音会发现&#xff0c;音频效果是极差的&#xff0c;特别距离手机越远效果会越明显&#xff0c;会出现…