当前位置: 首页 > news >正文

USB偏好设置-Android13

USB偏好设置

  • 1、USB偏好设置界面和入口
  • 2、USB功能设置
    • 2.1 USB功能对应模式
    • 2.2 点击设置
    • 2.3 广播监听刷新
  • 3、日志开关
    • 3.1 Evet日志
    • 3.2 代码中日志开关
    • 3.3 关键日志
  • 4、异常

1、USB偏好设置界面和入口

设置》已连接的设备》USB
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
packages/apps/Settings/res/xml/usb_details_fragment.xml
在这里插入图片描述

private static List<UsbDetailsController> createControllerList(Context context,UsbBackend usbBackend, UsbDetailsFragment fragment) {List<UsbDetailsController> ret = new ArrayList<>();ret.add(new UsbDetailsHeaderController(context, fragment, usbBackend));ret.add(new UsbDetailsDataRoleController(context, fragment, usbBackend));ret.add(new UsbDetailsFunctionsController(context, fragment, usbBackend));ret.add(new UsbDetailsPowerRoleController(context, fragment, usbBackend));ret.add(new UsbDetailsTranscodeMtpController(context, fragment, usbBackend));return ret;
}

2、USB功能设置

packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

2.1 USB功能对应模式

FWK模式对应值字符串显示节点
FUNCTION_NONE = 0NONE = 0
FUNCTION_MTP = GadgetFunction.MTPMTP = 1 << 2“文件传输”
FUNCTION_PTP = GadgetFunction.PTPPTP = 1 << 4“PTP”
FUNCTION_RNDIS = GadgetFunction.RNDISRNDIS = 1 << 5“USB 网络共享”
FUNCTION_MIDI = GadgetFunction.MIDIMIDI = 1 << 3“MIDI”
FUNCTION_ACCESSORY = GadgetFunction.ACCESSORYACCESSORY = 1 << 1
FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCEAUDIO_SOURCE = 1 << 6
FUNCTION_ADB = GadgetFunction.ADBADB = 1 << 0“不用于数据传输”

frameworks/base/core/java/android/hardware/usb/UsbManager.java
hardware/interfaces/usb/gadget/1.0/types.hal
frameworks/base/core/proto/android/service/usb.proto

/* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */
enum Function {FUNCTION_ADB = 1;FUNCTION_ACCESSORY = 2;FUNCTION_MTP = 4;FUNCTION_MIDI = 8;FUNCTION_PTP = 16;FUNCTION_RNDIS = 32;FUNCTION_AUDIO_SOURCE = 64;
}

2.2 点击设置

mUsbBackend 通过UsbManager.java、UsbService.java、UsbDeviceManager.java设置

packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

