开头
准备入职做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的目的就达成了。
ActivityManagerNative.getDefault().startActivities(whoThread,who.getBasePackageName(),intents,resolvedTypes,token, options, userId);
三,AMS获取APP的Binder代理
AMS在完成Activity的启动后,需要回调通知app,app也要像AMS那样注册到SM吗?不是的,app在调用AMS的方法时,把自己的binder传给了AMS。
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跨进程中调用的流程,这下我们就可以继续下一步正式进行系统启动流程的分析了。
呜谢: