Tencent official open source project for Unity Bug fixes artifact InjectFix

InjectFix Tencent is the latest open source Unity of external thermal rehabilitation program code logic can be realized in Unity online client, without iteration new version, you can quickly fix the game online bug.

Let me talk about a few highlights:

  1. C # directly modifying the project to update the Unity; old projects without modifying the original code to work with;
  2. More in line with Apple updated the terms of the heat;
  3. Each game format a private patch, security more secure.

InjectFix multiple projects by Tencent internal applications feedback is very good, not only to solve the online bug, can effectively improve the efficiency of daily development, let's talk about past lives under this project.

Heat more programs Smash Bros.

All supported iOS heat more programs have one thing in common: After the update code is parsed execution. If their resolve to execute before the update can be divided into two categories:

One is certain modules or even entire games, have been resolved executed. This is the most traditional way, all currently available mainstream programs (xLua, slua, tolua, ILRuntime, jsb etc.) are supported in this way. This mode features:

  1. Some more or less invasive: ILRuntime resolution is performed after assembly of the C # compiler, minimum invasive in these programs may be inside, but it also needs to reconstruct the code, to update the logical split into separate assemblies. C # scripting various non-invasive largest, has completed a project to use pure C # means rewriting.

ps: have an idea is to achieve C # coding through a C # turn XX scripting tools, analysis execution, but if you are an existing project would like it to turn about, a large probability of failure, unless you start using this way not necessarily exactly the same in the development, across the pit to avoid, because such programs are often not full support for all the grammar, syntax supported.

  1. Performance, implementation considerations such as convenience-based, general game some places to run in a native way, these native code to run a bug in this way is powerless.
  2. If the script using a dynamically typed language, code maintenance will bring difficult issues.
  3. The advantage is you can add features, some games can even do a download, do not follow the whole package update. However, analysis of the terms of Section Apple can see, this is not necessarily a good thing.

Another class is run natively, if bug, redirected to the new logical, parsing logic execution. This mode features:

  1. Invasive low, post-project can also be used.
  2. Normal logic native run, there is a problem to resolve only a partial handover execution, the better the performance.
  3. Cause increased code segment, increasing the number of classes proportional to the injected.
  4. New in this way is often difficult.

The second way is the focus of the following discussion, for convenience we call "hot fix" hot fixes the earliest maturity of the program is to provide xLua, after two years of use has gradually been accepted, tolua # later joined this function, there are some users based ILRuntime had a hot repair.

What InjectFix that?

InjectFix a hot fix is ​​achieved. That it and other hot-fix solutions, what difference will it make?

Imagine such a scene, we have a function of a thousand lines of code, there is a line there is a problem, we need to fix it.

If xLua, lua need to re-implement this function again, the heavy workload. And on hot fixes ILRuntime, because of its patch is another assembly, it can not directly access private members of the original class, so that 999 lines of code generally can not normally be used directly, more needs to be done to modify.

The InjectFix not need to use lua, you do not need to like ILRuntime hot fixes as another project to build a thousand lines of logic weight to achieve that. Just need to get rid of this line of code directly in Unity original project, and make note of this function can be updated.

Not only that, InjectFix there are other advantages:

  • Very small operation, only about 100K, compared lua each program, ILRuntime to be much smaller, and does not rely on third-party libraries, pure C # implementation.
  • Each game generates a support own private patch format, the definition of private instruction. Such code is compared to the original universal lua, lua bytecode, clr assemblies are safer.
  • Support to repair dll outside the Assembly-CSharp.dll.
  • Free code generation, cleaner.

It has its drawbacks, does not support the new class, nor does it support the new field in existing classes, repair bug, or enough, but the game is more difficult to pass through the hot new features. InjectFix on a pure bug repair tool.

Black &

Due to repeated loading InjectFix support patch, a new patch will be automatically loaded on a cover, this feature can be used to achieve real machine code logic modified in real time.

(Video address: https://v.qq.com/x/page/v09240mo6ai.html?&ptag=4_7.2.5.22206_copy )

Apple policy compliance

One of the most frequently asked questions of each heat more program group: This program will not lead my game is not reviewed by Apple.

Let's take a look at Apple's hot update provisions:

You can see the latest provisions allowing download code analysis execution, but the premise is not through new features and functionality to the program change was (and when compared to the audit) beyond recognition. Look at the grounds when usually rejected in Guideline 2.5.2 in the sentence:

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。

There are "new features and capabilities," the ability of the embarrassment hot update program that has the ability to "changed beyond recognition" of. The InjectFix from its ability to provide (only modify the existing function) point of view, does not have the ability to "New features and functionality," which was originally weakness on here has become a guarantee of compliance.

Fundamental

InjectFix research and development projects quite tortuous. InjectFix and xLua is the same author, is author of this article, then after xLua open source, continue to want to provide a tool for C # turn of lua was mentioned, and in-depth research to realize that a virtual machine workload il also smaller, this avoids the lua Some gc problems.

决定要做il虚拟机后,也曾想过直接使用ILRuntime,评估后觉得不太符合我们的使用场景:ILRuntime并不能实现和原生代码的函数级别配合,这是我们能实现原工程直接改Bug的关键;ILRuntime运行时部分依赖cecil,除了资源占用大之外,还容易和unity自带或者某些插件的cecil冲突;加载的是标准的程序集在安全性方面也比较堪忧。虽说这些都可以改,但修改的工作量也挺大的,还不如自己写一个。

InjectFix实现bug修复主要靠这两部分:虚拟机负责新逻辑的解析执行;注入代码负责把调用重定向到虚拟机;下面我们结合最简单的例子介绍下这两部分。

虚拟机

关键部分用几行伪码就可以描述清楚:

导读

  1. pc指向的是函数的第一条指令;
  2. argumentBase指向的是第一个参数;
  3. while+switch一条条指令往下执行,具体指令的操作在case那;

argumentBase指向的是求值栈该函数的栈帧,栈帧是这么安排的:

先放参数(如果有的话),再放本地变量(如果有的话),接着是临时区域,当函数返回时弹掉所有东西,如果有返回值就放到栈顶(函数执行前参数0的位置)。

用如下一个静态方法来演示下虚拟机怎么运行:

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

这函数编译后是这四条指令

http://km.oa.com/files/photos/pictures/201803/1520994863_7_w145_h75.png

Add函数的执行过程

  1. 指令1把参数0 Push到栈顶;
  2. 指令2把参数1 Push到栈顶;
  3. 指令3把两个栈顶元素弹出(Pop)并相加,结果Push到栈顶;
  4. 指令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使用简单,小巧,合规且安全。即使你不打算用它来更新线上版本,只要你程序有原生部分,接入也能一定程度上提高开发效率,没什么拒绝它的理由,是吧?

Guess you like

Origin www.oschina.net/news/109803/injectfix-opensource