@Override
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {final long function = UsbBackend.usbFunctionsFromString(preference.getKey());final long previousFunction = mUsbBackend.getCurrentFunctions();if (DEBUG) {Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : "+ UsbManager.usbFunctionsToString(function) + ", previousFunction : "+ previousFunction + ", toString() : "+ UsbManager.usbFunctionsToString(previousFunction));}if (function != previousFunction && !Utils.isMonkeyRunning()&& !isClickEventIgnored(function, previousFunction)) {mPreviousFunction = previousFunction;//Update the UI in advance to make it looks smoothfinal SelectorWithWidgetPreference prevPref =(SelectorWithWidgetPreference) mProfilesContainer.findPreference(UsbBackend.usbFunctionsToString(mPreviousFunction));if (prevPref != null) {prevPref.setChecked(false);preference.setChecked(true);}if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) {// We need to have entitlement check for usb tethering, so use API in// TetheringManager.mTetheringManager.startTethering(TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler),mOnStartTetheringCallback);} else {mUsbBackend.setCurrentFunctions(function);}}
}

frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java

public void setCurrentFunctions(long functions) {if (DEBUG) {Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");}if (functions == UsbManager.FUNCTION_NONE) {MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_CHARGING);} else if (functions == UsbManager.FUNCTION_MTP) {MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);} else if (functions == UsbManager.FUNCTION_PTP) {MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_PTP);} else if (functions == UsbManager.FUNCTION_MIDI) {MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MIDI);} else if (functions == UsbManager.FUNCTION_RNDIS) {MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_RNDIS);} else if (functions == UsbManager.FUNCTION_ACCESSORY) {MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);}mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);}private boolean trySetEnabledFunctions(long usbFunctions, boolean forceRestart) {String functions = null;if (usbFunctions != UsbManager.FUNCTION_NONE) {functions = UsbManager.usbFunctionsToString(usbFunctions);}mCurrentFunctions = usbFunctions;if (functions == null || applyAdbFunction(functions).equals(UsbManager.USB_FUNCTION_NONE)) {functions = UsbManager.usbFunctionsToString(getChargingFunctions());}functions = applyAdbFunction(functions);String oemFunctions = applyOemOverrideFunction(functions);if (!isNormalBoot() && !mCurrentFunctionsStr.equals(functions)) {setSystemProperty(getPersistProp(true), functions);}if ((!functions.equals(oemFunctions)&& !mCurrentOemFunctions.equals(oemFunctions))|| !mCurrentFunctionsStr.equals(functions)|| !mCurrentFunctionsApplied|| forceRestart) {Slog.i(TAG, "Setting USB config to " + functions);mCurrentFunctionsStr = functions;mCurrentOemFunctions = oemFunctions;mCurrentFunctionsApplied = false;/*** Kick the USB stack to close existing connections.*/setUsbConfig(UsbManager.USB_FUNCTION_NONE);if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {Slog.e(TAG, "Failed to kick USB config");return false;}/*** Set the new USB configuration.*/setUsbConfig(oemFunctions);if (mBootCompleted&& (containsFunction(functions, UsbManager.USB_FUNCTION_MTP)|| containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {/*** Start up dependent services.*/updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));}if (!waitForState(oemFunctions)) {Slog.e(TAG, "Failed to switch USB config to " + functions);return false;}mCurrentFunctionsApplied = true;}return true;}

hardware/interfaces/usb/gadget/1.2/default/UsbGadget.cpp

V1_0::Status UsbGadget::setupFunctions(uint64_t functions,const sp<V1_0::IUsbGadgetCallback>& callback,uint64_t timeout) {bool ffsEnabled = false;int i = 0;if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=V1_0::Status::SUCCESS)return V1_0::Status::ERROR;if ((functions & V1_2::GadgetFunction::ADB) != 0) {ffsEnabled = true;if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;}// Pull up the gadget right away when there are no ffs functions.if (!ffsEnabled) {if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;mCurrentUsbFunctionsApplied = true;if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);return V1_0::Status::SUCCESS;}monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);// Monitors the ffs paths to pull up the gadget when descriptors are written.// Also takes of the pulling up the gadget again if the userspace process// dies and restarts.monitorFfs.startMonitor();if (kDebug) ALOGI("Mainthread in Cv");if (callback) {bool pullup = monitorFfs.waitForPullUp(timeout);Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());}return V1_0::Status::SUCCESS;
}Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,const sp<V1_0::IUsbGadgetCallback>& callback,uint64_t timeout) {std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);mCurrentUsbFunctions = functions;mCurrentUsbFunctionsApplied = false;// Unlink the gadget and stop the monitor if running.V1_0::Status status = tearDownGadget();if (status != V1_0::Status::SUCCESS) {goto error;}ALOGI("Returned from tearDown gadget");// Leave the gadget pulled down to give time for the host to sense disconnect.usleep(kDisconnectWaitUs);if (functions == static_cast<uint64_t>(V1_2::GadgetFunction::NONE)) {if (callback == NULL) return Void();Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);if (!ret.isOk())ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());return Void();}status = validateAndSetVidPid(functions);if (status != V1_0::Status::SUCCESS) {goto error;}status = setupFunctions(functions, callback, timeout);if (status != V1_0::Status::SUCCESS) {goto error;}ALOGI("Usb Gadget setcurrent functions called successfully");return Void();error:ALOGI("Usb Gadget setcurrent functions failed");if (callback == NULL) return Void();Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);if (!ret.isOk())ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());return Void();
}

hardware/interfaces/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp

Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,int* functionCount) {if (((functions & GadgetFunction::MTP) != 0)) {*ffsEnabled = true;ALOGI("setCurrentUsbFunctions mtp");if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;// Add endpoints to be monitored.monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");} else if (((functions & GadgetFunction::PTP) != 0)) {*ffsEnabled = true;ALOGI("setCurrentUsbFunctions ptp");if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;// Add endpoints to be monitored.monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");}if ((functions & GadgetFunction::MIDI) != 0) {ALOGI("setCurrentUsbFunctions MIDI");if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;}if ((functions & GadgetFunction::ACCESSORY) != 0) {ALOGI("setCurrentUsbFunctions Accessory");if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;}if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {ALOGI("setCurrentUsbFunctions Audio Source");if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;}if ((functions & GadgetFunction::RNDIS) != 0) {ALOGI("setCurrentUsbFunctions rndis");if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;std::string rndisFunction = GetProperty(kVendorRndisConfig, "");if (rndisFunction != "") {if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;} else {// link gsi.rndis for older pixel projectsif (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;}}if ((functions & GadgetFunction::NCM) != 0) {ALOGI("setCurrentUsbFunctions ncm");if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;}return Status::SUCCESS;
}

了解 USB Gadget HAL API 架构
在这里插入图片描述

2.3 广播监听刷新

广播监听刷新 onUsbConnectionChanged > refresh
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java
packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

/*** Interface definition for a callback to be invoked when usb connection is changed.*/
interface UsbConnectionListener {void onUsbConnectionChanged(boolean connected, long functions, int powerRole, int dataRole,boolean isUsbConfigured);
}
private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =(connected, functions, powerRole, dataRole, isUsbFigured) -> {for (UsbDetailsController controller : mControllers) {controller.refresh(connected, functions, powerRole, dataRole);}};

3、日志开关

3.1 Evet日志

如:MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_MTP);

frameworks/base/core/java/com/android/internal/logging/MetricsLogger.java
frameworks/base/core/java/android/metrics/LogMaker.java
frameworks/base/proto/src/metrics_constants/metrics_constants.proto

   // The view or control was activated.TYPE_ACTION = 4;// These values should never appear in log outputs - they are reserved for// internal platform metrics use.RESERVED_FOR_LOGBUILDER_CATEGORY = 757;RESERVED_FOR_LOGBUILDER_TYPE = 758;RESERVED_FOR_LOGBUILDER_SUBTYPE = 759;// ACTION: Usb config has been changed to charging// CATEGORY: SETTINGS// OS: PACTION_USB_CONFIG_CHARGING = 1275;// ACTION: Usb config has been changed to mtp (file transfer)// CATEGORY: SETTINGS// OS: PACTION_USB_CONFIG_MTP = 1276;// ACTION: Usb config has been changed to ptp (photo transfer)// CATEGORY: SETTINGS// OS: PACTION_USB_CONFIG_PTP = 1277;// ACTION: Usb config has been changed to rndis (usb tethering)// CATEGORY: SETTINGS// OS: PACTION_USB_CONFIG_RNDIS = 1278;// ACTION: Usb config has been changed to midi// CATEGORY: SETTINGS// OS: PACTION_USB_CONFIG_MIDI = 1279;// ACTION: Usb config has been changed to accessory// CATEGORY: SETTINGS// OS: PACTION_USB_CONFIG_ACCESSORY = 1280;

3.2 代码中日志开关

adb 打开:需要重启Settings进程

adb shell setprop log.tag.UsbFunctionsCtrl D
adb shell setprop log.tag.UsbBroadcastReceiver D

packages/apps/Settings/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java

private static final String TAG = "UsbFunctionsCtrl";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

3.3 关键日志

start u|SettingsActivity: Switching to|UsbFunctionsCtrl:|UsbDetailsFragment:|UsbBroadcastReceiver:|UsbDeviceManager:|sysui_multi_action: [757,.*,758,4]

android.hardware.usb.gadget@1.1-service-qti:|libusbconfigfs:

4、异常

symlink失败:"Cannot create symlink %s -> %s errno:%d"

hardware/interfaces/usb/gadget/1.2/default/lib/include/UsbGadgetCommon.h

#define GADGET_PATH "/config/usb_gadget/g1/"
#define PULLUP_PATH GADGET_PATH "UDC"
#define PERSISTENT_BOOT_MODE "ro.bootmode"
#define VENDOR_ID_PATH GADGET_PATH "idVendor"
#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
#define DESC_USE_PATH GADGET_PATH "os_desc/use"
#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
#define CONFIG_PATH GADGET_PATH "configs/b.1/"
#define FUNCTIONS_PATH GADGET_PATH "functions/"
#define FUNCTION_NAME "function"
#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"

在这里插入图片描述
hardware/interfaces/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp

