【android Framework 探究】浅谈AIDL和Binder

开头

准备入职做android系统工程师了,奈何系统方面的知识一直没有去梳理过,还是很感谢东家给我这次机会,对于一个小白来说,首要任务就是对自己目前掌握的知识进行总计,查漏补缺。所以自己列了一个学习计划同时也是总结计划,找到一个适合自己的学习曲线是我的首要任务。

下面是计划,哎…万事开头难,看了知识A发现知识B还不了解,计划也是修修改改

计划

任务 阶段目标
1,进程通讯机制 - binder 和 aidl (binder不能恋战) 这很重要,理解了这个才能看懂系统服务间大量的进程间调用关系
2,Android系统的启动流程 理解init进程,zygote,systemServer的启动流程,承担的角色
3,AMS的启动流程 理解AMS从哪里启动,负责启动和管理哪些服务
4,ActivityTask,ActivityRecord,ActivityStackSupervisor 理解Activity的基本数据结构和管理方式
5,Activity的启动流程 梳理startActivity的调用逻辑
6,SurfaceFling,Choreographer渲染机制 Jank的理解和计算方式
7,WMS窗口管理机制 (后面可能有调整)
未完待续

大佬们的指导思想

在迷茫的时候多看一些过来人的意见
Android Framework 如何学习,如何从应用深入到Framework?

我起跑时跌倒的经历

当然每个人的知识水平不同,我个人偏上层。

我个人的学习经历的:
阶段1:经常深陷细节,强行理解,导致昏昏欲睡。
阶段2:痛定思痛,补充一些基本理论知识,结果深陷内核和驱动代码不能自拔,一直到不自信。
阶段3:跳出来,换换脑子,找一些不错的博客,目的是看他们的学习路线,看哪一个最适合自己,不知道你有这种感觉没有,到KTV哪一首歌起头比较符合你的嗓门和最近的心情,你进入状态就很顺滑。
阶段4:从头再来,先宏观再细节,去看源码的调用链,经常看了忘,忘了再看,后来发现好像是要”背课文“。
阶段5:闲暇中思考,因为在系统设计中,都是先有的问题,再有的代码,有时候会思考这样设计解决的问题是什么?

从Binder开始

binder是我们入门Framework的最重要的基础之一,至少理解了binder在系统服务间的跨进程调用,否则很难看懂。

从应用开发者角度开始认识Binder

先聊聊binder,本文不是讲binder,android中的binder框架说实话,要从内核-》驱动-》native-》JNI -》Framework-》app层,牵扯的知识点从内核调度,虚拟内存,内存映射,数据结构,线程管理和设计模式,覆盖面太大了,要真正吃透binder需要大量的时间投入,甚至可能走很多弯路,我的建议对应用开发者,需要熟练掌握AIDL编写方式,理解Binder作者在android框架进程通讯的设计思想,理解常接触的Stub,Proxy这些角色的概念和Parcel序列化传输。

怎样学习binder?我推荐你先看完这个
Binder学习指南

我想做为应用开发者,大都是直接使用的AIDL框架来接触binder的,因为进程通讯的需求在业务开发过程中实在是太常见了。

一,Java层的几个类和概念

  • android.os.IBinder.java : 代表进程通讯的能力。
  • android.os.IInterface.java :客户端和服务端的接口定义(远程接口有什么样的功能)。
  • android.os.Binder.java :可以进程通讯的对象。

角色概念

我想大家都看过科幻剧,一般都有真人投影会议的桥段。

  • Proxy : 代理。影分身,和真人一模一样,客户端通过代理对象访问服务端,感官上和真人说话一模一样。
  • Stub :存根。一般是服务端来实现,就是真人本尊。

方法

  • transact :传送门,开始传送…
  • onTransact :传送门,到达了…

二,从一个AIDL的demo引入思考

demo结构,一个app模块,一个service模块

app模块

.
├── aidl
│ └── com
│ └── demo
│ └── service
│ └── IAidlInterface.aidl
├── AndroidManifest.xml
├── java
│ └── com
│ └── demo
│ └── helloaidl
│ └── MainActivity.java

