Android Framework底層原理之WMS的啟動流程

一 概述

今天,我們介紹 WindowManagerService(后續簡稱 WMS)的啟動流程,WMS 是 Android 系統中,負責窗口顯示的的服務。在 Android 中它也起著承上啟下的作用。

如下圖,就是《深入理解 Android》書籍中的一張圖。

圖中展示了,WMS 在 Android 系統的地位,它作為中間層,連接了上層的 View 框架和下層的 SurfaceFingler。了解了 WMS 的工作機制,我們就徹底打通了上層 VIew 到底層 Surface,甚至到顯示器如何顯示的邏輯。

接下來,我們依舊從 WMS 的啟動開始,來看 WMS 是如何啟動的。

二 從 SystemServer 開始

2.1 startOtherServices

[frameworks/base/services/java/com/android/server/SystemServer.java]
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {WindowManagerService wm = null;// 這里傳入的 PhoneWindowManager 就是 WMS 中的 WindowManagerPolicywm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);// 將 WMS 設置到 AMS 中mActivityManagerService.setWindowManager(wm);wm.onInitReady();...try {wm.displayReady();} catch (Throwable e) {reportWtf("making display ready", e);}...try {wm.systemReady();} catch (Throwable e) {reportWtf("making Window Manager Service ready", e);}...// 更新上下文中,關于顯示窗口相關的屬性final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);DisplayMetrics metrics = new DisplayMetrics();context.getDisplay().getMetrics(metrics);context.getResources().updateConfiguration(config, metrics);}

和 AMS 不同的是,WMS 的啟動是在 SystemServer 的 startOtherServices 中,啟動過程依舊是我們之前提過的構造、注冊,只是少了 onStart 這個步驟。

并且,在 WMS 啟動之后,還會陸續調用一些其他的函數

  • onInitReady
  • displayReady
  • systemReady
  • updateConfiguration

接下來,我們會根據 WMS 啟動過程中調用的函數,以此查看它們具體的實現原理。

從 AMS 和 WMS 的啟動,我們可以看出來,它們都是隸屬于 SystemServer 進程的,根據之前我們對應用和 AMS 的了解,也經常看到它們交互的流程中,有 WMS 的身影,所以雖然說是應用和 AMS,WMS 的通信,實際上就是應用和 SystemServer 進程的通信。

2.2 main

[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm) {return main(context, im, showBootMsgs, onlyCore, policy, atm,new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,SurfaceControl.Builder::new);
}public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, DisplayWindowSettingsProviderdisplayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {DisplayThread.getHandler().runWithScissors(() ->sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,surfaceControlFactory), 0);return sInstance;
}

在 WMS 的 main 函數中主要做了兩件事

  1. 創建了一個 WMS 對象
  2. 將這個 WMS 對象傳遞給了 DisplayThread

我們首先看這個 WMS 對象的構造函數

三 WindowManagerService

3.1 WMS 的構造函數

