Android 蓝牙服务启动
蓝牙是Android设备中非常常见的一个feature,设备厂家可以用BT来做RC、连接音箱、设备本身做Sink等常见功能。如果一些设备不需要BT功能,Android也可以通过配置来disable此模块,方便厂家为自己的设备做客制化。APP操作设备的蓝牙功能,一般是通过标准API-BluetoothAdapter实现,这里我们先不关心具体API的实现flow,先来了解Bluetooth framework的启动过程,这样可以为后面介绍一些BT 常见flow,做铺垫。
我们都知道Android的主要系统服务都是在system_server中启动的,BT也不例外:
// Skip Bluetooth if we have an emulator kernel// TODO: Use a more reliable check to see if this product should// support Bluetooth - see bug 988521if (isEmulator) {Slog.i(TAG, "No Bluetooth Service (emulator)");} else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {Slog.i(TAG, "No Bluetooth Service (factory test)");} else if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");} else {traceBeginAndSlog("StartBluetoothService");mSystemServiceManager.startService(BluetoothService.class);traceEnd();}
在SystemServer中,BT framework启动的起点以服务启动的形式表现,这在Android中非常常见;我们可以通过配置feature xml文件来表明系统当前是否支持蓝牙,在一些没有蓝牙模组的设备上,就可以去掉hardware feature bluetooth的声明,这样设备启动时就不会启动BT framework相关的模块了:
@frameworks/base/services/core/java/com/android/server/BluetoothManagerService.javaclass BluetoothService extends SystemService {private BluetoothManagerService mBluetoothManagerService;public BluetoothService(Context context) {super(context);//创建BluetoothManagerService的实例mBluetoothManagerService = new BluetoothManagerService(context);}........@Overridepublic void onBootPhase(int phase) {if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {//将BluetoothManagerService实例发布到系统中,这样就可以Context根据BT的service名去获取它的Binder代理操作API了publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,mBluetoothManagerService);} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {//此时系统应该启动到一个比较晚的阶段了,可以使用AMS去Bind需要的Service了mBluetoothManagerService.handleOnBootPhase();}}........
}
BluetoothManagerService构造过程中,跟开机flow中自动enable bt相关的主要是mEnableExternal这个flag:
BluetoothManagerService(Context context) {mHandler = new BluetoothHandler(IoThread.get().getLooper());//创建内部处理msg的handlermContext = context;mPermissionReviewRequired = context.getResources().getBoolean(com.android.internal.R.bool.config_permissionReviewRequired);mCrashes = 0;mBluetooth = null;mBluetoothBinder = null;mBluetoothGatt = null;mBinding = false;mUnbinding = false;mEnable = false;mState = BluetoothAdapter.STATE_OFF;mQuietEnableExternal = false;//false表示此次enable需要触发auto connect device和保存状态,BluetoothAdapter::enableNoAutoConnect()可以改变此状态mEnableExternal = false;mAddress = null;mName = null;mErrorRecoveryRetryCounter = 0;mContentResolver = context.getContentResolver();// Observe BLE scan only mode settings change.registerForBleScanModeChange();mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();IntentFilter filter = new IntentFilter();filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);//监听App通过接口修改BT local name的广播(对端设备搜索你显示的字符串)filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);//监听bt地址改变的广播filter.addAction(Intent.ACTION_SETTING_RESTORED);//监听当前设置需要restore回上一次设置的广播,此时需要重新保存name和addr为上一次的信息filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);mContext.registerReceiver(mReceiver, filter);loadStoredNameAndAddress();//从数据库中加载本机Bt的local name和addressif (isBluetoothPersistedStateOn()) {//查看上一次关机时,BT是否为enable状态;如果是,这次开机也需要enable BTif (DBG) {Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");}mEnableExternal = true;//表明开机过程中需要enable BT}String airplaneModeRadios =Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);if (airplaneModeRadios == null || airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) {mContentResolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,mAirplaneModeObserver);//监听Airplane mode改变,相应改变BT状态;这在TV plateform上基本没用}int systemUiUid = -1;try {// Check if device is configured with no home screen, which implies no SystemUI.boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen);if (!noHome) {systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY,UserHandle.USER_SYSTEM);}Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid));} catch (PackageManager.NameNotFoundException e) {// Some platforms, such as wearables do not have a system ui.Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);}mSystemUiUid = systemUiUid;}
它为true,表明上一次关机前BT就是enable的,这次开机也需要enable;其他的主要是一些广播、数据库字段的初始化动作。
回到前面BluetoothService启动的过程,当系统启动到合适的阶段,就回调SystemService相应的函数,当phase为PHASE_ACTIVITY_MANAGER_READY时,调用到BMS::handleOnBootPhase(),进行BT framework的启动:
/*** Send enable message and set adapter name and address. Called when the boot phase becomes* PHASE_SYSTEM_SERVICES_READY.*/public void handleOnBootPhase() {if (DBG) {Slog.d(TAG, "Bluetooth boot completed");}UserManagerInternal userManagerInternal =LocalServices.getService(UserManagerInternal.class);userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);final boolean isBluetoothDisallowed = isBluetoothDisallowed();if (isBluetoothDisallowed) {return;}if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {if (DBG) {Slog.d(TAG, "Auto-enabling Bluetooth.");}sendEnableMsg(mQuietEnableExternal/*默认false,表示此次enable需要自动连接device/保存enable状态*/,BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,mContext.getPackageName());} else if (!isNameAndAddressSet()) {if (DBG) {Slog.d(TAG, "Getting adapter name and address");}Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);mHandler.sendMessage(getMsg);}}
handleOnBootPhase()的内容比较单一,根据一些flag判断是否需要enable BT;而enable蓝牙这里是通过触发send msg实现:
private void sendEnableMsg(boolean quietMode, int reason, String packageName) {//发送MESSAGE_ENABLE msgmHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));addActiveLog(reason, packageName, true);mLastEnabledTime = SystemClock.elapsedRealtime();}case MESSAGE_ENABLE:if (DBG) {Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);}mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);mEnable = true;// Use service interface to get the exact statetry {mBluetoothLock.readLock().lock();if (mBluetooth != null) { //开机第一次enable,值为nullint state = mBluetooth.getState();if (state == BluetoothAdapter.STATE_BLE_ON) {//大部分设备一般都不是ble only modeSlog.w(TAG, "BT Enable in BLE_ON State, going to ON");mBluetooth.onLeServiceUp();persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);break;}}} catch (RemoteException e) {Slog.e(TAG, "", e);} finally {mBluetoothLock.readLock().unlock();}mQuietEnable = (msg.arg1 == 1);//此时为falseif (mBluetooth == null) {//mBluetooth是后面绑定Bt apk中AdapterService时拿到的Binder代理对象;用以把操作bypass到BT核心框架中handleEnable(mQuietEnable);} else {//如果mBluetooth不是null,说明之前已经启动过了;此时是Restart flow,以MESSAGE_RESTART_BLUETOOTH_SERVICE触发//// We need to wait until transitioned to STATE_OFF and// the previous Bluetooth process has exited. The// waiting period has three components:// (a) Wait until the local state is STATE_OFF. This// is accomplished by "waitForOnOff(false, true)".// (b) Wait until the STATE_OFF state is updated to// all components.// (c) Wait until the Bluetooth process exits, and// ActivityManager detects it.// The waiting for (b) and (c) is accomplished by// delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE// message. On slower devices, that delay needs to be// on the order of (2 * SERVICE_RESTART_TIME_MS).//waitForOnOff(false, true);Message restartMsg =mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);}break;
handleEnable()去Bind AdapterService拿到它的Binder句柄,bindServiceAsUser如果服务端没有启动,就会去启动服务端:
private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
......private class BluetoothServiceConnection implements ServiceConnection {public void onServiceConnected(ComponentName componentName, IBinder service) {String name = componentName.getClassName();if (DBG) {Slog.d(TAG, "BluetoothServiceConnection: " + name);}Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);if (name.equals("com.android.bluetooth.btservice.AdapterService")) {msg.arg1 = SERVICE_IBLUETOOTH;} else if (name.equals("com.android.bluetooth.gatt.GattService")) {msg.arg1 = SERVICE_IBLUETOOTHGATT;} else {Slog.e(TAG, "Unknown service connected: " + name);return;}msg.obj = service;mHandler.sendMessage(msg);}public void onServiceDisconnected(ComponentName componentName) {// Called if we unexpectedly disconnect.String name = componentName.getClassName();if (DBG) {Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);}Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);if (name.equals("com.android.bluetooth.btservice.AdapterService")) {msg.arg1 = SERVICE_IBLUETOOTH;} else if (name.equals("com.android.bluetooth.gatt.GattService")) {msg.arg1 = SERVICE_IBLUETOOTHGATT;} else {Slog.e(TAG, "Unknown service disconnected: " + name);return;}mHandler.sendMessage(msg);}}
......boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);intent.setComponent(comp);if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {Slog.e(TAG, "Fail to bind to: " + intent);return false;}return true;}
IBluetooth.class对于的Service声明在Bluetooth apk的manifest xml中,AdapterService是真正的服务端:
@packages/apps/Bluetooth/AndroidManifest.xml<application android:name=".btservice.AdapterApp"android:icon="@mipmap/bt_share"android:persistent="false"android:label="@string/app_name"android:supportsRtl="true"android:usesCleartextTraffic="false"android:directBootAware="trueandroid:defaultToDeviceProtectedStorage="true"<serviceandroid:process="@string/process"android:name = ".btservice.AdapterService"><intent-filter><action android:name="android.bluetooth.IBluetooth" /></intent-filter></service>
@packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
public class AdapterService extends Service {private static final String TAG = "BluetoothAdapterService";public void onCreate() {super.onCreate();debugLog("onCreate()");
去Bind AdapterService服务,并拿到它的Binder句柄,用以后面操作它的接口。AdapterService的初始化下篇再讲,现在先回到BMS binder成功之后发送MESSAGE_BLUETOOTH_SERVICE_CONNECTED(arg1:SERVICE_IBLUETOOTH)的处理:
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {if (DBG) {Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);}IBinder service = (IBinder) msg.obj; //保存Service的onBinder()句柄try {mBluetoothLock.writeLock().lock();if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {mBluetoothGatt =IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));continueFromBleOnState();break;} // else must be SERVICE_IBLUETOOTH//Remove timeoutmHandler.removeMessages(MESSAGE_TIMEOUT_BIND);mBinding = false;mBluetoothBinder = service;mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));//再转成IBluetooth对象if (!isNameAndAddressSet()) {Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);mHandler.sendMessage(getMsg);if (mGetNameAddressOnly) {return;}}//Register callback objecttry {mBluetooth.registerCallback(mBluetoothCallback);//mBluetoothCallback用来监听BT的enable状态,如state_on/state_off的状态变化} catch (RemoteException re) {Slog.e(TAG, "Unable to register BluetoothCallback", re);}//Inform BluetoothAdapter instances that service is upsendBluetoothServiceUpCallback();//Do enable requesttry {if (!mQuietEnable) {if (!mBluetooth.enable()) {//Service bind成功之后,call AdpaterService的enable()接口;做一些初始化动作,并向stack发送enable命令启动蓝牙Slog.e(TAG, "IBluetooth.enable() returned false");}} else {if (!mBluetooth.enableNoAutoConnect()) {Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");}}} catch (RemoteException e) {Slog.e(TAG, "Unable to call enable()", e);}} finally {mBluetoothLock.writeLock().unlock();}if (!mEnable) {waitForOnOff(true, false);handleDisable();waitForOnOff(false, false);}break;}
主要操作:
拿到bind服务的onBinder()句柄,并转成IBluetooth类型
通过IBluetooth类型的obj,调用enable()接口,将flow转到AdapterService中,做一些初始化、并向stack下enable bt的cmd
也要注意到,如果BMS中和AdapterService的连接断掉了,最终会通过MESSAGE_RESTART_BLUETOOTH_SERVICE msg去重新bind它;这在场景可能是由于模组异常导致Bluetooth apk crash(会产生tombstone),与AdapterService的bind连接断掉;这里触发Restart,会导致重走一遍介绍的enable BT流程。
到此,enable BT的flow就从BluetoothManagerService转到AdapterService中了;实际上,通过BluetoothAdapter下来的大部分API调用最终都是call到AdapterService,再通过它下cmd给stack。
AdapterService是蓝牙框架中一个非常重要的服务,它的启动和初始化部分,我们下篇再单独介绍。
PS:
可以看到BT启动过程中有两个常见到的flag:
mEnable:它主要是用来标记系统运行时,蓝牙状态的变化,它有些时候时跟mEnableExternal值一致的。但如果蓝牙的状态是因为某些原因,如stack崩溃,导致蓝牙需要reset、重新启动时,需要靠这个flag来标记这种case的enable/disable状态
mEnableExternal:它主要是记录通过用户手动操作导致的BT使能状态,如通过蓝牙功能按钮来enable/disable BT
@packages/apps/Bluetooth/AndroidManifest.xml
<application android:name=".btservice.AdapterApp"
android:icon="@mipmap/bt_share"
android:persistent="false"
android:label="@string/app_name"
android:supportsRtl="true"
android:usesCleartextTraffic="false"
android:directBootAware="true
android:defaultToDeviceProtectedStorage="true"
<service
android:process="@string/process"
android:name = ".btservice.AdapterService">
<intent-filter>
<action android:name="android.bluetooth.IBluetooth" />
</intent-filter>
</service>
相关文章:
Android 蓝牙服务启动
蓝牙是Android设备中非常常见的一个feature,设备厂家可以用BT来做RC、连接音箱、设备本身做Sink等常见功能。如果一些设备不需要BT功能,Android也可以通过配置来disable此模块,方便厂家为自己的设备做客制化。APP操作设备的蓝牙功能ÿ…...
【安全系列--处理挖矿】
现象:我们云上waf提示有台服务器存在挖矿行为 解决思路: 1、查看服务器的进程情况 top发现服务的CPU使用率非常高 2、使用性能分析工具perf查看占用的cpu进程 sudo apt install linux-tools-common发现一些kernel进程存在异常 3、使用find查一下这…...
SpringBoot集成Thymeleaf模板引擎,为什么使用(详细介绍)
学习本技术第一件事:你为什么要使用,解决什么问题的? 1.为什么使用(使用背景)? 首先应用场景是单体项目,如果是前后端分离就不用关注这个了,因为单体项目你前后端都是写在一个项目…...
Docker突然宣布:涨价80%
从11月15日起,Docker的付费订阅中Pro和Team的价格都将大幅上调:Pro从原来的5美元每月激增到9美元每月,直接涨了80%;而Team也从之前的9美元每月来到15美元每月,涨价66.7%。只有Business保持此前的24美元每月不变。 同时…...
工厂方法模式和抽象工厂模式
工厂方法模式 一个工厂只能创建一种产品 工厂方法模式的结构 工厂方法模式包含以下4个角色 Product(抽象产品) ConcreteProduct(具体产品) Factory(抽象工厂) ConcreteFactory(具体工厂…...
【星海出品】go语言环境兼install
官网 https://golang.google.cn/dl/ go的安装包下载地址 https://go.dev/dl/ set GO111MODULEon //是否以Go modules的模式运行项目 auto,on,off set GOARCHamd64 //目标可执行程序操作系统构架 包括 386,amd64,arm set GOBIN //项目的第三方可执行文件目…...
Spring 源码解读:自定义实现BeanPostProcessor的扩展点
引言 在Spring的生命周期管理中,BeanPostProcessor是一个非常重要的扩展点。它允许开发者在Bean初始化的前后插入自定义的逻辑,从而实现更灵活的Bean管理。BeanPostProcessor是Spring框架中用于对Bean实例进行修改的机制之一。通过实现该接口࿰…...
Spring Boot-分布式系统问题
Spring Boot 在分布式系统中的常见问题及解决方案 随着互联网的发展,系统规模和复杂度越来越大,分布式系统成为应对高并发、大数据量场景的重要架构选择。Spring Boot 作为一种轻量级的开发框架,广泛应用于构建微服务和分布式系统中。然而&a…...
面试题总结(三) -- 内存管理篇
面试题总结(三) – 内存管理篇 文章目录 面试题总结(三) -- 内存管理篇<1> C 中堆内存和栈内存的区别是什么?<2> 如何在 C 中手动管理内存(new/delete 操作符)?<3> C 中内存泄漏的原因和避免方法<4> 谈谈…...
Qt 定时器-定时备份
定时备份 在Qt 中,可以使用QTimer类来实现定时备份功能。以下是一个示例代码,每隔一段时间自动执行备份操作: #include <QTimer>QTimer timer; int backupInterval 24 * 60 * 60 * 1000;//备份间隔为24小时connect(&timer, &…...
天融信把桌面explorer.exe删了,导致开机之后无windows桌面,只能看到鼠标解决方法
win10开机进入桌面,发现桌面无了,但是可以ctrlaltdelete调出任务管理器 用管理员权限打开cmd,输入: sfc /scanfilec:\windowslexplorer.exe 在运行C:\windows\Explorer.exe;可以进入桌面,但是隔离几秒钟…...
视频分割操作教程
1、打开剪映 2、点击开始创作上面的“”,选择视频,点击添加按钮,导入一个视频素材到剪映 3、滑动视频,让视频竖线到合适位置 4、点击视频,出现白色边框 5、点击工具栏“分割”,然后点击需要删除的视频部分 …...
唯品会大数据面试题及参考答案(3万字长文)
synchronized 和 volatile 的区别 synchronized是 Java 中的关键字,用于实现同步机制,确保在同一时刻只有一个线程可以访问被它修饰的代码块或方法。volatile也是 Java 中的关键字,主要用于保证变量的可见性。 功能方面: synchronized可以保证原子性、可见性和有序性。它通…...
使用容器技术快速入门MinIO
使用容器技术快速入门MinIO 使用容器技术(docker或者podman)快速部署一个单节点单磁盘 MinIO 服务器,用于对MinIO对象存储及其兼容 S3 的 API 层进行早期的开发和评估。 1. 准备工作 机器已经安装了 Podman 或者 Docker 。 对用于持久卷的…...
ros2教程(一):使用python和C++发布摄像头原始图像和压缩图像
1. 使用python发布图像 在ROS 2中,可以通过使用rclpy库来发布压缩图像和原始图像。发布原始图像可以使用sensor_msgs.msg.Image消息类型,压缩图像则使用sensor_msgs.msg.CompressedImage消息类型。 #!/usr/bin/env python3# function: usbcam publish r…...
【自动化测试】UI自动化的分类、如何选择合适的自动化测试工具以及其中appium的设计理念、引擎和引擎如何工作
引言 UI自动化测试主要针对软件的用户界面进行测试,以确保用户界面元素的交互和功能符合预期 文章目录 引言一、UI自动化的分类1.1 基于代码的自动化测试1.2 基于录制/回放的自动化测试1.3 基于框架的自动化测试1.4 按测试对象分类1.5 按测试层次分类1.6 按测试执行…...
深入理解Python中的“_,”:一个实用的语法特性
在Python编程中,你可能经常会看到一个特殊的标识符“_”。这个符号在Python中有多种用途,其具体含义依上下文而定。本文将探讨其中一种常见用法——作为一个临时性的占位符——并解释它在实际编程中的实用性和应用场景。 1. “_”作为占位符 在Python中…...
Mac清理其他文件:释放存储空间的高效指南
每个Mac用户都可能遇到存储空间不足的问题,尤其是当“其他”文件积累到一定体积时。在Mac上,“其他”文件通常包括各种系统文件、缓存、文档以及不被归类为应用程序、照片、电影或音乐的其他类型的文件。这些文件往往不易被注意,但逐渐占用了…...
html+css+js网页设计 旅游 龙门石窟4个页面
htmlcssjs网页设计 旅游 龙门石窟4个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…...
CISSP一站通关
依托轻速云维护了一个专注于CISSP备考通关的在线学习平台,提供知识串讲视频,配合大量针对性的习题和重难点习题解析,帮助备考学习者高效学习和巩固知识点。已经帮助100考友顺利通过考试。 知识串讲视频是我主讲的5天直播课程的录屏࿰…...
Arcgis新手必看:如何用线矢量快速提取tif栅格值并绘制专业剖面线图
ArcGIS线矢量提取栅格值实战:从数据到专业剖面图的完整指南 当你第一次面对需要分析地形起伏、温度梯度或任何连续空间数据的变化趋势时,剖面线图无疑是直观展示这些信息的利器。作为ArcGIS平台的核心分析功能之一,线矢量提取栅格值并绘制剖面…...
从“数字员工”到“可控系统”:Agent 治理框架与审批流程
从“数字员工”到“可控系统”:Agent 治理框架与审批流程深度解析 摘要/引言 开门见山 你有没有在最近的科技峰会、企业新闻或者 GitHub 热榜里,听到过「Agent 接管 80% 重复性编程工作」「金融客服 Agent 日处理量破百万件」这类令人振奋又隐隐不安的消息?上周我和某银行…...
OpenClaw硬件推荐:流畅运行Kimi-VL-A3B-Thinking的配置清单
OpenClaw硬件推荐:流畅运行Kimi-VL-A3B-Thinking的配置清单 1. 为什么需要关注硬件配置? 去年冬天,当我第一次尝试在MacBook Pro上运行Kimi-VL-A3B-Thinking模型时,风扇的呼啸声让我意识到——多模态模型的硬件需求远比想象中苛…...
On the Spectral Geometry of Cognitive Manifolds and the Emergence of Physical Laws
On the Spectral Geometry of Cognitive Manifolds and the Emergence of Physical Laws (A Noncommutative Framework for Free Will, Physical Constants, and Arithmetical Obstructions)作者:方见华 单位:世毫九实验室摘要&am…...
2025届学术党必备的六大降重复率助手推荐
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 提高人工智能生成内容即AIGC的检测难度,关键之处在于增强文本的自然特性与个性化…...
【Dify】无网络环境下的Dify部署指南:从在线到离线的无缝迁移
1. 为什么需要离线部署Dify? 在企业级应用场景中,数据安全和网络隔离是刚需。很多金融、政务、医疗机构的服务器都部署在内网环境,完全与互联网物理隔离。这时候如果想使用Dify这样的AI应用开发平台,常规的在线安装方式就完全行不…...
8年Java后端转型AI,踩坑一年总结:后端工程力是大模型应用开发的护城河!涨薪30%的秘诀在此
做了八年Java后端,去年咬牙转型AI应用开发。这一年踩过坑、加过班、也被面试官问倒过。但回头看,这条路选对了——薪资涨了30%,职业空间也打开了。我必须告诉那些还在犹豫要不要从后端跳出来的同行——现在的AI应用开发社招,确实是…...
2025届必备的五大降AI率方案推荐
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 在内容创作这个范畴里,要提升文本的真实感以及原创性,关键在于降低人…...
基于DSP28335逆变器程序,单相全桥逆变器程序,采用双极性调制 程序逻辑清晰,注释详细,详...
基于DSP28335逆变器程序,单相全桥逆变器程序,采用双极性调制 程序逻辑清晰,注释详细,详细到几乎每一句都有注释,对于小白异常友好,有些地方甚至基本原理都补充写明了,百分之99的程序注释不会有我…...
突破3D资产生产瓶颈:Hunyuan3D-2赋能企业级内容创作的实战案例
突破3D资产生产瓶颈:Hunyuan3D-2赋能企业级内容创作的实战案例 【免费下载链接】Hunyuan3D-2 High-Resolution 3D Assets Generation with Large Scale Hunyuan3D Diffusion Models. 项目地址: https://gitcode.com/GitHub_Trending/hu/Hunyuan3D-2 Hunyuan3…...
