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天直播课程的录屏࿰…...

Golang | Leetcode Golang题解之第406题根据身高重建队列
题目: 题解: func reconstructQueue(people [][]int) (ans [][]int) {sort.Slice(people, func(i, j int) bool {a, b : people[i], people[j]return a[0] > b[0] || a[0] b[0] && a[1] < b[1]})for _, person : range people {idx : pe…...

【我的Android进阶之旅】解决CardView四个圆角有白边的问题
文章目录 一、问题描述二、分析CardView出现白边的原因三、如何解决这个问题?3.1 如何修复?3.2 为什么这样可以修复?3.3 示例代码3.4 总结一、问题描述 在实现一个RecycleView的Item时候,样式需要用到卡片式效果,于是想到用CardView来实现,但是最终发现运行出来的效果,…...

学习笔记JVM篇(四)
垃圾回收器 说完垃圾回收算法接下来就需要对应的垃圾回收器去回垃圾回收器。接下来介绍几种垃圾回收器 1、Serial 串行回收器,是单线程版本,暂停所有的应用。在单CPU的情况下效率是很高的,因为不涉及线程的上下文切换。适用于小型程序和客…...

828 华为云征文|华为 Flexus 云服务器搭建萤火商城 2.0
《828 华为云征文|华为 Flexus 云服务器搭建萤火商城 2.0》 在 2024 年 9 月 14 日这个特别的日子,我着手利用华为 Flexus 云服务器搭建轻量级、高性能、前后端分离的电商系统萤火商城 2.0,开启了一段充满挑战与惊喜的旅程。 华为 Flexus 云服…...

centos7安装MySQL5.7.44
下载压缩文件 命令: #放到在/usr/local目录下 cd /usr/local #上传命令选择安装包 rz #解压缩包 tar -zxvf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz #给包重命名为mysql mv mysql-5.7.44-linux-glibc2.12-x86_64 mysql #查看mysql目录下有什么东西 [rootlocal…...

HTTP 请求处理的完整流程到Servlet流程图
HTTP 请求处理的完整流程。从 TCP 三次握手开始,一直到 Servlet 处理请求并返回响应。 首先,让我解释一下 response.setContentType("text/html;charsetUTF-8"); 这行代码: 这行代码设置了 HTTP 响应的 Content-Type 头。它告诉浏…...

spingboot中创建简单的WebSocket服务和使用OKHttp创建socket客户端接收数据
背景 springboot 中使用okhttp3创建webSocket服务端 server1 和客户端 client1,客户端clinet1调用server1用于发送图片,创建客户端client2接收此图片. 在Spring Boot中使用OkHttp3创建WebSocket服务端和客户端,涉及到两个不同的操作ÿ…...

Redis入门2
在java中操作Redis Redis的Java客户端 Redis 的 Java 客户端很多,常用的几种: Jedis Lettuce Spring Data Redis Spring Data Redis 是 Spring 的一部分,对 Redis 底层开发包进行了高度封装。 在 Spring 项目中,可以使用Spring Data R…...

嵌入式Linux:信号是什么?
目录 1、信号的来源 2、信号的处理方式 3、信号的异步性 4、信号编号 信号是Linux系统中用于通知进程事件发生的一种机制,可以将其视为一种软件中断。信号类似于硬件中断,能够打断进程当前的执行流程,从而实现对中断机制的一种软件层面的…...

教你搭建一个wifi贴系统
大家好,我是鲸天科技千千,大家都知道我是做小程序开发的,平时会给大家分享一些互联网相关的创业项目,感兴趣的可以跟我关注一下。 搭建一个首先就是要搭建一个自己的wifi贴小程序,我们自己的工作就是把这个小程序推广…...