Android 12 Bluetooth源码分析蓝牙配对
本文主要是列出一些蓝牙配对重要的类和方法/函数,遇到相关问题时方便查找添加log排查。
蓝牙扫描列表页面:packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java点击其中一个设备会调用:onPreferenceTreeClick()
@Overridepublic boolean onPreferenceTreeClick(Preference preference) {if (KEY_BT_SCAN.equals(preference.getKey())) {startScanning();return true;}if (preference instanceof BluetoothDevicePreference) {BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;CachedBluetoothDevice device = btPreference.getCachedDevice();mSelectedDevice = device.getDevice();mSelectedList.add(mSelectedDevice);//配对onDevicePreferenceClick(btPreference);return true;}return super.onPreferenceTreeClick(preference);}
接着调用 packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
void onClicked() {Context context = getContext();int bondState = mCachedDevice.getBondState();final MetricsFeatureProvider metricsFeatureProvider =FeatureFactory.getFactory(context).getMetricsFeatureProvider();if (mCachedDevice.isConnected()) {metricsFeatureProvider.action(context,SettingsEnums.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);askDisconnect();} else if (bondState == BluetoothDevice.BOND_BONDED) {metricsFeatureProvider.action(context,SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT);mCachedDevice.connect();} else if (bondState == BluetoothDevice.BOND_NONE) {metricsFeatureProvider.action(context,SettingsEnums.ACTION_SETTINGS_BLUETOOTH_PAIR);if (!mCachedDevice.hasHumanReadableName()) {metricsFeatureProvider.action(context,SettingsEnums.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);}pair();//配对}}
继续调用
public boolean startPairing() {// Pairing is unreliable while scanning, so cancel discoveryif (mLocalAdapter.isDiscovering()) {mLocalAdapter.cancelDiscovery();}//创建配对if (!mDevice.createBond()) {return false;}return true;}
一直往下会到BluetoothDevice.java,在里面调用了IBuletooth.aidl
frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,@Nullable OobData remoteP256Data) {final IBluetooth service = sService;if (service == null) {Log.w(TAG, "BT not enabled, createBondOutOfBand failed");return false;}try {return service.createBond(this, transport, remoteP192Data, remoteP256Data, mAttributionSource);} catch (RemoteException e) {Log.e(TAG, "", e);}return false;}
在AdapterService.java里实现了IBluetooth.Stub
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
@VisibleForTestingpublic static class AdapterServiceBinder extends IBluetooth.Stub {private AdapterService mService;AdapterServiceBinder(AdapterService svc) {mService = svc;mService.invalidateBluetoothGetStateCache();BluetoothAdapter.getDefaultAdapter().disableBluetoothGetStateCache();}.....省略@Overridepublic boolean createBond(BluetoothDevice device, int transport, OobData remoteP192Data,OobData remoteP256Data, AttributionSource attributionSource) {Attributable.setAttributionSource(device, attributionSource);AdapterService service = getService();if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG, "createBond")|| !Utils.checkConnectPermissionForDataDelivery(service, attributionSource, "AdapterService createBond")) {return false;}// This conditional is required to satisfy permission dependencies// since createBond calls createBondOutOfBand with null value passed as data.// BluetoothDevice#createBond requires BLUETOOTH_ADMIN only.service.enforceBluetoothPrivilegedPermissionIfNeeded(remoteP192Data, remoteP256Data);//进入createBondreturn service.createBond(device, transport, remoteP192Data, remoteP256Data,attributionSource.getPackageName());}}
boolean createBond(BluetoothDevice device, int transport, OobData remoteP192Data,OobData remoteP256Data, String callingPackage) {DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {return false;}if (!isPackageNameAccurate(this, callingPackage, Binder.getCallingUid())) {return false;}CallerInfo createBondCaller = new CallerInfo();createBondCaller.callerPackageName = callingPackage;createBondCaller.user = UserHandle.of(UserHandle.getCallingUserId());mBondAttemptCallerInfo.put(device.getAddress(), createBondCaller);mRemoteDevices.setBondingInitiatedLocally(Utils.getByteAddress(device));// Pairing is unreliable while scanning, so cancel discovery// Note, remove this when native stack improvescancelDiscoveryNative();Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);msg.obj = device;msg.arg1 = transport;Bundle remoteOobDatasBundle = new Bundle();boolean setData = false;if (remoteP192Data != null) {remoteOobDatasBundle.putParcelable(BondStateMachine.OOBDATAP192, remoteP192Data);setData = true;}if (remoteP256Data != null) {remoteOobDatasBundle.putParcelable(BondStateMachine.OOBDATAP256, remoteP256Data);setData = true;}if (setData) {msg.setData(remoteOobDatasBundle);}//发送配对messagemBondStateMachine.sendMessage(msg);return true;}
接着进入packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java
private boolean createBond(BluetoothDevice dev, int transport, OobData remoteP192Data,OobData remoteP256Data, boolean transition) {if (dev.getBondState() == BluetoothDevice.BOND_NONE) {infoLog("Bond address is:" + dev);byte[] addr = Utils.getBytesFromAddress(dev.getAddress());boolean result;// If we have some dataif (remoteP192Data != null || remoteP256Data != null) {result = mAdapterService.createBondOutOfBandNative(addr, transport,remoteP192Data, remoteP256Data);} else {//调用了native的代码result = mAdapterService.createBondNative(addr, transport);}BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED,mAdapterService.obfuscateAddress(dev), transport, dev.getType(),BluetoothDevice.BOND_BONDING,remoteP192Data == null && remoteP256Data == null? BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN: BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED,BluetoothProtoEnums.UNBOND_REASON_UNKNOWN);if (!result) {BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED,mAdapterService.obfuscateAddress(dev), transport, dev.getType(),BluetoothDevice.BOND_NONE, BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN,BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS);// Using UNBOND_REASON_REMOVED for legacy reasonsendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);return false;} else if (transition) {transitionTo(mPendingCommandState);}return true;}return false;}
这里调到了JNI层的代码,进入packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address,jint transport) {ALOGV("%s", __func__);if (!sBluetoothInterface) return JNI_FALSE;jbyte* addr = env->GetByteArrayElements(address, NULL);if (addr == NULL) {jniThrowIOException(env, EINVAL);return JNI_FALSE;}//调用hal层的配对函数int ret = sBluetoothInterface->create_bond((RawAddress*)addr, transport);env->ReleaseByteArrayElements(address, addr, 0);return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
调用到了hal层的代码,在蓝牙协议栈里 system/bt/btif/src/bluetooth.cc
static int create_bond(const RawAddress* bd_addr, int transport) {if (!interface_ready()) return BT_STATUS_NOT_READY;if (btif_dm_pairing_is_busy()) return BT_STATUS_BUSY;//调用了btif_dm_create_bonddo_in_main_thread(FROM_HERE,base::BindOnce(btif_dm_create_bond, *bd_addr, transport));return BT_STATUS_SUCCESS;
}
调用到了system/bt/btif/src/btif_dm.cc
/********************************************************************************* Function btif_dm_create_bond** Description Initiate bonding with the specified device*******************************************************************************/
void btif_dm_create_bond(const RawAddress bd_addr, int transport) {BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,bd_addr.ToString().c_str(), transport);btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND,pairing_cb.state);pairing_cb.timeout_retries = NUM_TIMEOUT_RETRIES;btif_dm_cb_create_bond(bd_addr, transport);
}
static void btif_dm_cb_create_bond(const RawAddress bd_addr,tBT_TRANSPORT transport) {bool is_hid = check_cod(&bd_addr, COD_HID_POINTING);bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);int device_type = 0;tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC;std::string addrstr = bd_addr.ToString();const char* bdstr = addrstr.c_str();if (transport == BT_TRANSPORT_LE) {if (!btif_config_get_int(bdstr, "DevType", &device_type)) {btif_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE);}if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) !=BT_STATUS_SUCCESS) {// Try to read address type. OOB pairing might have set it earlier, but// didn't store it, it defaults to BLE_ADDR_PUBLICuint8_t tmp_dev_type;tBLE_ADDR_TYPE tmp_addr_type = BLE_ADDR_PUBLIC;BTM_ReadDevInfo(bd_addr, &tmp_dev_type, &tmp_addr_type);addr_type = tmp_addr_type;btif_storage_set_remote_addr_type(&bd_addr, addr_type);}}if ((btif_config_get_int(bdstr, "DevType", &device_type) &&(btif_storage_get_remote_addr_type(&bd_addr, &addr_type) ==BT_STATUS_SUCCESS) &&(device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) ||(transport == BT_TRANSPORT_LE)) {BTA_DmAddBleDevice(bd_addr, addr_type, device_type);}if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) {bt_status_t status;status = (bt_status_t)btif_hh_connect(&bd_addr);if (status != BT_STATUS_SUCCESS)bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);} else {//执行到这个方法BTA_DmBond(bd_addr, addr_type, transport, device_type);}/* Track originator of bond creation */pairing_cb.is_local_initiated = true;
}
这个函数BTA_DmBond里调用到了system/bt/bta/dm/bta_dm_act.cc
/** Bonds with peer device */
void bta_dm_bond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport, int device_type) {tBTA_DM_SEC sec_event;char* p_name;//在BTM_SecBond函数发送配对信息,蓝牙地址、数据、命令等信息tBTM_STATUS status =(bluetooth::shim::is_gd_security_enabled())? bluetooth::shim::BTM_SecBond(bd_addr, addr_type, transport,device_type): BTM_SecBond(bd_addr, addr_type, transport, device_type, 0, NULL);if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) {memset(&sec_event, 0, sizeof(tBTA_DM_SEC));sec_event.auth_cmpl.bd_addr = bd_addr;p_name = (bluetooth::shim::is_gd_security_enabled())? bluetooth::shim::BTM_SecReadDevName(bd_addr): BTM_SecReadDevName(bd_addr);if (p_name != NULL) {memcpy(sec_event.auth_cmpl.bd_name, p_name, BD_NAME_LEN);sec_event.auth_cmpl.bd_name[BD_NAME_LEN] = 0;}/* taken care of by memset [above]sec_event.auth_cmpl.key_present = false;sec_event.auth_cmpl.success = false;*/sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;if (status == BTM_SUCCESS) {sec_event.auth_cmpl.success = true;} else {/* delete this device entry from Sec Dev DB */bta_dm_remove_sec_dev_entry(bd_addr);}bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);}
}
来到system/bt/stack/btm/btm_sec.cc,最终在这里发送命令给HCI与硬件打交道
/********************************************************************************* Function BTM_SecBond** Description This function is called to perform bonding with peer device.* If the connection is already up, but not secure, pairing* is attempted. If already paired BTM_SUCCESS is returned.** Parameters: bd_addr - Address of the device to bond* transport - doing SSP over BR/EDR or SMP over LE* pin_len - length in bytes of the PIN Code* p_pin - pointer to array with the PIN Code** Note: After 2.1 parameters are not used and preserved here not to change API******************************************************************************/
tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type,tBT_TRANSPORT transport, int device_type,uint8_t pin_len, uint8_t* p_pin) {if (bluetooth::shim::is_gd_shim_enabled()) {return bluetooth::shim::BTM_SecBond(bd_addr, addr_type, transport,device_type);}if (transport == BT_TRANSPORT_INVALID)transport = BTM_UseLeLink(bd_addr) ? BT_TRANSPORT_LE : BT_TRANSPORT_BR_EDR;tBT_DEVICE_TYPE dev_type;BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);/* LE device, do SMP pairing */if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) ||(transport == BT_TRANSPORT_BR_EDR &&(dev_type & BT_DEVICE_TYPE_BREDR) == 0)) {return BTM_ILLEGAL_ACTION;}//执行btm_sec_bond_by_transport函数return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin);
}/********************************************************************************* Function btm_sec_bond_by_transport** Description this is the bond function that will start either SSP or SMP.** Parameters: bd_addr - Address of the device to bond* pin_len - length in bytes of the PIN Code* p_pin - pointer to array with the PIN Code** Note: After 2.1 parameters are not used and preserved here not to change API******************************************************************************/
tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,tBT_TRANSPORT transport, uint8_t pin_len,uint8_t* p_pin) {//....代码太多,最底层就是发送控制命令if (!controller_get_interface()->supports_simple_pairing()) {/* The special case when we authenticate keyboard. Set pin type to fixed *//* It would be probably better to do it from the application, but it is *//* complicated */if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==BTM_COD_MAJOR_PERIPHERAL) &&(p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) &&(btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) {btm_cb.pin_type_changed = true;//通过HCI向底层发送命令btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED);}}return status;
}
到这里就结束了,后面就是控制硬件发起配对操作。
相关文章:
Android 12 Bluetooth源码分析蓝牙配对
本文主要是列出一些蓝牙配对重要的类和方法/函数,遇到相关问题时方便查找添加log排查。 蓝牙扫描列表页面:packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java点击其中一个设备会调用:onPrefere…...
Python异步编程并发执行爬虫任务,用回调函数解析响应
一、问题:当发送API请求,读写数据库任务较重时,程序运行效率急剧下降。 异步技术是Python编程中对提升性能非常重要的一项技术。在实际应用,经常面临对外发送网络请求,调用外部接口,或者不断更新数据库或文…...
React组件化开发
1.组件的定义方式 函数组件Functional Component类组件Class Component 2.类组件 export class Profile extends Component {render() {console.log(this.context);return (<div>Profile</div>)} } 组件的名称是大写字符开头(无论类组件还是函数组件…...
LuatOS-SOC接口文档(air780E)--crypto - 加解密和hash函数
crypto.md5(str) 计算md5值 参数 传入值类型 解释 string 需要计算的字符串 返回值 返回值类型 解释 string 计算得出的md5值的hex字符串 例子 -- 计算字符串"abc"的md5 log.info("md5", crypto.md5("abc"))crypto.hmac_md5(str, k…...
自动化测试的定位及一些思考
大家对自动化的理解,首先是想到Web UI自动化,这就为什么我一说自动化,公司一般就会有很多人反对,因为自动化的成本实在太高了,其实自动化是分为三个层面的(UI层自动化、接口自动化、单元测试)&a…...
展会动态 | 迪捷软件邀您参加2023世界智能网联汽车大会
*9月18日之前注册的观众免收门票费* 由北京市人民政府、工业和信息化部、公安部、交通运输部和中国科学技术协会联合主办的2023世界智能网联汽车大会将于9月21日-24日在北京中国国际展览中心(顺义馆)举行。 论坛背景 本届展会以“聚智成势 协同向新——…...
jenkins自动化部署springboot、gitee项目
服务器需要安装jdk11、maven、gitee 1. jenkins安装 # yum源 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo # 公钥 sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key # 安装 yum install jenkins如果yum源报…...
Python环境配置及基础用法Pycharm库安装与背景设置及避免Venv文件夹
目录 一、Python环境部署及简单使用 1、Python下载安装 2、环境变量配置 3、检查是否安装成功 4、Python的两种模式(编辑模式&交互模式) 二、Pycharm库安装与背景设置 1、Python库安装 2、Pycharm自定义背景 三、如何避免Venv文件夹 一、P…...
PHP常见的SQL防注入方法
利用Mysqli和PDO 产生原因主要就是一些数据没有经过严格的验证,然后直接拼接 SQL 去查询。导致产生漏洞,比如: $id $_GET[id]; $sql "SELECT name FROM users WHERE id $id";因为没有对 $_GET[‘id’] 做数据类型验证…...
分布式和中间件等
raft协议 paxos算法ddos 如何避免?怎么预防?怎么发现?利用了TCP什么特点?怎么改进TCP可以预防?服务端处理不了的请求怎么办?连接数最大值需要设置吗?怎么设置? Thrift RPC过程是什么样子的?异构系统怎么完成通信?跟http相比什么优缺点?了解grpc吗?kafka topic part…...
通过http发送post请求的三种Content-Type分析
通过okhttp向服务端发起post网络请求,可以通过Content-Type设置发送请求数据的格式。 常用到的三种: 1)application/x-www-form-urlencoded; charsetutf-8 2)application/json; charsetutf-8 3)multipart/form-dat…...
Vue中的自定义指令详解
文章目录 自定义指令自定义指令-指令的值(给自定义指令传参数) 自定义指令 自定义指令:自己定义的指令,可以封装一些dom 操作,扩展额外功能(自动聚焦,自动加载,懒加载等复杂的指令封…...
[管理与领导-100]:管理者到底是什么?调度器?路由器?交换机?监控器?
目录 前言: 二层交换机 三层路由器 监视器(Monitor) 调度器 前言: 人在群体中,有点像设备在网络中,管理者到底承担什么的功能? 二层交换机 交换机是计算机网络中,用于连接多台…...
保研CS/软件工程/通信问题汇总
机器学习 1.TP、TN、FP、FN、F1 2.机器学习和深度学习的区别和联系 模型复杂性:深度学习是机器学习的一个子领域,其主要区别在于使用深层的神经网络模型。深度学习模型通常包含多个隐层,可以学习更加复杂的特征表示,因此在某些任…...
word、excel、ppt转为PDF
相关引用对象在代码里了 相关依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.0.1</version></dependency> <dependency><groupId>org.apache.poi</group…...
2023华为杯D题——基于Kaya模型的碳排放达峰实证研究
一、前言 化石能源是推动现代经济增长的重要生产要素,经济生产活动与碳排放活动密切相关。充分认识经济增长与碳排放之间的关系对转变生产方式,确定碳达峰、碳中和路径极为必要。本研究在对经济增长与碳排放关系现有研究梳理的基础上,系统地分…...
有哪些好用的上网行为管理软件?(上网行为管理软件功能好的软件推荐)
随着互联网的快速发展,企业的信息化管理和员工的上网行为已经成为企业信息化建设的重要组成部分。上网行为管理软件作为一种新型的管理工具,可以帮助企业实现对员工上网行为的管控和优化,进而提高企业的工作效率和网络安全。本文将对多款市场…...
npm install报错 code:128
报的错误: npm ERR! code 128 npm ERR! An unknown git error occurred npm ERR! command git --no-replace-objects ls-remote ssh://gitgithub.com/nhn/raphael.git npm ERR! gitgithub.com: Permission denied (publickey). npm ERR! fatal: Could not read from remote re…...
爬虫 — Scrapy 框架(一)
目录 一、介绍1、同步与异步2、阻塞与非阻塞 二、工作流程三、项目结构1、安装2、项目文件夹2.1、方式一2.2、方式二 3、创建项目4、项目文件组成4.1、piders/__ init __.py4.2、spiders/demo.py4.3、__ init __.py4.4、items.py4.5、middlewares.py4.6、pipelines.py4.7、sett…...
Python编程语言学习笔记
目录 1 书写格式1.1 程序框架格式1.1 注释1.2 保留字 2 数据2.1 整数类型2.2 浮点类型2.3 复数类型2.4 数值运算符2.5 数值运函数2.6 数值类型转换函数2.7 math 库2.8 字符串2.8.1 字符串的表示2.8.2 字符串的区间访问2.8.3 字符串操作符2.8.4 字符串操作函数 2.9 字符串类型的…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...
