騰訊正式開源面向 Unity 項目的 Bug 修復神器 InjectFix

2021-01-10 開源中國

InjectFix是騰訊最新對外開源的Unity代碼邏輯熱修複方案,可實現在Unity線上客戶端內,不用迭代新版本,就能快速修復遊戲的線上bug。

先說幾個亮點:

直接在Unity工程上修改C#即可更新;老項目無需修改原有代碼即可使用; 更符合蘋果熱更新條款; 每個遊戲一份私有補丁格式,安全更有保障。

InjectFix經騰訊內部多個項目應用反饋十分良好,不僅能解決線上bug,還可以有效的提高日常開發效率,下面我們聊下這項目的前世今生。

熱更方案大亂鬥

所有支持iOS的熱更方案都有個共同點:更新後代碼都是解析執行。如果按其更新前是否解析執行,可以分為兩大類:

一類是某些模塊甚至整個遊戲,都一直解析執行。這是最傳統的方式,目前市面上所有主流方案(xLua,slua,tolua,ILRuntime,jsb等等)都支持這種方式。這種方式的特點:

或多或少都會有些侵入性:ILRuntime解析執行C#編譯後的程序集,在這些方案裡頭侵入性可能最小,但也需要對代碼重構,把要更新的邏輯拆到單獨程序集。各種非C#的腳本侵入性最大,一個已經完成的純C#項目要用意味著重寫。

ps:也有一種思路是通過一個C#轉XX腳本工具來實現C#編碼,解析執行,但如果你是一個已有項目想這麼轉一下,大概率是失敗的,除非你一開始就在用這方式在開發,碰到坑就避開,因為這類方案往往不是完整支持全部語法,支持的語法也不一定能完全一致。

基於性能,實現便利性等的考慮,一般遊戲有些地方要以原生的方式跑,這些原生跑的代碼出了bug這種方式是無能為力的。 如果使用的腳本是動態類型語言,還會帶來代碼維護困難的問題。 優點是可以新增功能,有的遊戲甚至可以做到一次下載,後續不用整包更新。但蘋果條款分析的章節可以看到,這也不一定是好事。

另外一類是以原生方式跑,如果有bug,把邏輯重定向到新的,解析執行的邏輯。這種方式的特點:

侵入性低,後期項目也可以使用。 正常邏輯是原生方式運行,有問題只是局部切換到解析執行,所以性能比較好。 會導致代碼段增大,增大正比於注入的類的數量。 這種方式往往難以新增功能。

第二種方式是接下來討論的重點,方便起見,我們稱之為「熱修復」,熱修復最早的成熟方案是xLua提供,經過兩年來的使用已經逐漸被接受,tolua#後來也加入了這功能,也有一些網友基於ILRuntime做了熱修復功能。

InjectFix是什麼?

InjectFix就是一個熱修復的實現。那它和其它熱修複方案又有什麼不同呢?

設想這麼個場景,我們有一個一千行代碼的函數,其中有一行有問題,我們需要修復它。

如果用xLua,需要用lua去重新實現一遍這個函數,工作量大。而基於ILRuntime的熱修復,由於其補丁是另一個程序集,它無法直接訪問原類的私有成員,所以那999行正常代碼一般也不能直接使用,需要做較多修改。

而InjectFix不需要用lua,也不需要像ILRuntime熱修復那樣另外建一個工程把那一千行邏輯重實現。只需要在Unity原工程直接改掉這行代碼,然後標註這函數要更新即可。

不僅如此,InjectFix還有其它優勢:

運行時非常小巧,僅100K左右,比各lua方案,ILRuntime都要小很多,而且不依賴第三方庫,純C#實現。 支持每個遊戲生成一份自己私有的補丁格式,私有的指令定義。這樣相比通用的lua原代碼,lua字節碼,clr程序集都更安全些。 支持Assembly-CSharp.dll之外的dll的修復。 免代碼生成,更乾淨。

它也有缺點,不支持新增類,也不支持在已有類新增欄位,修bug還是夠用的,但難以通過熱更為遊戲增加新功能。InjectFix就一個純粹的修bug工具而已。

黑科技

由於InjectFix支持重複加載補丁,新加載補丁會自動覆蓋上一個,這特性可以用來實現真機代碼邏輯實時修改。

(視頻地址:https://v.qq.com/x/page/v09240mo6ai.html?&ptag=4_7.2.5.22206_copy)

蘋果政策合規性

各熱更方案群的問的頻率最高的問題之一:這方案會不會導致我遊戲蘋果審核不通過。

讓我們看看蘋果的熱更新條款:

可以看到最新條款允許下載代碼解析執行,但前提是不能通過新增特性和功能來把程序改得(和審核時相比)面目全非。再看看通常被拒時的理由中的Guideline 2.5.2裡的一句:

Your app, extension, or linked framework appears to contain code designed explicitly with the capability to change your app’s behavior or functionality after App Review approval。

有「新增特性和功能」能力的熱更新方案的尷尬之處在於有「改得面目全非」的能力。而InjectFix從它提供的能力(只能修改已有函數)來看,並不具備「新增特性和功能」的能力,這本來是弱點,放在這裡卻成為合規性的保證了。

基本原理

InjectFix項目的研發挺曲折的。InjectFix和xLua是同一個作者,也是本文筆者,當時xLua開源後,不斷有人提希望提供個C#轉lua的工具,而深入研究覺得實現個il虛擬機工作量還更小,這樣還能避免lua的一些gc問題。

決定要做il虛擬機後,也曾想過直接使用ILRuntime,評估後覺得不太符合我們的使用場景:ILRuntime並不能實現和原生代碼的函數級別配合,這是我們能實現原工程直接改Bug的關鍵;ILRuntime運行時部分依賴cecil,除了資源佔用大之外,還容易和unity自帶或者某些插件的cecil衝突;加載的是標準的程序集在安全性方面也比較堪憂。雖說這些都可以改,但修改的工作量也挺大的,還不如自己寫一個。

InjectFix實現bug修復主要靠這兩部分:虛擬機負責新邏輯的解析執行;注入代碼負責把調用重定向到虛擬機;下面我們結合最簡單的例子介紹下這兩部分。

虛擬機

關鍵部分用幾行偽碼就可以描述清楚:

導讀

pc指向的是函數的第一條指令; argumentBase指向的是第一個參數; while+switch一條條指令往下執行,具體指令的操作在case那;

argumentBase指向的是求值棧該函數的棧幀,棧幀是這麼安排的:

先放參數(如果有的話),再放本地變量(如果有的話),接著是臨時區域,當函數返回時彈掉所有東西,如果有返回值就放到棧頂(函數執行前參數0的位置)。

用如下一個靜態方法來演示下虛擬機怎麼運行:

public static float Add(float a, float b){    return a - b;}

這函數編譯後是這四條指令

Add函數的執行過程

指令1把參數0 Push到棧頂; 指令2把參數1 Push到棧頂; 指令3把兩個棧頂元素彈出(Pop)並相加,結果Push到棧頂; 指令4把棧頂拷貝到參數0的位置,清理棧,退出循環,Execute函數執行結束。代碼注入

上面的Add函數注入後是這樣的

public static float Add(float a, float b){ if (WrappersManagerImpl.IsPatched(92)) { return WrappersManagerImpl.GetPatch(92).__Gen_Wrap_25(a, b); } return a - b;}

比較簡單,發現這函數有patch的話,就重定向到虛擬機。

而__Gen_Wrap_25是個適配器函數,賦值把參數壓棧,調用虛擬機的Execute函數,並把結果返回。__Gen_Wrap_25的實現如下:

public float __Gen_Wrap_25(float P0, float P1){ Call call = Call.Begin(); call.PushSingle(P0); call.PushSingle(P1); this.virtualMachine.Execute(this.methodId, ref call, 2, 0); return call.GetSingle(0);}

PS:我們的例子僅有三種指令,和這幾條指令無關的代碼全部簡化了,真正複雜得多,有興趣可以看源碼了解。

總結

InjectFix使用簡單,小巧,合規且安全。即使你不打算用它來更新線上版本,只要你程序有原生部分,接入也能一定程度上提高開發效率,沒什麼拒絕它的理由,是吧?

相關焦點

  • 騰訊開源手遊熱更新方案,Unity3D 下的 Lua 編程
    2016年12月末,xLua剛剛實現新的突破:全平臺支持用Lua修復C#代碼bug。那麼,騰訊開源的xLua究竟是怎樣的技術?它是為何如此設計的?更令人關心的是,xLua的性能如何?帶著這些問題,InfoQ對其作者進行了採訪並將內容整理成文。技術背景騰訊自研手遊,就我了解的項目來說,大多數遊戲引擎都是Unity3D,少數用coco2d。xLua這個插件具體用到了哪些遊戲中?
  • 網傳Epic Games啟動器莫名佔用CPU,官方承認出現bug正修復
    由於網絡反響越來越大,Epic開發團隊已表示將儘快發布修復程序。Epic Games的發布策略主管Sergey Galyonkin在Twitter上表示,公司已了解到情況,這是一個Bug。目前這個bug似乎是與AMD Ryzen的多線程技術有關,導致CPU進行大量運算,甚至可以拉高10~20°C,相當可觀。
  • 企業級雲原生:TKEStack 騰訊雲原生開源實踐之路
    導語丨TKEStack 是騰訊開源的一款集強壯性和易用性於一身的企業級容器編排引擎,是開放原子開源基金會的孵化項目之一。本文是對TKEStack 開源項目負責人汝英哲、TKEStack 高級產品經理何鵬飛在雲+社區沙龍online的分享整理,介紹 TKEStack 的開源方法論,希望與大家一同交流。
  • 騰訊雲成為MariaDB基金會白金會員,成全球資料庫開源中堅力量
    ,騰訊雲正式成為MariaDB基金會白金會員,這是基金會最高級別會員。MariaDB是由MySQL之父Michael Widenius於2009年開創的一個MySQL分支,在MySQL被商業企業收購後,為保證行業仍有開源可用的兼容MySQL的分支可用,Michael Widenius在創立了 MariaDB的同時,還成立了非贏利組織 MariaDB 基金會為MariaDB 項目、用戶和開發者社區提供基礎架構支持。
  • 開源項目在GitHub上貢獻33.5W個Star!騰訊的十年「雲」答卷,請收好!
    這一路來,騰訊也貢獻了一份重要的力量,110+個開源項目,Github總Star數超過33.5W,「雲原生」產品API每日調用量更是超100億次,騰訊在2020 Techo開發者大會上交出開源十年的答卷! 2020年,雲原生(Cloud Native)的概念,火得一塌糊塗。
  • KDE Plasma 5.1.2 發布,bug 修復版本
    KDE 發布了 Plasma 5 的 bug 修復版本,Plasma 5.1.2。此版本添加了這個月的新翻譯,還有 KDE 貢獻者發布的 bug 修復。這些 bug 修復非常經典,很小,但是很重要!Fix vertical aligment.
  • 雲+社區技術沙龍丨解析騰訊最新開源項目背後的技術棧
    本期活動的主題為「騰訊開源技術」,多位來自騰訊的開源技術專家及工程師圍繞 Kona JDK、TencentOS tiny、TubeMQ 等開源項目的開發過程,分享了騰訊在開源之路上取得的最新成果以及過程中所積累的實踐經驗,並深入探討了開源技術在大數據、物聯網、醫療等不同場景下的發展趨勢。
  • 盤點面向物聯網的21個開源軟體項目
    DSA項目正在構建分布式服務鏈路(DSLinks)庫,以便支持協議轉換、與第三方數據源整合數據。DSA提供一種可擴展的網絡拓撲結構,這種拓撲結構包括在連接到分層代理層次體系的物聯網邊緣設備上運行的多個DSLinks。
  • Qt 5.12 LTS 正式發布,修復超過 2000 個 bug
    Qt 5.12 已正式發布,這是一個長期支持版本(LTS),開發團隊將在未來 3 年內提供支持。
  • 開發者向開源項目提交 issue 表達謝意引發爭論
    開發者 Vito Botta 近日在 hairpin-proxy 的 repo 提交了一個 issue,這個 issue 無關技術和開源,也不是反饋 bug 或提出建議等,這更像是一封感謝信,Vito 希望通過這個 issue 表達對 hairpin-proxy 及其作者的感謝。
  • 淘寶Web伺服器Tengine正式開源:Nginx定製版
    站長之家(chinaz.com)12月5日報導:日前,由淘寶核心系統團隊定製和開發的淘寶Web伺服器Tengine正式開源,並對外提供下載。
  • 爐石傳說18.2版本正式上線 修復bug內容一覽
    爐石傳說最新補丁18.2正式上線,本次上線不僅實裝了巴羅夫家族而且還修復了一些已知的bug。小面就讓我們一起看看本次修復的bug有哪些吧,有沒有你所不知道的。 10、修復了使用克爾蘇加德英雄進入「卡拉贊之夜」最終戰鬥時的崩潰錯誤【單人冒險模式】。
  • Hadoop開源社區正式支持騰訊雲對象存儲COS
    8月4日消息,知名大數據開源社區Hadoop近日宣布對騰訊雲對象存儲COS的正式支持。後續,開發者在基於Hadoop架構進行大數據分析時,能夠在不修改代碼的情況下,無縫高效地使用騰訊雲COS來處理海量數據的讀寫任務。這標誌著騰訊雲對象存儲技術受到了全球最主流大數據開源社區的認可。
  • 《一起來捉妖》白老鼠攻擊出bug,2技被砍廢,訓練師救了騰訊!
    大家好,歡迎來到《一起來捉妖》捉妖娛樂坊~新版本上線後,對許多妖靈的攻擊傷害等做了調整,這次沫沫要跟大家提到的,就是白老鼠——半截觀音,更新後攻擊出bug,2技能被砍廢,一起來看看吧!白老鼠攻擊出bug,2技被砍廢,訓練師救了騰訊白老鼠技能打法簡單,起手2技能加攻速,接下來再按1技能即可,本次更新呢,公告上表示「半截觀音決勝鬥志技能的動作時長大幅縮短」,事實上體驗後,2技能前搖確實縮短了很多,但伴隨的問題是什麼呢?攻擊效果沒了~2技能的作用就是給1技能加物理攻擊傷害,前搖雖然調整了,可傷害給整沒了,那2技能除了消耗能量豆便一無是處。
  • Phasmophobia恐鬼症更新修復內容介紹
    * Potential fix for anyone on a University internet not being able to connect to the server.*潛在的修復:校園網不能連接到伺服器* Fixed a bug where dead players couldn't use voice chat.
  • NeuralNLP-NeuralClassifier:騰訊開源深度學習文本分類工具
    點擊上方「MLNLP」,選擇「星標」公眾號重磅乾貨,第一時間送達推薦一下騰訊的開源>https://github.com/Tencent/NeuralNLP-NeuralClassifier以下是來自騰訊開源的官方報導。
  • 騰訊優圖開源深度學習推理框架TNN 助力AI開發降本增效
    一方面,它以「授人以漁」的方式為AI構建了一個開放共進的生態環境,幫助行業加速AI應用落地;另一方面,在解決行業實際問題時持續更新和迭代,源源不斷地給AI領域輸送重要的技術養料和創造力,可以說開源是AI落地和繁榮不可或缺的源動力。  6月10日,騰訊優圖實驗室宣布正式開源新一代移動端深度學習推理框架TNN,通過底層技術優化實現在多個不同平臺的輕量部署落地,性能優異、簡單易用。
  • iOS12.1.3正式版發布,解決信號問題,修復了大量BUG
    昨天凌晨,蘋果發布了iOS12.1.3正式版本,在經歷了4個測試版本的更新之後,蘋果終於是解決了iPhone信號的問題,那麼接下來讓仙仙跟大家分享一下這個版本具體的表現情況吧!本次更新包的大小在279M左右,升級過程沒有異常發熱的現象,這個版本修復了雙 SIM 卡蜂窩數據連接問題,同時還修復了大量的 bug。如果你手裡的機型出現網絡信號問題建議及時升級。
  • 11 個開源的面向文檔資料庫
    本文介紹 11 個開源的面向文檔的資料庫系統: 1. MongoDB MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。他支持的數據結構非常鬆散,是類似 json的bjson格式,因此可以存儲比較複雜的數據類型。
  • ...周報第72期:騰訊雲發布八款雲原生系列產品,阿里發布開源量子...
    華為高性能車規級雷射雷達首發 將面向百萬級量產需求在T10 ICV CTO峰會上,華為首次面向行業正式發布車規級高性能雷射雷達產品和解決方案。華為快速建立了第一條車規級雷射雷達的Pilot產線,面向百萬級量產需求,華為已按照年產10萬套/線在推進,以適應未來大規模量產需求。