插件化知识详细分解及原理 之Binder机制

最近一直在研究插件化的东西,我看了网上大多都是直接上来就开始讲解原理然后写个demo,这样对于很多没有入门的朋友不是很好的理解,下面我会通过自己的研究过程,一步一步循序渐进的将插件化需要的知识点都梳理一遍及讲解,其实学习插件化的好处并不全因为它是一门热门的技术,插件化涉及的知识点很多,可以让我们对Android的理解及境界上都会有一个质的飞跃,在我将所有设计的知识点都大概讲一遍后会用一个demo来实现插件化,里面将设计所有讲过的知识。

插件化其实就是动态加载,动态加载又包括了代码加载和资源加载。

可以干什么:

插件化最早出现是因为65535问题出现的,用于查分多个dex并动态加载dex来防止65535问题

现在很多公司用插件化来做模块的动态加载,这样既能实现web端一样的随时更新,还能减少apk包的体积,其实就是加载一个未安装的apk。

热修复,热修复其实也是动态加载原理

换肤,使用动态的资源加载可以实现换肤功能

还可以通过hook系统的一些类做一些你想做的坏事。

目前比较有名的插件化框架:

任玉刚的:dynamic-load-apk,这个项目使用的是一种代理的方式去实现
https://github.com/singwhatiwanna/dynamic-load-apk

360的:DroidPlugin,这个项目是通过hook系统类来实现
https://github.com/Qihoo360/DroidPlugin

目前比较火的热修复框架:

阿里的:andfix,用于对方法的修复,可以立即生效,不支持资源及类替换
https://github.com/alibaba/AndFix

腾讯的:tinker,除了不支持立即生效,全部支持
https://github.com/Tencent/tinker

美团的:robust,不开源

如果要使用插件化来作为模块化的话,那么就需要解决两个问题

代码的加载,就是使用ClassLoader加载代码
资源的加载,使用AssetManager的隐藏方法,addAsssetPath方法加入一个资源路径来获取这个资源的Resource资源
还有一个问题就是对四大组件的生命周期管理
准备:

在了解插件化之前首先需要了解及掌握的知识点
一、Binder机制
二、代理模式,
三、反射
四、类加载及dex加载
五、应用启动过程及类加载过程
六、实现插件化完整demo及思路分析
七、动态加载资源及解决资源冲突问题

Binder机制:

其实Binder看你怎么去理解,如果从代码角度的话他是一个类,如果从硬件角度的话他是一个驱动,如果从IPC角度的话他是一种通信机制,是framework层的各种ServiceManager的链接桥梁,
我们知道我们平时使用的系统服务对象其实都是系统的,他们存在的进程和我们的应用并不在一个进程中,但是为什么我们能直接使用呢?其实就是因为Binder的存在,跨进程通信,再说大白话一点就是使用了我们经常说的aidl,Binder很复杂,这里只是为了插件化做铺垫,想深入理解请自行查阅资料。

进程间通信过程

1.首先客户端要链接服务端
2.然后服务端会返回一个客户端的对象(代理对象)
3.然后客户端使用这个代理对象其中的方法时,系统会先调用服务端的方法,然后将运算的结果返回给客户端(要知道其实并不是用了这个对象的方法,而是去服务端里运算,然后在返回给客户端的)
我们通过自己写一个aidl,然后和系统的源码进行对比

//我们自己写的aidl的接口
//IMyAidlInterface.aidl
package com.huanju.chajianhuatest;
import com.huanju.chajianhuatest.aidlmode.TestBean;

interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);

 String getS(in TestBean s);

 TestBean getInfoBean(out TestBean b);

}
系统会帮我们自动创建一个IMyAidlInterface.Java的文件,我们去看看

>

package com.huanju.chajianhuatest;

public interface IMyAidlInterface extends android.os.IInterface {

public static abstract class Stub extends android.os.Binder implements com.huanju.chajianhuatest.IMyAidlInterface {
    private static final java.lang.String DESCRIPTOR = "com.huanju.chajianhuatest.IMyAidlInterface";


    public Stub() {

        this.attachInterface(this, DESCRIPTOR);
    }

