插桩的概念:
插桩就是在代码中插入一段我们自定义的代码。
插桩的目的:
将程序中插入我们自定义的代码编译到可执行文件中,
该程序的运行过程中就会执行我们自定义的代码,实现我们想要增加的功能需求。
安卓插桩简介:
在安卓方面,插桩通常是指在某手机的官方原厂ROM中通过反编译的方式获得中间代码,
然后通过对中间代码的修改加入自定义的功能,达到为ROM添加功能的目的。
这样做的优势是厂商原厂ROM中的功能、特性或优化基本不会丧失。
而且适配工作很简单,因为官方的ROM本身就是能正常运行的,插桩者只要保证把自己的代码正确插入即可。
缺点是通过中间代码插桩实现功能比起源代码进行修改要费力太多。
而且维护起来也相对麻烦,各机型上难以复用,需要针对性的做一些修改。
什么时候用到插桩:
源码开发是自己拥有一套完整的源代码,想要实现新增的功能需求只需直接在源码上修改。
比如小米自己生产的手机的ROM,必然是在一套完整的源代码上不断修改完善的。
而小米用来适配到其它厂商手机的patchrom项目,则是通过插桩修改的方式。
因为小米并不能获得其它厂商的ROM源代码,只能通过反编译获得中间代码进行插桩修改。
这里首先说一下smali:android反编译的工具,如何进行反编译。反编译后可以得到jar或者得到smali文件。Android采用的是java语言 进行开发,但是Android系统有自己的虚拟机Dalvik,代码编译最终不是采用的java的class,而是使用的smali,smali字节码是类似于汇编的,如果你没有汇编基础,理解起来是非常困难的。
比如:
move v0, v3 #把v3寄存器的值移动到寄存器v0上.
const v0, 0x1 #把值0x1赋值到寄存器v0上。
invoke-static {v4, v5}, Lme/isming/myapplication/MainActivity;->sum(II)I #执行方法sum(),v4,v5的值分别作为sum的参数。
比如我们把小米Nexus 5 MIUIV6的框架反编译,就是反编译Nexus 5官方原厂ROM后得到的中间代码并加入MIUI自己的功能的版本。
我们随便打开里面一个不太复杂的文件,如AsyncResult.smali,你看到的内容就是所谓中间代码了。
.class public Landroid/os/AsyncResult;
.super Ljava/lang/Object;
.source "AsyncResult.java"
# instance fields
.field public exception:Ljava/lang/Throwable;
.field public result:Ljava/lang/Object;
.field public userObj:Ljava/lang/Object;
# direct methods
.method public constructor <init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
.locals 0
.param p1, "uo" # Ljava/lang/Object;
.param p2, "r" # Ljava/lang/Object;
.param p3, "ex" # Ljava/lang/Throwable;
.prologue
.line 63
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
.line 64
iput-object p1, p0, Landroid/os/AsyncResult;->userObj:Ljava/lang/Object;
.line 65
iput-object p2, p0, Landroid/os/AsyncResult;->result:Ljava/lang/Object;
.line 66
iput-object p3, p0, Landroid/os/AsyncResult;->exception:Ljava/lang/Throwable;
.line 67
return-void
.end method
.method public static forMessage(Landroid/os/Message;)Landroid/os/AsyncResult;
.locals 3
.param p0, "m" # Landroid/os/Message;
.prologue
const/4 v2, 0x0
.line 53
new-instance v0, Landroid/os/AsyncResult;
iget-object v1, p0, Landroid/os/Message;->obj:Ljava/lang/Object;
invoke-direct {v0, v1, v2, v2}, Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
.line 55
.local v0, "ret":Landroid/os/AsyncResult;
iput-object v0, p0, Landroid/os/Message;->obj:Ljava/lang/Object;
.line 57
return-object v0
.end method
.method public static forMessage(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)Landroid/os/AsyncResult;
.locals 2
.param p0, "m" # Landroid/os/Message;
.param p1, "r" # Ljava/lang/Object;
.param p2, "ex" # Ljava/lang/Throwable;
.prologue
.line 40
new-instance v0, Landroid/os/AsyncResult;
iget-object v1, p0, Landroid/os/Message;->obj:Ljava/lang/Object;
invoke-direct {v0, v1, p1, p2}, Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
.line 42
.local v0, "ret":Landroid/os/AsyncResult;
iput-object v0, p0, Landroid/os/Message;->obj:Ljava/lang/Object;
.line 44
return-object v0
.end method
我们可以看到,smali就是类似汇编,其中很多命令,我们必需要去查它的手册来一一对应。可读性较差,而源代码可读性要比中间代码强多了,我们打开AOSP项目中相同文件的源码来看
https://github.com/android/platform_frameworks_base/blob/android-4.4_r1.2.0.1/core/java/android/os/AsyncResult.java
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
import android.os.Message;
/** @hide */
public class AsyncResult
{
/*************************** Instance Variables **************************/
// Expect either exception or result to be null
public Object userObj;
public Throwable exception;
public Object result;
/***************************** Class Methods *****************************/
/** Saves and sets m.obj */
public static AsyncResult
forMessage(Message m, Object r, Throwable ex)
{
AsyncResult ret;
ret = new AsyncResult (m.obj, r, ex);
m.obj = ret;
return ret;
}
/** Saves and sets m.obj */
public static AsyncResult
forMessage(Message m)
{
AsyncResult ret;
ret = new AsyncResult (m.obj, null, null);
m.obj = ret;
return ret;
}
/** please note, this sets m.obj to be this */
public
AsyncResult (Object uo, Object r, Throwable ex)
{
userObj = uo;
result = r;
exception = ex;
}
}
读到这里你应该会对插桩的中间代码和源代码的区别有一个基础的了解了。
patchrom开源根本不算源码开发,因为反编译中间代码的取得我们任何一个人通过反编译工具都能做到。这种人俗称打包党,是盗取其他人的rom反编译得来的rom
现在大家明白了,为什么大神中会有很多人厌恶某月亮打包大神(安卓梦工厂)moonlight,骂其盗包狗:5_149: