美文网首页
Handler和Binder

Handler和Binder

作者: 双囍_小赵 | 来源:发表于2021-11-23 17:27 被阅读0次

FrameWork层的Handler和Binder;

通信分为:

App间的通信——Binder

App内部通信——Handler


Handler

Handler学好解决的问题:

1.面试

2.防止内存泄露

3.防止内存抖动

Handler原理:

Handler原理:是为了实现线程间的通信

线程间的通信,两个线程使用公共的变量或者公共的其他东西都可以进行通信,但是这种方式不是自主的,不能够自主切换线程执行,所以Handler的最终是为了线程间的切换。

Handler的使用会涉及到message、looper、messageQueue;Message的作用是携带数据,handle通过调用sendMessage的方式发送数据到MessageQueue队列,looper通过循环遍历的方式从messageQueue中取出数据;

Handler四大部分:

Handler:提供传输数据的作用(handler.sendMessage() / handler.handlerMessage() 发送/获取数据)

Message:具体的数据

MessageQueue:具体的数据的列表

Looper:获取传输数据

Handler调用:

handler发送消息关键方法调用

最终的会到handler.enqueueMessage  -> MessageQueue.enqueueMessage

将数据通过handle发送数据到MessageQueue中。

handler调用了sendMessage,立刻就会调用handlerMessage()方法;

sendMessage是生产者,handlerMessage是消费者;消息在队列中排队(MessageQueue),这样解决大量的消息过来的问题,不会造成主线程sendMessage阻塞,所有消息都会直接放在队列中排队等候执行;

一个线程可以有几个Handler,几个looper?

有多个handler,每个handler都会配一个队列MessageQueue。

注:Lopper和MessageQueue绑定,为防止创建多个messageQueue,Looper创建也只能被调用一次;

一个Looper,因为looper里面是死循环执行,后面的代码是执行不到的,所以只有一个looper;looper的生命周期是当前线程的生命周期长度,如何保证一个线程中只有一个Looper,可以通过线程——ThreadLocal,ThreadLocal中会有一个ThreadLocalMap保存一个Looper,通过调用ThreadLocal的get方法来获取是否能得到Looper,如果能得到说明已经有了Looper,就直接返回一个异常通知已经有了Looper。

Looper.looper()就是循环提取消息并调用handlerMessage()去处理;

Looper.prepare()就是保证只有一个looper;

为什么handler会造成内层泄露?

长生命周期持有短生命周期,造成短生命周期得不到释放就会造成内存泄露;

线程的生命周期长,Activity的生命周期短,activity运行完得不到释放;

1.在Activity中实例化Handler导致了,Activity中持有handler对象;

2.Message和Handler的持有是由于在Lopper中进行循环遍历的时候,Message需要被执行所以要使用handler的handleMessage,但是此时获取不到handler对象,所以,通过Message中实例化一个Handler对象;

3.MessageQueue是Message的集合对象,所以造成持有关系;

4.Looper又和MessageQueue进行了绑定,造成了Looper对Message的持有;

最终 :线程----->Looper----->MessageQueue----->Message----->Handler------>Activity,一系列持有造成的内存泄露;

解决内存泄露可以使用static+弱引用的方式解决。

主线程会一直阻塞?

是的,如果主线程不进行looper.loop阻塞,一下子执行完成,整个程序就直接结束了,不可能有机会去执行其他的任务了。

Android是事件为驱动的操作系统,事件过来就去handler里执行,没有事件就阻塞在那里显示界面;

Message

Message的创建方式有两种:

1.new Message()

2.obtainMessage

涉及:想要了解优化内存抖动,可以看看message的原理,内存抖动是为啥?因为短时间创建大量的对象并销毁。

使用obtainMessage创建一个Message,会有复用的作用,涉及到一个回收池,回收池中存放的是Message,会有一定的数量,使用单项链表来存放这些Message。每个message对象指向下一个Message对象;