    public static com.huanju.chajianhuatest.IMyAidlInterface asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.huanju.chajianhuatest.IMyAidlInterface))) {
            return ((com.huanju.chajianhuatest.IMyAidlInterface) iin);
        }
        return new com.huanju.chajianhuatest.IMyAidlInterface.Stub.Proxy(obj);
    }

    @Override
    public android.os.IBinder asBinder() {
        return this;
    }

    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_basicTypes: {
                data.enforceInterface(DESCRIPTOR);
                int _arg0;
                _arg0 = data.readInt();
                long _arg1;
                _arg1 = data.readLong();
                boolean _arg2;
                _arg2 = (0 != data.readInt());
                float _arg3;
                _arg3 = data.readFloat();
                double _arg4;
                _arg4 = data.readDouble();
                java.lang.String _arg5;
                _arg5 = data.readString();
                this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getS: {
                data.enforceInterface(DESCRIPTOR);
                com.huanju.chajianhuatest.aidlmode.TestBean _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.huanju.chajianhuatest.aidlmode.TestBean.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                java.lang.String _result = this.getS(_arg0);
                reply.writeNoException();
                reply.writeString(_result);
                return true;
            }
            case TRANSACTION_getInfoBean: {
                data.enforceInterface(DESCRIPTOR);
                com.huanju.chajianhuatest.aidlmode.TestBean _arg0;
                _arg0 = new com.huanju.chajianhuatest.aidlmode.TestBean();
                com.huanju.chajianhuatest.aidlmode.TestBean _result = this.getInfoBean(_arg0);
                reply.writeNoException();
                if ((_result != null)) {
                    reply.writeInt(1);
                    _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                } else {
                    reply.writeInt(0);
                }
                if ((_arg0 != null)) {
                    reply.writeInt(1);
                    _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                } else {
                    reply.writeInt(0);
                }
                return true;
            }
        }
        return super.onTransact(code, data, reply, flags);
    }

    private static class Proxy implements com.huanju.chajianhuatest.IMyAidlInterface {
        private android.os.IBinder mRemote;

        Proxy(android.os.IBinder remote) {
            mRemote = remote;
        }

        @Override
        public android.os.IBinder asBinder() {
            return mRemote;
        }

        public java.lang.String getInterfaceDescriptor() {
            return DESCRIPTOR;
        }


        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                _data.writeInt(anInt);
                _data.writeLong(aLong);
                _data.writeInt(((aBoolean) ? (1) : (0)));
                _data.writeFloat(aFloat);
                _data.writeDouble(aDouble);
                _data.writeString(aString);
                mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                _reply.readException();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
        }

        @Override
        public java.lang.String getS(com.huanju.chajianhuatest.aidlmode.TestBean s) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.lang.String _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                if ((s != null)) {
                    _data.writeInt(1);
                    s.writeToParcel(_data, 0);
                } else {
                    _data.writeInt(0);
                }
                mRemote.transact(Stub.TRANSACTION_getS, _data, _reply, 0);
                _reply.readException();
                _result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }

        @Override
        public com.huanju.chajianhuatest.aidlmode.TestBean getInfoBean(com.huanju.chajianhuatest.aidlmode.TestBean b) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            com.huanju.chajianhuatest.aidlmode.TestBean _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                mRemote.transact(Stub.TRANSACTION_getInfoBean, _data, _reply, 0);
                _reply.readException();
                if ((0 != _reply.readInt())) {
                    _result = com.huanju.chajianhuatest.aidlmode.TestBean.CREATOR.createFromParcel(_reply);
                } else {
                    _result = null;
                }
                if ((0 != _reply.readInt())) {
                    b.readFromParcel(_reply);
                }
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }

    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getS = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_getInfoBean = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}


public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;

public java.lang.String getS(com.huanju.chajianhuatest.aidlmode.TestBean s) throws android.os.RemoteException;

public com.huanju.chajianhuatest.aidlmode.TestBean getInfoBean(com.huanju.chajianhuatest.aidlmode.TestBean b) throws android.os.RemoteException;

}
看着代码好像很多,但是其实没什么,我们分析一下结构

1.我们根据上面的代码,创建的类继承了IInterface接口

2.内部类Stub继承Binder

3.看asInterface方法,判断如果不是一个进程会返回代理类

4.每个方法都对应一个id,用于在跨进程访问时确定访问的是哪个方法,通过transact方法再调用服务端的onTransact方法

我们再看一下系统的类,就看我们最熟悉的ActivityManager,要知道ActivityManager其实是ActivityManagerService在我们进程中的一个代理包装类,他内部全部使用 ActivityManagerNative.getDefault()去进程操作,那么我么直接看 ActivityManagerNative的部分代码

1.asInterface
/* {@hide} /
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}

    return new ActivityManagerProxy(obj);
}

2.onTransact
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
代码太多我们就看这两个就好了,有没有感觉很熟悉,和我们自己写的aidl几乎没有区别,他虽然叫做ActivityManagerNative,其实他就是我们自己写的aidl里的内部类Stub。

下面我们分析一下aidl的运行过程

我们直接看如果是远程的话返回了代理对象,我们看代理对象的方法,这个方法就是aidl结果定义的方法,看他怎么实现的
>

@Override
public com.huanju.chajianhuatest.aidlmode.TestBean getInfoBean(com.huanju.chajianhuatest.aidlmode.TestBean b) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
com.huanju.chajianhuatest.aidlmode.TestBean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getInfoBean, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
_result = com.huanju.chajianhuatest.aidlmode.TestBean.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
if ((0 != _reply.readInt())) {
b.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
客户端发起请求

1.首先创建输出类型data
2.创建接受类型reply
3.创建需要的参数
4.将参数写入data中
5.发起远程调用,当前线程挂起调用mRemote.transact()方法,这个方法的实现在Binder中,他会调用服务端的onTransact方法,直到有返回结果
6.从_result中取回返回结果_result
服务端接到请求会走到onTransact方法,这个方法运行在服务端的Binder线程池中,我们再看看怎么实现的

>

case TRANSACTION_getInfoBean: {
data.enforceInterface(DESCRIPTOR);
com.huanju.chajianhuatest.aidlmode.TestBean _arg0;
_arg0 = new com.huanju.chajianhuatest.aidlmode.TestBean();
com.huanju.chajianhuatest.aidlmode.TestBean _result = this.getInfoBean(_arg0);
reply.writeNoException();
if ((_result != null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
1.通过id确定访问哪个方法
2.然后从目标参数data取出需要的参数
3.然后调用请求的相应方法
4.将返回值写入reply
5.返回true,这里需要说一下,如果返回false,代表客户端访问失败,我们实际当中可根据这个特性来做远程的校检,毕竟我们的远程方法并是不想让任何人都可以访问的。
,通过id确定访问哪个方法,然后从目标参数data取出需要的参数,然后调用相应方法,将返回值写入reply,
好了,到这里Binder的通信过程就完了,其实我们看到了只要我们理解了我们自己写的aidl的流程及原理,那么系统层的通信也是这样的。下一篇我们继续说代理模式及反射。

原文链接 http://blog.csdn.net/yulong0809/article/details/56841993

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值