int linkFunction(const char* function, int index) {char functionPath[kMaxFilePathLength];char link[kMaxFilePathLength];sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);sprintf(link, "%s%d", FUNCTION_PATH, index);if (symlink(functionPath, link)) {ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);return -1;}return 0;
}Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,int* functionCount) {if (((functions & GadgetFunction::MTP) != 0)) {*ffsEnabled = true;ALOGI("setCurrentUsbFunctions mtp");if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;// Add endpoints to be monitored.monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");} else if (((functions & GadgetFunction::PTP) != 0)) {*ffsEnabled = true;ALOGI("setCurrentUsbFunctions ptp");if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;// Add endpoints to be monitored.monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");}if ((functions & GadgetFunction::MIDI) != 0) {ALOGI("setCurrentUsbFunctions MIDI");if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;}if ((functions & GadgetFunction::ACCESSORY) != 0) {ALOGI("setCurrentUsbFunctions Accessory");if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;}if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {ALOGI("setCurrentUsbFunctions Audio Source");if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;}if ((functions & GadgetFunction::RNDIS) != 0) {ALOGI("setCurrentUsbFunctions rndis");if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;std::string rndisFunction = GetProperty(kVendorRndisConfig, "");if (rndisFunction != "") {if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;} else {// link gsi.rndis for older pixel projectsif (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;}}if ((functions & GadgetFunction::NCM) != 0) {ALOGI("setCurrentUsbFunctions ncm");if (linkFunction("ncm.gs6", (*functionCount)++)) return Status::ERROR;}return Status::SUCCESS;
}

相关文章:

USB偏好设置-Android13

USB偏好设置 1、USB偏好设置界面和入口2、USB功能设置2.1 USB功能对应模式2.2 点击设置2.3 广播监听刷新 3、日志开关3.1 Evet日志3.2 代码中日志开关3.3 关键日志 4、异常 1、USB偏好设置界面和入口 设置》已连接的设备》USB packages/apps/Settings/src/com/android/setting…...

Ubuntu 22.04 (WSL) 安装 libssl1.1

废话不多说&#xff01;&#xff01;&#xff01; 步骤一&#xff1a; echo "deb http://security.ubuntu.com/ubuntu focal-security main" | sudo tee /etc/apt/sources.list.d/focal-security.list 步骤二&#xff1a; sudo apt-get update 步骤三&#xff1a…...

数据结构-图的课后习题(2)

题目要求&#xff1a; 对于下面的这个无向网&#xff0c;给出&#xff1a; 1.“深度优先搜索序列”&#xff08;从V1开始&#xff09; 2.“广度优先序列”&#xff08;从V1开始&#xff09; 3.“用Prim算法求最小生成树” 代码实现&#xff1a; 1.深度优先搜索&#xff1a…...

[Machine Learning] 多任务学习

文章目录 基于参数的MTL模型 (Parameter-based MTL Models)基于特征的MTL模型 (Feature-based MTL Models)基于特征的MTL模型 I&#xff1a;基于特征的MTL模型 II&#xff1a; 基于特征和参数的MTL模型 (Feature- and Parameter-based MTL Models) 多任务学习 (Multi-task Lear…...

【C语言从入门到放弃 6】递归,强制类型转换,可变参数和错误处理详解

C语言是一种功能强大的编程语言&#xff0c;具有许多高级特性&#xff0c;包括强制类型转换&#xff0c;递归&#xff0c;可变参数和错误处理。在本文中&#xff0c;我们将深入了解这些特性&#xff0c;并提供简单的示例来帮助理解。 递归 递归是一种函数调用自身的技术&…...

使用LLama和ChatGPT为多聊天后端构建微服务

微服务架构便于创建边界明确定义的灵活独立服务。这种可扩展的方法使开发人员能够在不影响整个应用程序的情况下单独维护和完善服务。然而&#xff0c;若要充分发挥微服务架构的潜力、特别是针对基于人工智能的聊天应用程序&#xff0c;需要与最新的大语言模型&#xff08;LLM&…...

CSS3 用户界面、图片、按钮

一、CSS3用户界面&#xff1a; 在CSS3中&#xff0c;增加了一些新的用户界面特性来调整元素尺寸、框尺寸和外边框。CSS3用户界面属性&#xff1a;resize、box-sizing、outline-offset。 1、resize&#xff1a; resize属性指定一个元素是否应该由用户去调整大小。 <style…...

说说对Redux中间件的理解?常用的中间件有哪些?实现原理?

一、是什么 中间件&#xff08;Middleware&#xff09;是介于应用系统和系统软件之间的一类软件&#xff0c;它使用系统软件所提供的基础服务&#xff08;功能&#xff09;&#xff0c;衔接网络上应用系统的各个部分或不同的应用&#xff0c;能够达到资源共享、功能共享的目的…...

【已验证】php配置连接sql server中文乱码(解决方法)更改utf-8格式

解决数据库中的中文数据在页面显示乱码的问题 在连接的$connectionInfo中设置"CharacterSet" > "UTF-8"&#xff0c;指定编码方式即可 $connectionInfo array("UID">$uid, "PWD">$pwd, "Database">$database…...

《未来之路:技术探索与梦想的追逐》

创作纪念日 日期&#xff1a;2023年07月05日文章标题&#xff1a;《从零开始-与大语言模型对话学技术-gradio篇&#xff08;1&#xff09;》成为创作者第128天 在这个平凡的一天&#xff0c;我撰写了自己的第一篇技术博客&#xff0c;题为《从零开始-与大语言模型对话学技术-…...

vue3 自动导入composition-apiI和组件

1.api的自动导入 常规写法&#xff1a; <script setup>import { ref, reactive, onMounted, computed ,watch } from vue;import { useRouter } from "vue-router";const router useRouter();const person reactive ({name&#xff1a;张三&#xff0c;age…...

LeetCode15-三数之和

本文最精华的就是下面的视频讲解! &#x1f517;:参考的视频讲解 class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> ans new ArrayList<>();Arrays.sort(nums);int nnums.length;int i0,j0,k0,sum0;for(…...

安全物理环境(设备和技术注解)

网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1物理位置选择 1.1机房…...

箭头函数 跟匿名函数this的指向问题

var id 10; function foo() {// 创建时 this->windowthis.id 20; // 等价于 window.id 20let c () > {console.log("id1:", this.id); // 创建时父级 创建时 this->window};let d function () {console.log("id2:", this.id); // 执行时本…...

Java Stream:List分组成Map或LinkedHashMap

在Java中&#xff0c;使用Stream API可以轻松地对集合进行操作&#xff0c;包括将List转换为Map或LinkedHashMap。本篇博客将演示如何利用Java Stream实现这两种转换&#xff0c;同时假设List中的元素是User对象。 1. 数据准备 List<User> list new ArrayList<>(…...

vue2+elementui使用MessageBox 弹框$msgbox自定义VNode内容:实现radio

虽说实现下面的效果&#xff0c;用el-dialog很轻松就能搞定。但是这种简单的交互&#xff0c;我更喜欢使用MessageBox。 话不多说&#xff0c;直接上代码~ <el-button type"primary" size"mini" click"handleApply()" >处理申请</el-b…...

OC 实现手指滑动拖动View

RPReplay_Final1699613924 实现手指滑动拖动View 支持手势移动的控件 支持 Masonry frame 布局 使用富文本 也支持自动高度 核心代码 - (void)handlePanGesture:(UIPanGestureRecognizer *)p {CGPoint panPoint [p locationInView:self.view];CGPoint currentViewPoint _dr…...

多级缓存之实现多级缓存

多级缓存的实现离不开Nginx编程&#xff0c;而Nginx编程又离不开OpenResty。 1. OpenResty快速入门 我们希望达到的多级缓存架构如图&#xff1a; 其中&#xff1a; windows上的nginx用来做反向代理服务&#xff0c;将前端的查询商品的ajax请求代理到OpenResty集群 OpenRest…...

React【axios、全局处理、 antd UI库、更改主题、使用css module的情况下修改第三方库的样式、支持sass less】(十三)

文件目录 Proxying in Development http-proxy-middleware fetch_get fetch 是否成功 axios 全局处理 antd UI库 更改主题 使用css module的情况下修改第三方库的样式 支持sass & less Proxying in Development 在开发模式下&#xff0c;如果客户端所在服务器跟后…...

在gitlab中指定自定义 CI/CD 配置文件

文章目录 1. 介绍2. 配置操作3. 配置场景3.1 CI/CD 配置文件在当前项目step1&#xff1a;在当前项目中创建目录&#xff0c;编写流水线文件存放在该目录中step2&#xff1a;在当前项目中配置step3&#xff1a;运行流水线测试 3.2 CI/CD 配置文件位于外部站点上step1&#xff1a…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...