private WindowManagerService(Context context, InputManagerService inputManager,boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, DisplayWindowSettingsProviderdisplayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {installLock(this, INDEX_WINDOW);// ActivityTaskManagerServicemGlobalLock = atm.getGlobalLock();mAtmService = atm;mContext = context;mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);mAllowBootMessages = showBootMsgs;...// 輸入法管理mInputManager = inputManager; // Must be before createDisplayContentLocked.// 顯示管理mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);// Surface 圖像相關mSurfaceControlFactory = surfaceControlFactory;mTransactionFactory = transactionFactory;mSurfaceFactory = surfaceFactory;mTransaction = mTransactionFactory.get();mPolicy = policy;// 窗口動畫mAnimator = new WindowAnimator(this);// 根窗口容器mRoot = new RootWindowContainer(this);final ContentResolver resolver = context.getContentResolver();mUseBLAST = Settings.Global.getInt(resolver,Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, 1) == 1;mSyncEngine = new BLASTSyncEngine(this);mWindowPlacerLocked = new WindowSurfacePlacer(this);mTaskSnapshotController = new TaskSnapshotController(this);mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,Choreographer.getInstance());LocalServices.addService(WindowManagerPolicy.class, mPolicy);mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);mKeyguardDisableHandler = KeyguardDisableHandler.create(mContext, mPolicy, mH);mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);if (mPowerManagerInternal != null) {mPowerManagerInternal.registerLowPowerModeObserver(new PowerManagerInternal.LowPowerModeListener() {@Overridepublic int getServiceType() {return ServiceType.ANIMATION;}@Overridepublic void onLowPowerModeChanged(PowerSaveState result) {synchronized (mGlobalLock) {final boolean enabled = result.batterySaverEnabled;if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {mAnimationsDisabled = enabled;dispatchNewAnimatorScaleLocked(null);}}}});mAnimationsDisabled = mPowerManagerInternal.getLowPowerState(ServiceType.ANIMATION).batterySaverEnabled;}mScreenFrozenLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");mScreenFrozenLock.setReferenceCounted(false);mDisplayNotificationController = new DisplayWindowListenerController(this);// AMS 相關mActivityManager = ActivityManager.getService();mActivityTaskManager = ActivityTaskManager.getService();mAmInternal = LocalServices.getService(ActivityManagerInternal.class);mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);... 
}

WMS 的構造函數的代碼非常長,其中有包含各種服務,我們這里只關注和我們應用 Activity 相關的,還有和顯示相關的窗口容器 RootWindowContainer,還有和刷新相關的 Surface

3.2 runWithScissors

另外,在 main 函數中,還調用了一個 runWithScissors,這個函數是 Handler 中定義的函數,這里我們簡單看一下。

public final boolean runWithScissors(@NonNull Runnable r, long timeout) {if (r == null) {throw new IllegalArgumentException("runnable must not be null");}if (timeout < 0) {throw new IllegalArgumentException("timeout must be non-negative");}if (Looper.myLooper() == mLooper) {r.run();return true;}BlockingRunnable br = new BlockingRunnable(r);return br.postAndWait(this, timeout);
}

runWithScissors 是 Handler 中的函數,用一句話概括就是,如果發送消息的線程與 Handler 處理的線程相同,就直接調用。如果不同,就阻塞調用

3.3 onInitReady

public void onInitReady() {initPolicy();// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);createWatermark();showEmulatorDisplayOverlayIfNeeded();
}

3.4 initPolicy

private void initPolicy() {UiThread.getHandler().runWithScissors(new Runnable() {@Overridepublic void run() {WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());// mPolicy 其實就是 PhoneWindowManager【5.1】mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);}}, 0);
}

mPolicy 其實是 PhoneWindowManager,runWithScissors 前面介紹過了,如果是當前線程,就直接運行,如果不是當前線程,就阻塞運行。

所以這里是在 android.ui 線程中,運行 mPolicy 的初始化邏輯

3.5 createWatermark

void createWatermark() {if (mWatermark != null) {return;}File file = new File("/system/etc/setup.conf");FileInputStream in = null;DataInputStream ind = null;try {in = new FileInputStream(file);ind = new DataInputStream(in);String line = ind.readLine();if (line != null) {String[] toks = line.split("%");if (toks != null && toks.length > 0) {// TODO(multi-display): Show watermarks on secondary displays.final DisplayContent displayContent = getDefaultDisplayContentLocked();mWatermark = new Watermark(displayContent, displayContent.mRealDisplayMetrics,toks, mTransaction);mTransaction.apply();}}} ...
}

createWatermark 創建系統水印(只能顯示文字)。

3.6 displayReady

[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public void displayReady() {synchronized (mGlobalLock) {if (mMaxUiWidth > 0) {mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));}applyForcedPropertiesForDefaultDisplay();mAnimator.ready();mDisplayReady = true;// createWatermark重新配置所有顯示器大小mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);// 是否觸屏mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);}try {// ATMSmActivityTaskManager.updateConfiguration(null);} catch (RemoteException e) {}
}

displayReady 就是初始化顯示器大小。

3.7 systemReady

[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public void systemReady() {mSystemReady = true;// 調用 PhoneWindowManager 的 systemReadymPolicy.systemReady();// 調用 DisplayPolicy 的 systemReadymRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);// 調用 TaskSnapshotController 的 systemReadymTaskSnapshotController.systemReady();mHasWideColorGamutSupport = queryWideColorGamutSupport();mHasHdrSupport = queryHdrSupport();// 加載系統設置UiThread.getHandler().post(mSettingsObserver::loadSettings);// VRIVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(Context.VR_SERVICE));if (vrManager != null) {try {final boolean vrModeEnabled = vrManager.getVrModeState();synchronized (mGlobalLock) {vrManager.registerListener(mVrStateCallbacks);if (vrModeEnabled) {mVrModeEnabled = vrModeEnabled;mVrStateCallbacks.onVrStateChanged(vrModeEnabled);}}} catch (RemoteException e) {// Ignore, we cannot do anything if we failed to register VR mode listener}}
}

3.8 computeNewConfiguration

public Configuration computeNewConfiguration(int displayId) {synchronized (mGlobalLock) {return computeNewConfigurationLocked(displayId);}
}

3.9 computeNewConfigurationLocked

private Configuration computeNewConfigurationLocked(int displayId) {if (!mDisplayReady) {return null;}final Configuration config = new Configuration();final DisplayContent displayContent = mRoot.getDisplayContent(displayId);displayContent.computeScreenConfiguration(config);return config;
}

displayId 表示的是顯示設備的 id,這兩段代碼,就是通過 mRoot(RootWindowContainer)獲取顯示指定設備的 DisplayContent。說人話就是,通過顯示器的 id,獲取顯示器對應的實例類 DisplayContent

四 DisplayThread

[frameworks/base/services/core/java/com/android/server/DisplayThread.java]
public final class DisplayThread extends ServiceThread {private static DisplayThread sInstance;private static Handler sHandler;private DisplayThread() {// DisplayThread 運行重要的東西,但 AnimationThread 更重要。因此,優先級設置為 THREAD_PRIORITY_DISPLAY + 1// THREAD_PRIORITY_DISPLAY 的值為 -4,super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);}

DisplayThread 就是 Android 中的 android.display 線程,它的優先級為 THREAD_PRIORITY_DISPLAY + 1,THREAD_PRIORITY_DISPLAY 值為 -4,所以 android.display 線程的優先級是 -3。

再回到 【2.2】中,WMS 的 main 函數是通過 android.display 線程完成的,并且在 android.display 線程中,對 android.ui 線程進行了初始化。

五 UIThread

public final class UiThread extends ServiceThread {private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;private static UiThread sInstance;private static Handler sHandler;private UiThread() {super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);}@Overridepublic void run() {// Make sure UiThread is in the fg stune boost groupProcess.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);super.run();}

UiThread 和 DisplayThread 一樣,也是繼承自 ServiceThread,它的線程名是 android.ui,優先級是 THREAD_PRIORITY_FOREGROUND,值為-2,所以 android.ui 線程的優先級是 -2。

六 PhoneWindowManager

PhoneWindowManager 是 WindowManagerPolicy 的實現類,它定義了手機窗口、處理輸入事件以及與系統 UI 交互的策略和行為。

PhoneWindowManager 中的函數有很多,這里我們列舉一個,其中的按鍵分發的函數 interceptKeyBeforeQueueing。

6.1 interceptKeyBeforeQueueing

[frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java]
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {final int keyCode = event.getKeyCode();final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0|| event.isWakeKey();if (!mSystemBooted) {// 系統啟動前,只監聽電源按鍵if (down && (keyCode == KeyEvent.KEYCODE_POWER|| keyCode == KeyEvent.KEYCODE_TV_POWER)) {wakeUpFromPowerKey(event.getDownTime());} else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)&& isWakeKeyWhenScreenOff(keyCode)) {wakeUpFromWakeKey(event);}// 攔截掉電源鍵return 0;}// interceptKeyBeforeQueueing 主要就是對手機按鍵的事件攔截,這里我們簡單列舉幾個// 返回鍵,音量鍵等等。switch (keyCode) {case KeyEvent.KEYCODE_BACK: {if (down) {mBackKeyHandled = false;} else {if (!hasLongPressOnBackBehavior()) {mBackKeyHandled |= backKeyPress();}// Don't pass back press to app if we've already handled it via long pressif (mBackKeyHandled) {result &= ~ACTION_PASS_TO_USER;}}break;}case KeyEvent.KEYCODE_VOLUME_DOWN:case KeyEvent.KEYCODE_VOLUME_UP:

返回值是一個整型,如果是 0 就表示被攔截,一開始的電源按鍵我們就看到了,在系統沒有啟動前,電源按鍵只能用于系統啟動,但是系統啟動后,電源按鍵就可以用于其他的作用了,例如語音助手。

PhoneWindowManager 這個類主要的作用有:

  1. 按鍵的分發
  2. 窗口的管理

這里我們就不擴展了,后面遇到實際的場景再來說明。

七 總結

WMS 的啟動流程比較簡單,主要就是啟動了兩個線程 "android.display""android.ui"

如果你還沒有掌握Framework,現在想要在最短的時間里吃透它,可以參考一下《Android Framework核心知識點》,里面內容包含了:Init、Zygote、SystemServer、Binder、Handler、AMS、PMS、Launcher……等知識點記錄。

《Framework 核心知識點匯總手冊》:https://qr18.cn/AQpN4J

Handler 機制實現原理部分:
1.宏觀理論分析與Message源碼分析
2.MessageQueue的源碼分析
3.Looper的源碼分析
4.handler的源碼分析
5.總結

Binder 原理:
1.學習Binder前必須要了解的知識點
2.ServiceManager中的Binder機制
3.系統服務的注冊過程
4.ServiceManager的啟動過程
5.系統服務的獲取過程
6.Java Binder的初始化
7.Java Binder中系統服務的注冊過程

Zygote :

  1. Android系統的啟動過程及Zygote的啟動過程
  2. 應用進程的啟動過程

AMS源碼分析?:

  1. Activity生命周期管理
  2. onActivityResult執行過程
  3. AMS中Activity棧管理詳解

深入PMS源碼:

1.PMS的啟動過程和執行流程
2.APK的安裝和卸載源碼分析
3.PMS中intent-filter的匹配架構

WMS:
1.WMS的誕生
2.WMS的重要成員和Window的添加過程
3.Window的刪除過程

《Android Framework學習手冊》:https://qr18.cn/AQpN4J

  1. 開機Init 進程
  2. 開機啟動 Zygote 進程
  3. 開機啟動 SystemServer 進程
  4. Binder 驅動
  5. AMS 的啟動過程
  6. PMS 的啟動過程
  7. Launcher 的啟動過程
  8. Android 四大組件
  9. Android 系統服務 - Input 事件的分發過程
  10. Android 底層渲染 - 屏幕刷新機制源碼分析
  11. Android 源碼分析實戰

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

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

相關文章

033_小馳私房菜_Qcom平臺8系列-Dump Jpeg Jpeg Exif信息修改

全網最具價值的Android Camera開發系列資料~ 作者:8年Android Camera開發,從Camera app一直做到Hal和驅動~ 歡迎訂閱,相信能擴展你的知識面,提升個人能力~ 平臺:高通8系列 jpeg相關代碼邏輯在camx/src/swl/jpeg/ 路徑下 一、Dump Jpeg 有時我們想把hal這邊拍照的jpe…

【C++】STL初識

1.STL的基本概念 2.vector存放內置數據類型 #include <iostream> using namespace std; #include <vector> #include <algorithm>void MyPrint(int val) {cout << val << endl; }void test01() {//創建vector容器對象&#xff0c;并且通過模板參…

Harbor企業鏡像倉庫部署(本地)

簡述&#xff1a; Docker 官方鏡像倉庫是用于管理公共鏡像的地方&#xff0c;大家可以在上面找到想要的鏡像&#xff0c;也可以把自己的鏡像推送上去。但是有時候服務器無法訪問互聯網&#xff0c;或者不希望將自己的鏡像放到互聯網上&#xff0c;那么就需要用到 Docker Regis…

越南的區塊鏈和NFT市場調研

越南的區塊鏈和NFT市場調研 基本介紹 https://zh.wikipedia.org/wiki/%E8%B6%8A%E5%8D%97 語言文字&#xff1a; 越南語&#xff0c; 文字以國語字&#xff08;越南羅馬字&#xff09;為主&#xff0c;漢喃文&#xff08;漢字&#xff09; 貨幣&#xff1a;越南盾 人口(2022…

Leetcode-每日一題【劍指 Offer 15. 二進制中1的個數】

題目 編寫一個函數&#xff0c;輸入是一個無符號整數&#xff08;以二進制串的形式&#xff09;&#xff0c;返回其二進制表達式中數字位數為 1 的個數&#xff08;也被稱為 漢明重量).&#xff09;。 提示&#xff1a; 請注意&#xff0c;在某些語言&#xff08;如 Java&…

如何安全地移動WSL 2 到另一個驅動器

當您擁有小型 SSD 并且適用于 Linux 的 Windows 子系統 (WSL) 的大小呈指數增長時&#xff0c;這真的很痛苦。沒有簡單的方法將 WSL 安裝移動到另一個驅動器。在這篇博客中&#xff0c;我將討論如何通過小步解決這個問題。 1.打開具有管理員訪問權限的 PowerShell或命令提示符…

【Docker】Windows下docker環境搭建及解決使用非官方終端時的連接問題

目錄 背景 Windows Docker 安裝 安裝docker toolbox cmder 解決cmder 連接失敗問題 資料獲取方法 背景 時常有容器方面的需求&#xff0c;經常構建調試導致測試環境有些混亂&#xff0c;所以想在本地構建一套環境&#xff0c;鏡像調試穩定后再放到測試環境中。 Windows …

多線程與高并發--------線程池

線程池 一、什么是線程池 在開發中&#xff0c;為了提升效率的操作&#xff0c;我們需要將一些業務采用多線程的方式去執行。 比如有一個比較大的任務&#xff0c;可以將任務分成幾塊&#xff0c;分別交給幾個線程去執行&#xff0c;最終做一個匯總就可以了。 比如做業務操…

Windows電腦快速搭建FTP服務教程

FTP介紹 FTP&#xff08;File Transfer Protocol&#xff09;是一種用于在計算機網絡上進行文件傳輸的標準協議。它提供了一種可靠的、基于客戶端-服務器模型的方式來將文件從一個主機傳輸到另一個主機。在本文中&#xff0c;我將詳細介紹FTP的工作原理、數據傳輸模式以及常見…

數據結構【第4章】——棧與隊列

隊列是只允許在一端進行插入操作、而在另-端進行刪除操作的線性表。 棧 棧與隊列&#xff1a;棧是限定僅在表尾進行插入和刪除操作的線性表。 我們把允許插入和刪除的一端稱為棧頂&#xff08;top&#xff09;&#xff0c;另一端稱為棧底&#xff08;bottom&#xff09;&…

VBA技術資料MF42:VBA_從Excel中上面的單元格復制公式

【分享成果&#xff0c;隨喜正能量】唯有夢想才配讓你不安&#xff0c;唯有行動才能解除你的不安.繩鋸木斷&#xff0c;水滴石穿。也許你現在做的事情很小&#xff0c;只要你能日積月累的堅持下去&#xff0c;才會發現意義非凡。所謂的成功&#xff0c;便是別人失敗的時候你還在…

微服務與Nacos概述-2

微服務間消息傳遞 微服務是一種軟件開發架構&#xff0c;它將一個大型應用程序拆分為一系列小型、獨立的服務。每個服務都可以獨立開發、部署和擴展&#xff0c;并通過輕量級的通信機制進行交互。 應用開發 common模塊中包含服務提供者和服務消費者共享的內容 provider模塊是…

10-1_Qt 5.9 C++開發指南_Data Visualization實現數據三維顯示

Data Visualization 是 Qt 提供的用于數據三維顯示的模塊。在 Qt 5.7 以前只有商業版才有此模塊&#xff0c;而從Qt5.7 開始此模塊在社區版本里也可以免費使用了。Data Visualization 用于數據的三維顯示&#xff0c;包括三維柱狀圖、三維空間散點、三維曲面等。Data Visualiza…

鑒源實驗室丨汽車網絡安全攻擊實例解析(二)

作者 | 田錚 上海控安可信軟件創新研究院項目經理 來源 | 鑒源實驗室 社群 | 添加微信號“TICPShanghai”加入“上海控安51fusa安全社區” 引言&#xff1a;汽車信息安全事件頻發使得汽車行業安全態勢愈發緊張。這些汽車網絡安全攻擊事件&#xff0c;輕則給企業產品發布及產品…

高效數據傳輸:輕松上手將Kafka實時數據接入CnosDB

本篇我們將主要介紹如何在 Ubuntu 22.04.2 LTS 環境下&#xff0c;實現一個KafkaTelegrafCnosDB 同步實時獲取流數據并存儲的方案。在本次操作中&#xff0c;CnosDB 版本是2.3.0&#xff0c;Kafka 版本是2.5.1&#xff0c;Telegraf 版本是1.27.1 隨著越來越多的應用程序架構轉…

無涯教程-Perl - redo函數

描述 此函數將重新啟動當前循環,而不會強制判斷控制語句。塊中不再執行任何語句。如果存在繼續塊,將不會執行。如果指定了LABEL,則在LABEL標識的循環開始時重新開始執行。 語法 以下是此函數的簡單語法- redo LABELredo返回值 此函數不返回任何值。 例 以下是顯示其基本…

用友時空KSOA SQL注入漏洞復現(HW0day)

0x01 產品簡介 用友時空KSOA是建立在SOA理念指導下研發的新一代產品&#xff0c;是根據流通企業最前沿的I需求推出的統一的IT基礎架構&#xff0c;它可以讓流通企業各個時期建立的IT系統之間彼此輕松對話&#xff0c;幫助流通企業保護原有的IT投資&#xff0c;簡化IT管理&#…

以商業大數據技術助力數據合規流通體系建立,合合信息參編《數據經紀從業人員評價規范》團標

經國務院批準&#xff0c;由北京市人民政府、國家發展和改革委員會、工業和信息化部、商務部、國家互聯網信息辦公室、中國科學技術協會共同主辦的2023 全球數字經濟大會于近期隆重召開。由數交數據經紀&#xff08;深圳&#xff09;有限公司為主要發起單位&#xff0c;合合信息…

深度剖析堆棧指針

為什么打印root的值與&root->value的值是一樣的呢 測試結果&#xff1a; *號一個變量到底取出來的是什么&#xff1f; 以前我寫過一句話&#xff0c;就是說&#xff0c;如果看到一個*變量&#xff0c;那就是直逼這個變量所保存的內存地址&#xff0c;然后取出里面保存的…

Skeleton-Aware Networks for Deep Motion Retargeting

Skeleton-Aware Networks for Deep Motion Retargeting解析 摘要1. 簡介2. Related Work2.1 運動重定向&#xff08;Motion Retargeting&#xff09;2.2 Neural Motion Processing 3. 概述&#xff08;Overview&#xff09;4. 骨骼感知深度運動處理4.1 運動表征4.2 骨架卷積4.3…