obtainMessage创建对象是从回收池中获取,没有的才会进行创建,回收池中获取一个Message需要将管理回收池的列表同这个取出来的Message的关联进行切断,所以需要将此获取的Message的next引用置为空。并且spool变量的引用将会变成下一个Message,同时单向列表的size-1,如下代码:

public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message();

new Message()产生的对象是不会进回收池的。

安卓中的Looper.loop()阻塞为什么不会有问题?

Android是事件为驱动的操作系统,事件过来就去handler里执行(handle里处理包括了创建服务,创建广播,结束服务,等等事件处理),如果没有事件过来就阻塞在那里,显示静止界面,有事件就去执行事件;

利用epoll机制可以定位到是哪个app接受这个事件

运用到红黑树,事件过来之后查找app来执行这个事件,事件带有一个标记,查找对应的app。


Binder

binder是Android独有的,其他平台没有,但是移植到其他平台上进行编译通信。

Android是继承自Linux,在Linux基础上进行封装一层;

学习Binder作用

1.面试

2.解决bug

3.了解android运行原理

Android中为什么会用Binder?

Android系统为每个app提供服务,就是类似于C/S模型;为什么不沿用Linux的进程通信方式呢,以下对Linux的集中方式进行分析:

linux中有哪几种进程通信:管道、共享内存、Socket、File;

管道:

    1.效率:管道不高,App1的数据copy到管道,管道copy到App2里面,进行了两次拷贝;

    2.安全:管道比较安全

    3.模型:1V1

共享内存:

    效率是最高的,不会涉及任何copy;不安全,多线程下难以控制;多个程序有一个共享的内存,NVN模式;

Socket:

    进行两次copy,还要用户和内核的cpu状态切换,比管道效率还低;安全;C/S模型;

File:

    磁盘读写,更不安全;

Android中Binder机制:

Binder进行了一次copy(用户空间copy到内核空间);基于C/S模型,易用性高;为每个App分配UID,支持实名和匿名;

通信的时候通过Android系统进行验证两个App的UID进行通信,这样防止其他app拦截;

内核进程:里面装的系统代码、驱动代码(这些进程号为0的就是系统代码),防止,每个app都进行编译一次系统代码浪费资源;

App:里就是运行用户代码;

Binder为何能实现一次copy?

Binder的一次copy是利用了mmap(内存映射文件:目的是开辟物理地址),内存映射文件是在堆和栈的空余空间;mmap是在linux中的api,可以通过mmap去开辟物理地址空间。

而涉及到MMU,MMU(MemeoryManangerUnit)将mmap开辟的物理内存地址转化成虚拟内存地址;

物理地址:内存条上的地址;

虚拟地址:实际上是MMU提供的虚拟地址;

Binder采用的是C/S模式的,其中提供服务的进程成为Server进程,访问服务的进程成为Client进程;

Server和Client进程通信:要依靠运行在内核空间的Binder驱动程序来进行;

Service组件在开启时,会将自己注册到一个Service Manager里,以便于Client进程在ServiceManager中找到它;因此ServiceManager也称为Binder进程间通信的上下文管理者;同时它也需要和普通的Server进程和Client进程通信,所以也是可以看做一个特殊的Service组件;

注:Binder通信机制中的Service组件和Android中的Service组件是不同的概念;Service Manager里注册服务是在进程间的注册;

Binder

1.服务注册

2.服务发现

3.服务查找

扩展:在系统进程中init(pid = 1)是守护关键服务进程、启动关键服务进程,守护那些关键的服务进程(父进程是ppid = 1),

两个进程间的通信Binder原理:

Binder的通信是 进程A 调用copy_form_user,到内核空间,内核空间进程B建立了链接,copy_to_user会将数据传给B进程;而进程间的通信大小是1M-8K(copy到内核空间),8K是由于有请求头等信息,一页是4K,需要是4的整数倍;

扩展:了解什么是页

cpu为了高效执行以及内存管理,每次需要拿一个页的代码,这个页表示一块连续的储存空间。常见的4kb,也称为块。

