Android HAL到Framework
一、为什么需要Framwork?
Framework实际上是⼀个应⽤程序的框架,提供了很多服务:
1、丰富⽽⼜可扩展的视图(Views),
可以⽤来构建应⽤程序,它包括列表(lists),⽹格(grids),⽂本框(text boxes),按钮(buttons),甚⾄可嵌⼊的web浏览器。
2、内容提供器(Content Providers)
使得应⽤程序可以访问另⼀个应⽤程序的数据(如联系⼈数据库),或者共享它们⾃⼰的数据
3、资源管理器(Resource Manager)
提供⾮代码资源的访问,如本地字符串,图形,和布局⽂件(layout files)。
4、通知管理器(Notification Manager)
使得应⽤程序可以在状态栏中显⽰⾃定义的提⽰信息。
5、活动管理器(Activity Manager)
⽤来管理应⽤程序⽣命周期并提供常⽤的导航回退功能。
二、应用层访问硬件,如何自定义系统Service?
1、应用层如何访问硬件

(1)Linux
对于Linux来说的话,就比较简单,应用层的APP直接通过open一类的接口直接访问我们底层的驱动文件
(2)Android
对于Android来说的话,它就会有多种方式去访问,
1) APP ----- JNI ----- Kernel:
这种就很直接明了,上层app访问JNI,再去访问kernel
2)APP ----- Service ----- JNI ----- Kernel:
当我们要往系统里添加一个硬件的话,我们更希望把它封装为一个系统的服务,就可以以这种方式去访问到底层
3)APP ----- Service ----- JNI ----- HAL ----- Kernel:
一些驱动厂商的一个源码呢他是不希望开放给我们的一个开发者是吧,但是他们又依赖着Android的开源框架,所以就有一种比较好的方法,既不需要公开源码,又可以实现同样的功能。就是把它封装成库,这样可以让厂家去提供一个现成的库,然后我们直接去使用,他就不用开放这一层的源码,这就是HAL层的存在意义。
为什么需要JNI?
应⽤使⽤java编写,驱动⼀般使⽤c/cpp编写,提供⼀种Java访问c/cpp的⽅法。也就是Java代码可通过JNI接⼝调⽤C/C++⽅法。
JNI开发流程的步骤:
1)编写JNI⽅法表并注册
2)实现JNI的.c⽂件

2、自定义系统Service
Framework还有一个很重要的功能,就是系统server。所有的硬件呢都是通过我们的系统server去进行管理,那我们怎样为我们的硬件接口去添加一个自定义的系统serve呢?
(1)建立aidl通信接口;
(2)在system_server中注册service到servicemanager;
(3)实现service,对应aidl中的接口函数。
(4)client向servicemanager请求service,成功后,调用aidl接口函数,建立client进程和service进程的通信关系。

