廣播分發中心-廣播注冊流程

廣播是怎么注冊的呢?

0

階段

組件/數據結構

作用描述

存儲位置/關聯關系

App進程階段

BroadcastReceiver

開發者自定義的廣播接收器,實現onReceive

方法處理事件。

App進程(Activity/Service等組件內)

ReceiverDispatcher

將BroadcastReceiver封裝為跨進程可調用的

IIntentReceiver接口對象。

LoadedApk中創建,關聯InnerReceiver

InnerReceiver

繼承IIntentReceiver.Stub的Binder實體,AMS通過它回調App主線程的onReceive

作為Binder服務端存在于App進程,代理對象傳遞至AMS

SystemServer進程階段

ReceiverList

以InnerReceiver的Binder為Key,管理同一接收器的多個BroadcastFilter

存儲在AMS的mRegisteredReceivers(HashMap)

BroadcastFilter

關聯IntentFilter與ReceiverList,描述接收器感興趣的廣播類型。

注冊到mReceiverResolver(全局匹配引擎)和ReceiverList

BroadcastQueue

管理待分發的廣播,分為有序和無序隊列。

AMS中維護,異步分發廣播

核心數據結構

mRegisteredReceivers

維護所有動態注冊的ReceiverList,避免重復注冊。

AMS內存(HashMap結構)

mReceiverResolver

基于IntentFilter的快速匹配引擎,優化廣播分發效率。

AMS內存(IntentResolver子類)

mStickyBroadcasts

緩存粘性廣播,按用戶ID和Action分類存儲。

AMS內存(SparseArray結構),供新注冊接收器匹配歷史廣播

源碼流程:?

app.registerReceiver()->Context.registerReceiver(BroadcastReceiver, IntentFilter)#Context.registerReceiver(BroadcastReceiver, IntentFilter)->Context.registerReceiverInternal()##Context.registerReceiverInternal()->LoadedApk.getReceiverDispatcher:返回一個為IIntentReceiver類型的ReceiverDispatcher(廣播快遞員)###LoadedApk.getReceiverDispatcher->ReceiverDispatcher實例化####ReceiverDispatcher實例化->InnerReceiver實例化:可以看到 InnerReceiver extends IIntentReceiver.Stub 是跨進程對象的一個實體##Context.registerReceiverInternal()->ActivityManagerService.registerReceiverWithFeature(IIntentReceiver)###ActivityManagerService.registerReceiverWithFeature(IIntentReceiver)->ActivityManagerService.registerReceiverWithFeatureTraced####ActivityManagerService.registerReceiverWithFeatureTraced->RegisteredReceivers.get(receiver.asBinder())創建ReceiverList,并mRegisteredReceivers全局注冊表記錄####ActivityManagerService.registerReceiverWithFeatureTraced->new BroadcastFilter:創建BroadcastFilter并注冊到Resolver,并mReceiverResolver注冊到全局過濾器####ActivityManagerService.registerReceiverWithFeatureTraced->new BroadcastRecord創建廣播記錄并加入隊列,并mBroadcastQueue.enqueueBroadcastLocked(r)異步分發

源碼重點函數分析:

注冊廣播接收器

registerReceiver來時往里面看,因為Activity是Context的子類,這個注冊的方法的實現則是在ContextImpl當中,其中最終調用的方法為registerReceiverInternal,代碼如下???