假如页的大小为P,那么在虚拟内存中就是VP称为虚拟页;从虚拟内存中拿到的一页的代码放在物理内存中,那么物理内存中也得有一个同样大小可以页存放虚拟页的代码,物理内存中的页称为物理页(PP);

在任何时刻,虚拟页都有三种以下状态中的一种:

    未分配的:VM还未分配页(或者未创建),未分配的页还没有任何数据与代码与他们关联,因此也就不占任何磁盘;

    已缓存的:当前缓存在物理内存中已分配页;

    未缓存的:当前未缓存在屋里内存中已分配页;

以上状态都是在MMU中体现。

为什么会出现物理地址和虚拟地址呢?

由于现在的程序app大小都很大了,如果全部加载到内存中去运行需要很多内存,而手机的内存是有限的,又由于当你在运行一个app的时候不是所有的代码都会被加载到内存中去运行,只会加载一部分正在活动的代码,为了满足程序局部性原则,这时出现的物理地址和虚拟地址刚好能解决,能省下不用的内存空间供其他app使用。

物理地址和虚拟地址

为什么会存在MMU,因为app的整体大小假如是100M,但是实际的活跃代码在内存中只有1M,其他的代码处于磁盘中,所以,cpu在运行代码的时候不可能说只给1M的内存让cpu在里面运行,所以需要给一个MMU中间件,让CPU感觉运行在512M的内存中。

MMU(Memory Management Unit)内存管理单元又涉及到一个转换物理地址和虚拟地址;

物理地址:内存条上的地址;

虚拟地址:MMU提供的虚拟的地址;

MMU里有页表:页表里有效位+地址,有效位为0表示未缓存,为1表示已缓存,只要有效位是1就肯定有地址;

虚拟地址和物理地址,如果虚拟地址中没有的话,MMU就会读取磁盘并拿出来在内存中开辟一块新的空间,并在MMU中存放物理地址和对应的虚拟地址,cpu就会拿到虚拟地址;

共享内存:实现跨进程通信(也是mmap使用方式):

两个不同进程,通过native-lib.cpp文件,里面用C代码:通过mmap的api方式开辟物理内存并写入到物理内存,另外一个进程可以通过mmap获取到相同的那块物理内存地址,这样就可以获取内容了,实现了跨进程通信,和binder相比,没有进行copy,依赖于物理内存做通信。

BInder共享内存的区别在于:

进程A和内核空间发生了一次copy,而进程B(类似服务端)和内核空间之间的关联类似于共享内存的形式,没有发生copy。

进程A(类似客户端)和内核空间的copy又是怎样的?

数据接收方Stub类,数据发送方Proxy,就是创建aidl时自动生成的文件里面的两个类,Proxy类是Stub类的内部类,如下代码:

```

/*

* This file is auto-generated.  DO NOT MODIFY.

*/

package com.zx.annotationtest;

/**

* 工程目录直接反键,自动创建在aild文件目录下,创建一个AIDL文件用于生成代码

* 生成的是Stub类数据接受方和Proxy类数据发送方

*/

public interface IMyAidlIPC extends android.os.IInterface

{

/** Default implementation for IMyAidlIPC. */

  public static class Default implements com.zx.annotationtest.IMyAidlIPC

{

@Override public int add(int a, int b)throws android.os.RemoteException

{

return 0;

    }

@Override

    public android.os.IBinderasBinder() {

return null;

    }

}

/** Local-side IPC implementation stub class. */

  public static abstract class Stub extends android.os.Binder implements com.zx.annotationtest.IMyAidlIPC

{

private static final java.lang.StringDESCRIPTOR ="com.zx.annotationtest.IMyAidlIPC";

    /** Construct the stub at attach it to the interface. */

    public Stub()

{

this.attachInterface(this, DESCRIPTOR);

    }

/**

* Cast an IBinder object into an com.zx.annotationtest.IMyAidlIPC interface,

* generating a proxy if needed.

*/

    public static com.zx.annotationtest.IMyAidlIPCasInterface(android.os.IBinder obj)

{

if ((obj==null)) {

return null;

      }

android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

      if (((iin!=null)&&(iininstanceof com.zx.annotationtest.IMyAidlIPC))) {

return ((com.zx.annotationtest.IMyAidlIPC)iin);

      }

return new com.zx.annotationtest.IMyAidlIPC.Stub.Proxy(obj);

    }

@Override public android.os.IBinderasBinder()

{

return this;

    }

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)throws android.os.RemoteException

{

java.lang.String descriptor =DESCRIPTOR;

      switch (code)

{

case INTERFACE_TRANSACTION:

{

reply.writeString(descriptor);

return true;

        }

case TRANSACTION_add:

{

data.enforceInterface(descriptor);

          int _arg0;

          _arg0 = data.readInt();

          int _arg1;

          _arg1 = data.readInt();

          int _result =this.add(_arg0, _arg1);

          reply.writeNoException();

          reply.writeInt(_result);

return true;

        }

default:

{

return super.onTransact(code, data, reply, flags);

        }

}

}

private static class Proxy implements com.zx.annotationtest.IMyAidlIPC

{

private android.os.IBindermRemote;

      Proxy(android.os.IBinder remote)

{

mRemote = remote;

      }

@Override public android.os.IBinderasBinder()

{

return mRemote;

      }

public java.lang.String getInterfaceDescriptor()

{

return DESCRIPTOR;

      }

@Override public int add(int a, int b)throws android.os.RemoteException

{

android.os.Parcel _data = android.os.Parcel.obtain();

        android.os.Parcel _reply = android.os.Parcel.obtain();

        int _result;

        try {

_data.writeInterfaceToken(DESCRIPTOR);

          _data.writeInt(a);

          _data.writeInt(b);

          boolean _status =mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);

          if (!_status &&getDefaultImpl() !=null) {

return getDefaultImpl().add(a, b);

          }

_reply.readException();

          _result = _reply.readInt();

        }

finally {

_reply.recycle();

          _data.recycle();

        }

return _result;

      }

public static com.zx.annotationtest.IMyAidlIPCsDefaultImpl;

    }

static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION +0);

    public static boolean setDefaultImpl(com.zx.annotationtest.IMyAidlIPC impl) {

// Only one user of this interface can use this function

// at a time. This is a heuristic to detect if two different

// users in the same process use this function.

      if (Stub.Proxy.sDefaultImpl !=null) {

throw new IllegalStateException("setDefaultImpl() called twice");

      }

if (impl !=null) {

Stub.Proxy.sDefaultImpl = impl;

return true;

      }

return false;

    }

public static com.zx.annotationtest.IMyAidlIPC getDefaultImpl() {

return Stub.Proxy.sDefaultImpl;

    }

}

public int add(int a, int b)throws android.os.RemoteException;

}

```

内核进程开启了init进程,init是守护进程,守护那些系统进程比如蓝牙、电话……

init进程又会开启service-manager和zygote进程,而zygote进程会开启system-server进程,system-server会开启应用服务AMS、PMS、WMS……,而开启的这些应用进程又归service-manager管理

SystemServer类:

```

SystemServiceManager  mSystemServiceManager;

mActivityManagerService=mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();

```

其中Lifecycle.class是ActivityManagerService类的内部类:

```

public static final class Lifecycle extends SystemService {

        private final ActivityManagerService mService;

        public Lifecycle(Context context) {

            super(context);

            mService = new ActivityManagerService(context);

        } 

     public ActivityManagerService getService() {

            return mService;

        }

```

Lifecycle中包装了ActivityManagerService,并且将用getService方法把mService返回出去,就是上面的SystemServer类中获取ActivityManagerService的实例。

ActivityManagerService类:

ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);

ActivityManagerService  通过addService给ServiceManager。

相关文章

网友评论

      本文标题:Handler和Binder

      本文链接:https://www.haomeiwen.com/subject/tqydtrtx.html