总结来说就是:
1)system_server完成注册功能;
2)servicemanager完成服务管理功能;
3)aidl完成通讯功能;
(1)建立aidl通信接口
在frameworks/base/core/java/android/os/路径下新建对应名称的一个aidl文件
下面我们以顾凯歌的一个蓝牙模块的服务为大家举例:
路径:frameworks/base/core/java/android/os/IGocsdkService.aidl:
(因为他是Interface的一个接口,所有在前面加个 "I")+ package android.os;+ interface IEmbededService {
+ interface IFmService {
+
+ //蓝牙状态回调注册去注销
+ void registerCallback(IGocsdkCallback callback);
+ // 注销蓝牙状态
+ void unregisterCallback(IGocsdkCallback callback);
+
+ //注释后面带的为操作后相应的回调回复
+ //蓝牙协议软复位 ---》 onInitSucceed()
+ void restBluetooth();
+
+ //获取本地蓝牙名称 ---》onCurrentDeviceName()
+ void getLocalName();
+
+ //设置本地蓝牙名称 ---》onCurrentDeviceName()
+ void setLocalName(String name);+ ..................//等等一些,都为接口函数,会在下面实现}
编译到系统
路径:frameworks/base/Android.mk diff --git a/android/frameworks/base/Android.bp b/android/frameworks/base/Android.bp
old mode 100644
new mode 100755
index d8a7f06..953759c
--- a/android/frameworks/base/Android.bp
+++ b/android/frameworks/base/Android.bp
@@ -265,6 +265,11 @@ java_defaults {"core/java/android/os/IRecoverySystemProgressListener.aidl","core/java/android/os/IRemoteCallback.aidl","core/java/android/os/ISchedulingPolicyService.aidl",
+ "core/java/android/os/IGocsdkService.aidl",":statsd_aidl","core/java/android/os/ISystemUpdateManager.aidl","core/java/android/os/IThermalEventListener.aidl",
(2)在system_server中注册EmbededServicer到servicemanager
路径:frameworks/base/services/java/com/android/server/SystemServer.java
使用ServiceManager.addService添加我们自定义的server
@@ -1097,6 +1097,13 @@ public final class SystemServer {
}Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);+ try {+ Slog.i(TAG, "IGocsdkService");+ ServiceManager.addService("gocsdkService ", new GocsdkService());+ } catch (Throwable e) { + Slog.e(TAG, "Failure starting Gocsdk Service", e);+ }
(3)实现EmbededService,对应aidl中的接⼝函数
路径:frameworks/base/services/java/com/android/server/EmbededService.java
package com.android.server;
import android.content.Context;
import android.os.IGocsdkService;
import android.util.Slog;
public class GocsdkService extends IGocsdkService.Stub {private static final String TAG = "GocsdkService";GocsdkService(){Slog.i(TAG,"GocsdkService init");}public void registerCallback(IGocsdkCallback callback){return xxx;}public void unregisterCallback(IGocsdkCallback callback){return xxx;}public void getLocalName(){return xxx;}.......................
}
(4)在app中使⽤IEmbededService的大致流程如下
很好理解吧,把我们对应的一个服务导入,然后去初始化一个类,然后通过ServiceManager去找到我们自定义的这个server,然后使用自定义服务的函数获取数据。
import android.os.IGocsdkService; //导入private IGocsdkService mGocsdkService = null; //初始化类
mGocsdkService = IGocsdkService .Stub.asInterface(ServiceManager.getService("gocsdkService"));int version= mEmbededService.getLocalName();
String text = String.value(localName);
(5)编译service,烧录
直接全sdk编译,防止有遗漏
(6)验证
使⽤service list查看是否有EmbededService
xxx:/ $ service list | grep gocsdkServicegocsdkService: [android.os.IGocsdkService]
三、为什么需要Android HAL?
Hardware Abstract Layer 硬件抽象层,由于Linux Kernel需要遵循GPL开源协议,硬件⼚商为了保护⾃⼰硬件⽅⾯的各项参数不被外泄,⽽⼀个设备的驱动程序包含了硬件的⼀些重要参数,所以驱动的开源势必会使硬件⼚商蒙受损失,Google为了保护硬件⼚商的利益,所以在Android系统中加⼊了HAL层,在HAL层中不必遵循GPL协议,所以代码可以封闭。
所以如果硬件驱动开源的写在Kernel⾥,Framework直接调⽤,⽽不愿意开源的就写在HAL层⾥,实现闭源。也就是说,编写驱动分为两个部分,⼀个是HAL层的驱动代码,⼀个是Kernel层的驱动代码。
1、内核实现HAL驱动的⽅法有两种:
(1)采⽤直接调⽤so动态链接库⽅式
采⽤共享库形式,在编译时会调⽤到。由于采⽤function call形式调⽤,因此可被多个进程使⽤,但会被mapping到多个进程空间中,造成浪费,同时需要考虑代码能否安全重⼊的问题。
(2)采⽤Stub代理⽅式调⽤
采⽤HAL module和HAL stub结合形式,HAL stub不是⼀个share library,编译时
上层只拥有访问HAL stub的函数指针,并不需要HAL stub。上层通过HAL module提供的统⼀接⼝获取并操作HAL stub,so⽂件只会被mapping到⼀个进程,也不存在重复mapping和重⼊问题。
2、如何编写HAL层驱动
我们现在一般都是采用第二种方式,基于HAL框架提供了三个结构体,分别为hw_device_t、hw_module_t、hw_module_methods_t,编写HAL层驱动则是依据这三个结构体作扩展,我们创建⾃⼰驱动的device_t,module_t代码,并且写hw_module_methods_t这个结构体中⽅法的实现代码,最后JNI层通过hw_get_module调⽤。
(1)在 android/hardware/libhardware/modules/xxx 路径下创建我们的HAL文件夹,例如LED:
mkdirhardware/libhardware/modules/ledpath:hardware/libhardware/include/hardware/led_hal.h
path:hardware/libhardware/modules/embeded/led_hal.c
(1)led_hal.c:
#define LOG_TAG "dLed"
#include <hardware/hardware.h>
#include <hardware/led_hal.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#define DEVICE_NAME "sys/led/embeded_blue_led"
#define MODULE_NAME "EmLed"/*设备打开和关闭接⼝*/
static int embededled_device_open(const struct hw_module_t* module, const
char* name, struct hw_device_t** device);
static int embededled_device_close(struct hw_device_t* device);/*设备访问接⼝*/
static int embededled_set_val(struct embededled_device_t* dev, int val);
static int embededled_get_val(struct embededled_device_t* dev, int* val);
static int embededled_device_open(const struct hw_module_t* module, const
char* name, struct hw_device_t** device) {struct embededled_device_t* dev;dev = (structembededled_device_t*)malloc(sizeof(struct embededled_device_t));if(!dev) {ALOGI("embededled Stub: failed to alloc space");return -EFAULT;}memset(dev, 0, sizeof(struct embededled_device_t));//初始化设备相关信息,实现访问接⼝函数dev->common.tag = HARDWARE_DEVICE_TAG;dev->common.version = 0;dev->common.module = (hw_module_t*)module;dev->common.close = embededled_device_close;dev->set_val = embededled_set_val;dev->get_val = embededled_get_val;if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {ALOGI("embededled Stub: failed to opensys/embededled/embeded_blue_led -- %s.", strerror(errno));free(dev);return -EFAULT;}int status = 0;write(dev->fd, &status, sizeof(status));*device = &(dev->common);ALOGI("embededled Stub: open sys/embededled/embeded_blue_ledsuccessfully.");return 0;
}static int embededled_device_close(struct hw_device_t* device) {struct embededled_device_t* embededled_device = (structembededled_device_t*)device;if(embededled_device) {close(embededled_device->fd);free(embededled_device);}return 0;
}static int embededled_set_val(struct embededled_device_t* dev, int val) {ALOGI("embededled Stub: set value %d to device.", val);write(dev->fd, &val, sizeof(val));return 0;}static int embededled_get_val(struct embededled_device_t* dev, int* val) {
if(!val) {ALOGI("embededled Stub: error val pointer");return -EFAULT;
}read(dev->fd, val, sizeof(*val));ALOGI("embededled Stub: get value %d from device", *val);return 0;
}/*模块⽅法表*/
static struct hw_module_methods_t embededled_module_methods = {
open: embededled_device_open
};/*模块实例变量*/
struct embededled_module_t HAL_MODULE_INFO_SYM = {
common: {tag: HARDWARE_MODULE_TAG,version_major: 1,version_minor: 0,id: EMBEDEDLED_HARDWARE_MODULE_ID,name: MODULE_NAME,author: MODULE_AUTHOR,methods: &embededled_module_methods,
}
};
led_hal.h:
path:hardware/libhardware/include/hardware/led_hal.h
#ifndef ANDROID_LED_INTERFACE_H
#define ANDROID_LED_INTERFACE_H
#include <hardware/hardware.h>
__BEGIN_DECLS
/*定义模块ID*/
#define EMBEDEDLED_HARDWARE_MODULE_ID "led_hal"
/*硬件模块结构体*/
struct led_module_t {struct hw_module_t common;
};
/*硬件接⼝结构体*/
struct embededled_device_t {struct hw_device_t common;int fd;int (*set_val)(struct led_device_t* dev, int val);int (*get_val)(struct led_device_t* dev, int* val);
};
__END_DECLS
#endif
四、JNI层添加
JNI开发流程的步骤:

里面呢就是我们要实现的三个函数,然后再把对应的方法注册到我们的server里面去
1 diff --git a/frameworks/base/services/core/jni/Android.mkb/frameworks/base/services/core/jni/Android.mk
2 index 0f0124bd46..305773298a 100644
3 --- a/frameworks/base/services/core/jni/Android.mk
4 +++ b/frameworks/base/services/core/jni/Android.mk
5 @@ -36,6 +36,7 @@ LOCAL_SRC_FILES += \
6 $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
7 $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
8 $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
9 + $(LOCAL_REL_DIR)/com_android_server_EmbededLedService.cpp \
10 $(LOCAL_REL_DIR)/onload.cpp
11
12 LOCAL_SRC_FILES += \
1 diff --git a/frameworks/base/services/core/jni/onload.cppb/frameworks/base/services/core/jni/onload.cpp
2 index d5861f8c41..b52f7917fd 100644
3 --- a/frameworks/base/services/core/jni/onload.cpp
4 +++ b/frameworks/base/services/core/jni/onload.cpp
5 @@ -47,6 +47,7 @@ intregister_android_server_PersistentDataBlockService(JNIEnv* env);
6 int register_android_server_Watchdog(JNIEnv* env);
7 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
8 int register_com_android_server_rkdisplay_RkDisplayModes(JNIEnv* env);
9 +int register_android_server_EmbededLedService(JNIEnv* env);
10 };
11
12 using namespace android;
13 @@ -89,7 +90,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
14 register_android_server_Watchdog(env);
15 register_android_server_HardwarePropertiesManagerService(env);
16 register_com_android_server_rkdisplay_RkDisplayModes(env);
17 -
18 -
19 + register_android_server_EmbededLedService(env);
20 return JNI_VERSION_1_4;
21 } 1、AIDL:
1 package android.os;
2
3 interface IEmbededLedService {
4 void setVal(int val);
5 int getVal();
6 } 1 diff --git a/frameworks/base/Android.mk b/frameworks/base/Android.mk
2 index b9692de0e1..c426a3cd99 100755
3 --- a/frameworks/base/Android.mk
4 +++ b/frameworks/base/Android.mk
5 @@ -240,6 +240,7 @@ LOCAL_SRC_FILES += \
6 core/java/android/os/IUpdateLock.aidl \
7 core/java/android/os/IUserManager.aidl \
8 core/java/android/os/IVibratorService.aidl \
9 + core/java/android/os/IEmbededLedService.aidl \
10 core/java/android/os/IDisplayDeviceManagementService.aidl \
11 core/java/android/os/IRkDisplayDeviceManagementService.aidl \
12 core/java/android/security/IKeystoreService.aidl \ 2、Service
1 package com.android.server;
2 import android.content.Context;
3 import android.os.IEmbededLedService;
4 import android.util.Slog;
5 public class EmbededLedService extends IEmbededLedService.Stub {
6 private static final String TAG = "EmbededLedService";
7 EmbededLedService() {
8
9 boolean status = init_native();
10 Slog.i(TAG,"EmbededLedService Stub init"+status);
11 }
12 public void setVal(int val) {
13 setVal_native(val);
14 }
15 public int getVal() {
16 return getVal_native();
17 }
18
19 //JNI⽅法
20 private static native boolean init_native();
21 private static native void setVal_native(int val);
22 private static native int getVal_native();
23 }; 3、添加Service到System启动
1 diff --git
a/frameworks/base/services/java/com/android/server/SystemServer.java
b/frameworks/base/services/java/com/android/server/SystemServer.java
2 index cc6f1850e6..b22ecda734 100644
3 --- a/frameworks/base/services/java/com/android/server/SystemServer.java
4 +++ b/frameworks/base/services/java/com/android/server/SystemServer.java
5 @@ -1086,6 +1086,15 @@ public final class SystemServer {
6 } catch (Throwable e) {
7 reportWtf("starting DiskStats Service", e);
8 }
9 +
10 + try {
11 + Slog.i(TAG, "Embededled Service");
12 + ServiceManager.addService("embededled", new
EmbededLedService());
13 + } catch (Throwable e) {
14 + Slog.e(TAG, "Failure starting Embededled Service", e);
15 + }
16 +
17 +
18 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
19
20 if (!disableSamplingProfiler) { 4、编译&烧写
相关文章:
Android HAL到Framework
一、为什么需要Framwork? Framework实际上是⼀个应⽤程序的框架,提供了很多服务: 1、丰富⽽⼜可扩展的视图(Views), 可以⽤来构建应⽤程序,它包括列表(lists),⽹格&am…...
Python数据可视化(七)
绘制 3D 图形 到目前为止,我们一直在讨论有关 2D 图形的绘制方法和绘制技术。3D 图形也是数据可视化的 一个很重要的应用方面,我们接下来就重点讲解有关 3D 图形的实现方法。绘制 3D 图形通常需要导 入 mpl_toolkits 包中的 mplot3d 包的相关模块&#x…...
StringMVC
目录 一,MVC定义 二,SpringMVC的基本使用 2.1建立连接 - RequestMapping("/...") 编辑 2.2请求 1.传递单个参数 2.传递多个参数 3.传递对象 4.参数重命名 5.传递数组 6. 传递集合 7.传递JSON数据 8. 获取url中数据 9. 传递文…...
前端基础入门三大核心之HTML篇 —— SVG的viewBox、width和height:绘制矢量图的魔法比例尺【含代码示例】
前端基础入门三大核心之HTML篇 —— SVG的viewBox、width和height:绘制矢量图的魔法比例尺【含代码示例】 基本概念与作用viewBoxwidth和height 代码示例与实践基础示例动态调整示例 不同角度的使用思路保持比例缩放自动适应容器 实际问题与解决方案结语与讨论 在前…...
Java-Zookeeper
zookeeper是什么 一个分布式、开源的分布式应用程序协调服务,具有配置维护、域名服务、分布式同步、组服务等 zookeeper有哪些功能 功能简介集群管理监控节点状态、运行请求等主节点选举主节点挂掉之后会执行新主选举分布式锁zookeeper提供两种锁:独占…...
Godot游戏引擎有哪些优势
哈喽呀,大家好呀,淼淼又来和大家见面啦,众所周知在当今游戏开发领域,各种游戏引擎如雨后春笋般涌现,为开发者提供了丰富的选择。而在这些众多的选择中,Godot游戏引擎以其独特的特性和开放源代码的优势&…...
一张图看懂大模型性价比:能力、价格、并发量全面PK
最近,国内云厂商的大模型掀起一场降价风暴。火山引擎、阿里云、百度云等纷纷宣布降价,部分模型价格降幅据称高达99%,甚至还有些模型直接免费。 五花八门的降价话术,一眼望去遍地黄金。但事实真的如此吗?今天我们就拨开…...
设计井字棋游戏(一)
创建游戏登录注册窗口 用户名admin 密码admin(可自行改变) 主页面 1. 导包 import pickle:导入 pickle 模块,这是一个 Python 的内置模块,用于将 Python 对象序列化和反序列化。序列化是指将对象转换为字节流&am…...
华为手机卡顿(仅针对于部分人来说,我也不清楚是否真的有用)
关机! 之前一段时间手机变得特别卡顿,然后网上搜了一堆教程一点用没有,结果因为昨天下午在考试所以把手机关机了一个多小时,再打开之后手机就变得很流畅,原因不详,但效果显著,如有需要可尝试一…...
7、按钮无法点击
不能点击,打开f12,删除disabled...
开源博客项目Blog .NET Core源码学习(25:App.Hosting项目结构分析-13)
本文学习并分析App.Hosting项目中后台管理页面的文章管理页面。 文章管理页面用于显示、检索、新建、编辑、删除文章数据,以便在前台页面的首页、文章专栏、文章详情页面显示文章数据。文章管理页面附带一新建及编辑页面,以支撑新建和编辑文章数据。…...
第七节 ConfigurationClassParser 源码分析
tips: ConfigurationClassParser 是 Springframework 中的重要类。 本章主要是源码理解,有难度和深度,也枯燥乏味,可以根据实际情况选择阅读。 位置:org.springframework.context.annotation.ConfigurationClassPars…...
零基础代码随想录【Day42】|| 1049. 最后一块石头的重量 II,494. 目标和,474.一和零
目录 DAY42 1049.最后一块石头的重量II 解题思路&代码 494.目标和 解题思路&代码 474.一和零 解题思路&代码 DAY42 1049.最后一块石头的重量II 力扣题目链接(opens new window) 题目难度:中等 有一堆石头,每块石头的重量都是正整…...
2024-5-24 石群电路-15
2024-5-24,星期五,22:15,天气:晴,心情:晴。今天最后一天上班,终于要放返校假啦,开心!!!!!!不过放假也不能耽误…...
功能测试:核心原理、挑战以及解决之道
在软件开发生命周期中,功能测试占据了至关重要的位置。它是确保软件应用按照既定的要求和规格运行的关键测试阶段。功能测试的目的在于验证软件的功能、行为和用户界面等是否达到了业务需求的标准。本文将深入探讨功能测试的概念,执行过程中可能遇到的挑…...
跨境电商赛道,云手机到底能不能化繁为简?
当下国内电商背景: 从零售额的数据来看:随着互联网的普及和消费者购物习惯的改变,国内电商市场规模持续扩大。据相关数据显示,网络消费亮点纷呈,一季度全国网上零售额达到了3.3万亿元,同比增长12.4%。这表…...
linux:信号深入理解
文章目录 1.信号的概念1.1基本概念1.2信号的处理基本概念1.3信号的发送与保存基本概念 2.信号的产生2.1信号产生的五种方式2.2信号遗留问题(core,temp等) 3.信号的保存3.1 信号阻塞3.2 信号特有类型 sigset_t3.3 信号集操作函数3.4 信号集操作函数的使用 4.信号的处理4.1 信号的…...
Android系统的/etc/mkshrc文件
/etc/mkshrc 文件是用于配置 mksh(MirBSD Korn Shell)环境的启动脚本。mksh 是 Android 默认使用的 shell,在 shell 启动时会读取并执行这个文件中的配置。以下是关于 /etc/mkshrc 文件的详细信息及其用途。 /etc/mkshrc 文件的作用 环境配…...
LeetCode199二叉树的右视图
题目描述 给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 解析 这一题的关键其实就是找到怎么去得到当前是哪一层级,可以利用队列对二叉树进行层次遍历,但…...
JavaScript 基础
一 JavaScript 的书写形式 1.1 行内式 <input type"button" value"点我一下" onclick"alert(hello akai);" > 注意,JS 中的字符串常量可以用单引号表示,也可以使用双引号表示.HTML 中推荐使用双引号,JS 中推荐使用单引号(使用双引号容易…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