/**?* 動態注冊廣播接收器的核心方法,完成跨進程通信的Binder封裝和AMS注冊?* @param receiver 開發者定義的廣播接收器實例?* @param userId 用戶ID(多用戶支持)?* @param filter 意圖過濾器,描述接收器感興趣的廣播類型?* @param broadcastPermission 接收廣播所需的權限(可選)?* @param scheduler 指定回調線程的Handler(null則使用主線程Handler)?* @param context 關聯的Context對象?* @param flags 注冊標志位?* @return 匹配的粘性廣播Intent(若無則返回null)?*/private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,? ? ? ? IntentFilter filter, String broadcastPermission,? ? ? ? Handler scheduler, Context context, int flags) {? ? // 1. 創建跨進程通信對象IIntentReceiver? ? IIntentReceiver rd = null;? ? if (receiver != null) {? ? ? ? if (mPackageInfo != null && context != null) {? ? ? ? ? ? // 1.1 使用主線程Handler(若未指定)? ? ? ? ? ? if (scheduler == null) {? ? ? ? ? ? ? ? scheduler = mMainThread.getHandler(); // 獲取ActivityThread的H主線程Handler[1,3](@ref)? ? ? ? ? ? }? ? ? ? ? ? // 1.2 通過LoadedApk獲取ReceiverDispatcher(封裝跨進程Binder對象)? ? ? ? ? ? rd = mPackageInfo.getReceiverDispatcher(? ? ? ? ? ? ? ? receiver, context, scheduler,? ? ? ? ? ? ? ? mMainThread.getInstrumentation(), true); // true表示需要注冊[1,5](@ref)? ? ? ? } else {? ? ? ? ? ? // 1.3 備用路徑:直接創建ReceiverDispatcher(非標準場景)? ? ? ? ? ? if (scheduler == null) {? ? ? ? ? ? ? ? scheduler = mMainThread.getHandler();? ? ? ? ? ? }? ? ? ? ? ? rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),? ? ? ? ? ? ? ? ? ? receiver, context, scheduler, null, true).getIIntentReceiver();? ? ? ? }? ? }? ? try {? ? ? ? // 2. 跨進程調用AMS注冊廣播? ? ? ? final Intent intent = ActivityManager.getService().registerReceiverWithFeature(? ? ? ? ? ? ? ? mMainThread.getApplicationThread(), // 應用主線程的IApplicationThread對象? ? ? ? ? ? ? ? mBasePackageName, ? ? ? ? ? ? ? ? ? // 包名標識? ? ? ? ? ? ? ? getAttributionTag(), ? ? ? ? ? ? ? ?// 歸因標簽(用于權限跟蹤)? ? ? ? ? ? ? ? AppOpsManager.toReceiverId(receiver), // 接收器唯一ID? ? ? ? ? ? ? ? rd, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 跨進程回調接口? ? ? ? ? ? ? ? filter, ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 意圖過濾器? ? ? ? ? ? ? ? broadcastPermission, ? ? ? ? ? ? ? // 所需權限? ? ? ? ? ? ? ? userId, ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 用戶ID? ? ? ? ? ? ? ? flags); ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 標志位[5](@ref)? ? ? ? // 3. 處理返回的粘性廣播(若存在)? ? ? ? if (intent != null) {? ? ? ? ? ? intent.setExtrasClassLoader(getClassLoader());? ? ? ? ? ? // 3.1 準備Intent數據安全傳輸到應用進程? ? ? ? ? ? intent.prepareToEnterProcess(? ? ? ? ? ? ? ? ActivityThread.isProtectedBroadcast(intent),? ? ? ? ? ? ? ? getAttributionSource()); // 檢查簽名權限保護[3](@ref)? ? ? ? }? ? ? ? return intent;? ? } catch (RemoteException e) {? ? ? ? throw e.rethrowFromSystemServer(); // 處理Binder通信異常? ? }}

通過 LoadedApk.getReceiverDispatcher() 將 BroadcastReceiver 包裝為 IIntentReceiver(Binder接口),內部創建 ReceiverDispatcher 和 InnerReceiver(IIntentReceiver.Stub 實現類),構成雙向通信橋梁

獲取廣播分發器 getReceiverDispatcher

橋接BroadcastReceiver和Binder通信,含InnerReceiver和Handler?????

/**?* 為BroadcastReceiver創建/獲取跨進程通信的IIntentReceiver對象?* @param r 開發者定義的廣播接收器實例?* @param context 關聯的Context對象(通常為Activity/Service)?* @param handler 指定回調線程的Handler(主線程Handler)?* @param instrumentation 測試工具類(正常場景為null)?* @param registered 是否為持久化注冊(動態注冊通常為true)?* @return IIntentReceiver Binder接口對象,用于AMS跨進程回調?*/public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,? ? ? ? Context context, Handler handler,? ? ? ? Instrumentation instrumentation, boolean registered) {? ? // 線程安全:通過synchronized保護mReceivers數據結構? ? synchronized (mReceivers) {? ? ? ? LoadedApk.ReceiverDispatcher rd = null;? ? ? ? ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;? ? ? ? // 1. 嘗試從緩存中獲取已注冊的ReceiverDispatcher? ? ? ? if (registered) {? ? ? ? ? ? // 1.1 獲取當前Context對應的接收器映射表? ? ? ? ? ? map = mReceivers.get(context); ?// mReceivers: ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>? ? ? ? ? ? if (map != null) {? ? ? ? ? ? ? ? rd = map.get(r); ?// 檢查是否已存在相同接收器的Dispatcher? ? ? ? ? ? }? ? ? ? }? ? ? ? // 2. 緩存未命中時創建新對象? ? ? ? if (rd == null) {? ? ? ? ? ? // 2.1 構造ReceiverDispatcher(含跨進程Binder對象)? ? ? ? ? ? rd = new ReceiverDispatcher(? ? ? ? ? ? ? ? mActivityThread.getApplicationThread(), // IApplicationThread對象? ? ? ? ? ? ? ? r, ?// 用戶定義的BroadcastReceiver? ? ? ? ? ? ? ? context,? ? ? ? ? ? ? ? handler, ?// 主線程Handler(確保onReceive在主線程執行)? ? ? ? ? ? ? ? instrumentation,? ? ? ? ? ? ? ? registered? ? ? ? ? ? );? ? ? ? ? ? // 2.2 持久化注冊時加入緩存? ? ? ? ? ? if (registered) {? ? ? ? ? ? ? ? if (map == null) {? ? ? ? ? ? ? ? ? ? map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();? ? ? ? ? ? ? ? ? ? mReceivers.put(context, map); ?// 建立Context到接收器映射的關系? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? map.put(r, rd); ?// 緩存鍵:BroadcastReceiver對象? ? ? ? ? ? }? ? ? ? } else {? ? ? ? ? ? // 3. 緩存命中時校驗有效性? ? ? ? ? ? rd.validate(context, handler); ?// 檢查Context和Handler是否匹配? ? ? ? }? ? ? ? // 4. 標記為活躍狀態(防止被意外回收)? ? ? ? rd.mForgotten = false;? ? ? ? // 5. 返回InnerReceiver(IIntentReceiver.Stub的實現類)? ? ? ? return rd.getIIntentReceiver();? ? }}

AMS注冊廣播接收器方法

動態注冊核心步驟

ReceiverList管理:同一IIntentReceiver Binder對象對應一個ReceiverList,避免重復注冊。

BroadcastFilter注冊:將廣播過濾器加入全局mReceiverResolver,后續廣播分發時快速匹配

private Intent registerReceiverWithFeatureTraced(IApplicationThread caller, String callerPackage,?? ? ? ? String callerFeatureId, String receiverId, IIntentReceiver receiver,?? ? ? ? IntentFilter filter, String permission, int userId, int flags) {? ? // 1. 權限與調用者驗證? ? enforceNotIsolatedCaller("registerReceiver"); // 禁止隔離進程調用? ? ProcessRecord callerApp = getRecordForAppLOSP(caller); // 獲取調用者進程記錄? ? // 驗證調用者包名與進程匹配性(防止偽造身份)? ? if (!UserHandle.isCore(callerApp.info.uid) && !callerApp.getPkgList().containsKey(callerPackage)) {? ? ? ? throw new SecurityException("Package/Process mismatch");? ? }? ? // 2. 用戶ID處理與優先級檢查? ? userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, ...);? ? if (UserHandle.isCore(callingUid)) {? ? ? ? // 系統進程注冊重要廣播時需設置優先級(如USER_ACTION/PACKAGE_ACTION等)? ? ? ? if (filter.getPriority() == 0) {? ? ? ? ? ? filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); // 默認高優先級? ? ? ? }? ? }? ? // 3. 粘性廣播(Sticky Broadcast)匹配? ? ArrayList<StickyBroadcast> stickyBroadcasts = null;? ? synchronized (mStickyBroadcasts) {? ? ? ? // 遍歷IntentFilter的Action,查找匹配的粘性廣播? ? ? ? for (String action : filter.actionsIterator()) {? ? ? ? ? ? for (int userId : {UserHandle.USER_ALL, callingUserId}) {? ? ? ? ? ? ? ? ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId);? ? ? ? ? ? ? ? if (stickies != null && stickies.containsKey(action)) {? ? ? ? ? ? ? ? ? ? stickyBroadcasts.addAll(stickies.get(action)); // 收集匹配的粘性廣播? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }? ? }? ? // 4. 動態接收器注冊核心邏輯? ? synchronized (this) {? ? ? ? // 4.1 創建或獲取ReceiverList(同一Binder對象對應一個ReceiverList)? ? ? ? ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());? ? ? ? if (rl == null) {? ? ? ? ? ? rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver);? ? ? ? ? ? if (rl.app != null) {? ? ? ? ? ? ? ? rl.app.mReceivers.addReceiver(rl); // 關聯到進程記錄? ? ? ? ? ? } else {? ? ? ? ? ? ? ? receiver.asBinder().linkToDeath(rl, 0); // 跨進程死亡監聽? ? ? ? ? ? }? ? ? ? ? ? mRegisteredReceivers.put(receiver.asBinder(), rl); // 全局注冊表記錄? ? ? ? }? ? ? ? // 4.2 創建BroadcastFilter并注冊到Resolver? ? ? ? BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, ...);? ? ? ? if (!rl.containsFilter(filter)) {? ? ? ? ? ? rl.add(bf); // 添加到ReceiverList? ? ? ? ? ? mReceiverResolver.addFilter(bf); // 注冊到全局過濾器? ? ? ? }? ? ? ? // 5. 處理匹配的粘性廣播(立即分發給新注冊的接收器)? ? ? ? if (stickyBroadcasts != null) {? ? ? ? ? ? ArrayList<BroadcastFilter> receivers = new ArrayList<>();? ? ? ? ? ? receivers.add(bf);? ? ? ? ? ? for (StickyBroadcast broadcast : stickyBroadcasts) {? ? ? ? ? ? ? ? // 創建廣播記錄并加入隊列? ? ? ? ? ? ? ? BroadcastRecord r = new BroadcastRecord(..., broadcast.intent, ..., receivers);? ? ? ? ? ? ? ? mBroadcastQueue.enqueueBroadcastLocked(r); // 異步分發? ? ? ? ? ? }? ? ? ? }? ? ? ? return stickyBroadcasts != null ? stickyBroadcasts.get(0).intent : null; // 返回首個粘性Intent? ? }}

廣播注冊流程中的LoaderApk和AMS的數據結構關系圖

0

廣播注冊流程小結

1. App進程:打包“快遞員”

需求發起:App調用registerReceiver,就像下單寄快遞,告訴系統要接收哪種廣播(IntentFilter)

包裝處理:

ReceiverDispatcher:系統把開發者寫的BroadcastReceiver打包成“快遞員”,負責跨進程送貨(IIntentReceiver接口)

InnerReceiver:這個“快遞員”有個Binder工牌(IIntentReceiver.Stub),AMS憑工牌找到App的家(主線程)送貨

2. 跨進程:向AMS“登記收貨地址”

Binder快遞:把“快遞員”的工牌和收貨要求(IntentFilter)通過Binder寄給AMS(registerReceiverWithFeature)

防重復注冊:AMS用工牌(Binder對象)當身份證,檢查是否已登記過,避免重復注冊

3. AMS:建立“收貨檔案”

檔案管理:

ReceiverList:以Binder工牌為Key,建一個“收貨清單”,記錄同一接收器的所有過濾條件

BroadcastFilter:把IntentFilter和接收器綁定,存到全局“快遞分揀系統”(mReceiverResolver)

粘性廣播:如果歷史廣播中有匹配的“包裹”,直接塞進分發隊列(mBroadcastQueue)馬上派送

關鍵角色比喻

組件

比喻

作用

ReceiverDispatcher

快遞員+物流單

連接App和AMS,確保廣播送到主線程

mRegisteredReceivers

客戶檔案庫

用Binder工牌管理所有注冊的接收器,避免重復

mReceiverResolver

智能分揀機

根據IntentFilter快速匹配接收器,類似快遞分揀中心

mBroadcastQueue

快遞派送車

分前臺/后臺/離線三種車隊,決定廣播的派送優先級

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915619.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915619.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915619.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenCV計算機視覺實戰(16)——圖像分割技術

OpenCV計算機視覺實戰&#xff08;16&#xff09;——圖像分割技術0. 前言1. 分水嶺算法1.1 應用場景1.2 實現過程2. GrabCut 交互式分割2.1 應用場景2.2 實現過程3. FloodFill3.1 應用場景3.2 實現過程小結系列鏈接0. 前言 圖像分割是計算機視覺中將像素劃分為具有特定語義或…

Coturn打洞服務器

* 概念理解&#xff1a;1. SDP協議&#xff1a;會話描述協議&#xff0c;視頻通話的雙方通過交換SDP信息進行媒體協商&#xff0c;從而選擇使用某一相同的媒體協議進行通信&#xff1b;TLS協議&#xff1a;基于TCP的安全層傳輸協議DTLS協議&#xff1a;基于UDP的安全層傳輸協議…

python flusk 監控

# 創建虛擬環境目錄 python3 -m venv /sda1/xunjian/venv # 激活虛擬環境 source /sda1/xunjian/venv/bin/activate # 激活后終端會顯示 (venv)創建虛擬環境&#xff08;在當前目錄&#xff09;&#xff1a;bashpython3 -m venv venv激活虛擬環境&#xff1a;bashsource venv/b…

VUE2 項目學習筆記 ? 語法 v-if/v-show

?語法頁面渲染的時候&#xff0c;需要服務器傳過來的對象中的一個屬性&#xff0c;然后根據這個屬性用v-for渲染標簽&#xff0c;這里寫的v-for".... in dataList.goodsList"但是當解析到這行語法的時候&#xff0c;dataList還沒返回&#xff0c;因此控制臺會報錯找…

使用qemu命令啟動虛擬機

1. 安裝相關軟件 yum install qemu edk2* libvirt -y 啟動libvirt服務 systemctl start libvirtd systemctl status libvirtd2. 創建虛擬機 2.1. qemu啟動命令示例 /usr/bin/qemu-system-loongarch64 \-machine virt,accelkvm \-nodefaults \-m 2048 \-smp 2,maxcpus4,co…

大模型系統化學習路線

人工智能大模型系統化學習路線一、基礎理論筑基&#xff08;1-2個月) 目標&#xff1a;建立大模型核心認知框架 核心內容&#xff1a; 深度學習基礎&#xff1a;神經網絡原理、CNN/RNN結構、梯度下降算法大模型本質&#xff1a;Transformer架構&#xff08;重點掌握注意力機制、…

LLaMA-Factory 微調可配置的模型基本參數

LLaMA-Factory 微調可配置的模型基本參數 flyfish 基本參數 一、模型加載與路徑配置參數名類型描述默認值model_name_or_pathOptional[str]模型路徑&#xff08;本地路徑或 Huggingface/ModelScope 路徑&#xff09;。Noneadapter_name_or_pathOptional[str]適配器路徑&#xf…

Ubuntu 22 安裝 ZooKeeper 3.9.3 記錄

Ubuntu 22 安裝 ZooKeeper 3.9.3 記錄 本文記錄在 Ubuntu 22.04 系統上安裝 ZooKeeper 3.9.3 的過程&#xff0c;包含 Java 環境準備、配置文件調整、啟動與停機操作、以及如何將 ZooKeeper 注冊為系統服務。 一、準備環境 ZooKeeper 3.9.x 要求 Java 11 或更高版本&#xff…

FreeSwitch通過Websocket(流式雙向語音)對接AI實時語音大模型技術方案(mod_ppy_aduio_stream)

FreeSwitch通過WebSocket對接AI實時語音大模型插件技術方案1. 方案概述 基于FreeSWITCH的實時通信能力&#xff0c;通過WebSocket協議橋接AI大模型服務&#xff0c;實現低延遲、高并發的智能語音交互系統。支持雙向語音流處理、實時ASR/TTS轉換和動態業務指令執行。 1753095153…

航班調度優化策略全局概覽

在機場關閉場景下的航班恢復工作&#xff0c;是將機場關閉期間所有的航班進行取消然后恢復還是將機場關閉期間航班全部延誤而后調整呢&#xff1f;簡單來說&#xff0c;在實際操作中&#xff0c;既不是無差別地全部取消&#xff0c;也不是無差別地全部延誤。這兩種“一刀切”的…

spring boot 異步線程@Async 傳遞 threadLocal數據

將父類的 threadLocal 的數據 在線程池時&#xff0c;可以轉給子線程使用。 Async 的使用。 第一步在啟動服務加上 EnableAsync 注解。 EnableAsync public class NetCoreApplication {... ... }第二步&#xff1a;導入阿里 線程工具類<dependency><groupId>com.a…

AI產品經理成長記《零號列車》第一集 邂逅0XAI列車

《零號列車》絕非傳統意義上的 AI 產品經理教程 —— 它是我沉淀二十多年跨行業數字化轉型與工業 4.0 實戰經驗后,首創的100集大型小說體培養指南。那些曾在千行百業驗證過的知識與經驗,不再是枯燥的文字堆砌,而是化作一場沉浸式的學習旅程。? 這里沒有生硬的理論灌輸,而…

[C++11]范圍for循環/using使用

范圍for循環 范圍for循環&#xff08;Range-based for loop&#xff09;是 C11 引入的一種簡潔的循環語法&#xff0c;用于遍歷容器中的元素或者其他支持迭代的數據結構。 范圍for循環可以讓代碼更加簡潔和易讀&#xff0c;避免了傳統for循環中索引的操作。 下面是范圍for循環的…

簡單了解下npm、yarn 和 pnpm 中 add 與 install(i) 命令的區別(附上兩圖帶你一目明了)

目錄 pnpm 中 add 和 i 的區別 npm 中 add 和 i 的區別 yarn 中 add 和 i 的區別 附上兩圖帶你一目明了&#xff1a; npm、yarn和pnpm的三者區別圖&#xff1a; i 和 add 的核心區別圖&#xff1a; 個人建議&#xff1a;在項目中保持命令使用的一致性&#xff0c;選擇一種…

ESP32-S3學習筆記<2>:GPIO的應用

ESP32-S3學習筆記&#xff1c;2&#xff1e;&#xff1a;GPIO的應用1. 頭文件包含2. GPIO的配置2.1 pin_bit_mask2.2 mode2.3 pull_up_en和pull_down_en2.4 intr_type3. 設置GPIO輸出/獲取GPIO輸入4. 中斷的使用4.1 gpio_install_isr_service4.2 gpio_isr_handler_add4.3 gpio_…

得物視覺算法面試30問全景精解

得物視覺算法面試30問全景精解 ——潮流電商 商品鑒別 視覺智能&#xff1a;得物視覺算法面試核心考點全覽 前言 得物App作為中國領先的潮流電商與鑒別平臺&#xff0c;持續推動商品識別、真假鑒別、圖像搜索、內容審核、智能推薦等視覺AI技術的創新與落地。得物視覺算法崗位…

[Linux入門] Linux 賬號和權限管理入門:從基礎到實踐

一、Linux 用戶賬號&#xff1a;誰能訪問系統&#xff1f; 1??超級用戶&#xff08;root&#xff09; 2??普通用戶 3??程序用戶 二、組賬號&#xff1a;讓用戶管理更高效 1??組的類型 2??特殊組 三、用戶與組的 “身份證”&#xff1a;UID 和 GID 四、配置文…

阿里云ssl證書自動安裝及續訂(acme)

目錄 一、shell命令安裝 二、docker run安裝 三、docker compose安裝 一、shell命令安裝 # 安裝acme curl https://get.acme.sh | sh -s emailfloxxx5163.com# 注冊zerossl .acme.sh/acme.sh --register-account -m flowxxx25163.com --server zerossl# 獲取證書 export Al…

@fullcalendar/vue 日歷組件

功能&#xff1a;日程安排&#xff0c;展示日歷&#xff0c;可以用來做會議日歷&#xff0c;可以跨日期顯示日程。 Fullcalendarvue3 日歷組件 參考文檔&#xff1a;【vue2】一個完整的日歷組件 fullcalendar&#xff0c;會議預約功能 中文說明文檔&#xff1a;https://www.he…

Dijkstra 算法求解多種操作

一、問題背景與核心需求 需要找到從a到b的最優操作序列&#xff0c;使得總花費最小。三種操作的規則為&#xff1a; 操作 1&#xff1a;x → x1&#xff0c;花費c1&#xff1b;操作 2&#xff1a;x → x-1&#xff0c;花費c2&#xff1b;操作 3&#xff1a;x → x*2&#xff0…