service模块

.
├── aidl
│ └── com
│ └── demo
│ └── service
│ └── IAidlInterface.aidl
├── AndroidManifest.xml
├── java
│ └── com
│ └── demo
│ └── service
│ └── RemoteService.java

AIDL内容:我利用模板生成,为了好区分,我把方法名修改为add。

// IMyAidlInterface.aidl
package com.demo.service;

// Declare any non-default types here with import statements

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

build后,编译器会帮助我们生成aidl对应的IAidlInterface.java文件,不贴出全部了,重点我截取片段出来。

android的编译器一股脑全部生成在一个类,原本是这样的:

public interface IAidlInterface extends android.os.IInterface{
    
    
	...
	public static abstract class Stub extends android.os.Binder implements com.demo.service.IAidlInterface{
    
    
	...
		private static class Proxy implements com.demo.service.IAidlInterface{
    
    
		}
	}
}

嵌套了两层内部类,其实这个java文件也可以自己编写,我更喜欢这样看:

public interface IAidlInterface extends android.os.IInterface{
    
    }
public abstract class Stub extends android.os.Binder implements com.demo.service.IAidlInterface{
    
    }
private class Proxy implements com.demo.service.IAidlInterface{
    
    }

那么这个结构的类图可以用UML绘制出来

在这里插入图片描述


Framework中binder的调用

一,binder在AMS中的样子

Binder的java层机制在AMS中的实现,可以看到最终AMS是上图中的Stub角色,可以说AMS是一个服务端,即S端。
源码基于aosp 7.1.2,在之后的8.0版本中,ActivityManagerNative内容有所变更,留坑以后补。

在这里插入图片描述

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
    
    
    /**
     * Retrieve the system's default/global activity manager.
     * 通过这个静态方法,App就可以调用ams在IActivityManager注册的接口。
     */
    static public IActivityManager getDefault() {
    
    
        return gDefault.get();
    }
........
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    
    
        protected IActivityManager create() {
    
    
         	// 向SM大管家获取AMS的binder引用
            IBinder b = ServiceManager.getService("activity");
      		...
      		//如果是客户端调用,就返回代理对象。
            IActivityManager am = asInterface(b);
            ...
            return am;
        }
    };
}
    

二,APP获取AMS的Binder代理,进行调用

例如:Activity启动过程中,会调用AMS中去,那么Client访问Server的目的就达成了。

Instrumentation.java

 ActivityManagerNative.getDefault().startActivities(whoThread,who.getBasePackageName(),intents,resolvedTypes,token, options, userId);

三,AMS获取APP的Binder代理

AMS在完成Activity的启动后,需要回调通知app,app也要像AMS那样注册到SM吗?不是的,app在调用AMS的方法时,把自己的binder传给了AMS。

ActivityThread.java

    public static void main(String[] args) {
    
    
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);//启动的时候调用了这个方法。
        ...
    }
 	private void attach(boolean system){
    
    
 		 final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
    
    
            	//这个调用了AMS的方法,传入了一个mAppThread,我们紧接着去看AMS是怎么实现的
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
    
    
                throw ex.rethrowFromSystemServer();
            }
 	}

问题1: mAppThread是什么?

private class ApplicationThread extends ApplicationThreadNative{
    
    }
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{
    
    }
public interface IApplicationThread extends IInterface

基本就和AMS的实现一样,说明ApplicationThread也是一个S端。

问题2: mAppThread是怎样传递给AMS的?

传递的逻辑,如图

在这里插入图片描述

问题3: AMS是怎样调用mAppThread来通知App的?

紧接着就有一次对app的跨进程调用,调用了bindApplication方法。

ActivityManagerService.java#attachApplicationLocked

调用bindApplication方法的逻辑,如图

在这里插入图片描述
理解完上面的调用很重要,至此我们至少熟悉了binder跨进程中调用的流程,这下我们就可以继续下一步正式进行系统启动流程的分析了。

呜谢:

Android Framework 如何学习,如何从应用深入到Framework?

猜你喜欢

转载自blog.csdn.net/lucky_tom/article/details/121678198