进阶之光笔记一

第一章 Android 系统架构

Android系统架构分为五层,从上到下依次是:

  • 应用层
  • 应用框架层
  • 系统运行库层
  • 硬件抽象层
  • Linux内核层

五层内容:

①应用层

主要是系统内置的一些程序和非系统级的应用程序都属于应用层。
比如:Activity Manager/Package Manager/Resource Manager/Window Manager/View System

②应用框架层

提供开发程序所需要的API,平常开发调用的api都是这层的。也叫Java Framewordk.

③系统运行库层

分为两部分:C/C++程序库 & Android运行时库。
C/C++程序库:是android各组件使用的,可以通过应用程序框架给开发者使用。比如SQLite就在其中。(现在市面上android数据库框架虽然多,但是绝大多数都是SQLite的二次封装,所以与其用框架,还不如把SQLite玩精了)
Android运行时库:分为核心库和ART。Android5.0的时候已经用ART将Dalvik替换掉了。Dalvik的应用每次运行时,字节码都需要通过即时编译器(Just In Time,JIT)转换为机器码,这会使应用的运行效率降低。而在ART中,系统在安装应用时会进行一次预编译(Ahead Of Time,AOT),将字节码预先编译成机器码并存储到本地,这样每次运行时就不需要执行编译了,运行效率大大提升。

④硬件抽象层

位于操作系统内核与硬件电路之间的接口层。目的在于将硬件抽象化。

⑤Linux内核层

Android核心服务基于Linux内核,在此基础上添加了部分Android专用的驱动。

在线阅读源码

Androidxref

第二章 Android系统启动

init进程是Android系统中用户控件的第一个进程,进程号为1。极其重要,比如创建Zygote和属性服务

init进程启动过程

启动过程:当我们按下启动电源时,系统启动后会加载引导程序(BootLoader),引导程序又启动Linux内核,在Linux内核加载完成后,就会在系统文件中寻找init.rc文件,并启动init进程。
init启动流程需要分析C++程序代码,因本人没有C++基础,暂且略过,只看一下init进程中都做了什么东西。
init进程工作总结:
(1)创建和挂载启动所需的文件目录
(2)初始化和启动属性服务
(3)解析init.rc配置文件并启动Zygote进程

Zygote简述

在Android系统中,DVM(Dalvik)和ART、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程创建的,故我们也称其为孵化器。
它通过fork(复制进程)的形式来创建应用程序进程和SystemServer,因为通过fork来创建的,所以这些进程里会有一个DVM或者ART的副本。

Zygote启动流程

Zygote进程会启动两个,一个名称为zygote,执行程序为app_process32,作为主模式;一个名称为zygote_secondary,执行程序为app_process64,作为辅模式。


image.png

在app_main.cpp的main()方法中,如果zygote参数为true,就说明当前运行在Zygote进程中,那么就会调用AppRuntime的start函数。这个start函数中就是Zygote启动的核心所在:


image.png

image.png

先是创建了Java虚拟机,接着为Java虚拟机注册JNI方法。
接着通过JNI调用ZygoteInit的main方法。这里要用JNI的原因:
因为ZygoteInit的main方法是由Java语音编写的,当前的运行逻辑是在Native中,这就需要通过JNI里来调用Java.这么一来,Zygote就从Native层进入到了Java框架层。可以说,Zygote开创了Java层。
接着我们进入到ZygoteInit中的main方法,也就是启动Zygote的java层:

image.png

在ZygoteInit的main方法中,同样做了几件十分重要的工作:
①创建了一个Server端的Socket,sockName为"zygote"
②预加载类和资源
③启动SystemServer进程(毫无疑问,是由Zygote进程fork出来的)
④等待AMS请求创建新的应用程序进程(又是一个死循环)
在Zygote进程将SystemServer进程启动后,就会在这个服务端的Socket上等待AMS请求Zygote进程来创建新的应用程序进程。

Zygote进程启动总结:
主要工作如下:
①创建AppRuntime并调用其start方法,启动Zygote进程
②创建Java虚拟机并为Java虚拟机注册JNI方法
③通过JNI调用ZygoteInit的main函数进入 Zygote的Java框架层
④创建服务端Socket,并等待AMS的请求来创建新的应用程序进程
⑤启动SystemServer进程

SystemServer处理过程

SystemServer进程主要用于创建系统服务,我们熟知的AMS/WMS和PMS都是由它来创建的!掌握SystemServer进程如何启动,以及它在启动时做了什么工作十分必要。

image.png

在ZygoteInit中调用handleSystemServerProcess()方法来启动SystemServer进程。
image.png

image.png

在①处创建了PathClassLoader.
在②处调用的zygoteInit方法内部,会调用

ZygoteInit.nativeZygoteInit();

从方法名就可以看出,调用的是native方法。这个方法就是为了启动Binder线程池可以去看对应的JNI文件,因为本人对JNI不熟,所以后续再来完善内部方法分析。启动了Binder线程池后,SystemServer进程就可以使用Binder与其他进程进行通信了。
在nativeZygoteInit()方法下的applicationInit方法

image.png

内部会通过反射来创建SystemServer,并调用其main方法 :
image.png

image.png

image.png

①创建消息Looper
②加载了动态so库libandroid_servers.so
③创建系统的Context
④启动引导、核心、其他服务

总而言之,SystemServer进程主要做了如下三件事:
①启动Binder线程池,这样就可以与其他进程进行通信
②创建SystemServiceManager,其用于对系统的服务进行创建、启动和生命周期管理
③启动各种系统服务(AMS/PMS/WMS等核心服务由此创建!!!)

Launcher启动过程

上面学习了init进程、Zygote进程和SystemServer进程,系统启动的最后一步就是我们的Launcher进程了。
启动一个应用程序来显示系统中已经安装的应用程序这个应用程序就叫做launcher。
Launcher在启动过程中会请求PackageManagerService,PMS返回应用程序信息,Launcher负责展示这些应用程序图标。
Launcher主要作用有两点:
①作为Android系统的启动器,用于启动应用程序。
②作为Android系统的桌面,用于显示和管理应用程序的快捷图标及其他桌面组件。

image.png

Launcher入口为AMS的systemReady()方法,它在SystemServer的startOtherServices中被调用。
怎么说呢,Launcher启动流程后续补充...这块不好整理

Android系统启动流程【从按下开机键开始,Android系统都做了什么?】

1.启动电源以及系统启动
当电源按下时,加载引导程序BootLoader到RAM,然后执行。BootLoader是一个小程序,主要作用就是将系统OS拉起来。
2.Linux内核启动
内核完成系统设置后,会在系统文件中寻找init.rc文件,启动init进程。
3.init进程启动
初始化和启动属性服务,启动Zygote进程。
4.Zygote进程启动
创建Java虚拟机并为Java虚拟机注册JNI方法,创建服务端Socket,启动SystemServer进程。
5.SystemServer进程启动
启动Binder线程池和SystemServiceManager,并且启动各种系统服务。(PMS/WMS/AMS等)
6.Launcher启动
被System进程启动的AMS会启动Launcher,Launcher启动后会将已安装的快捷图标显示到界面上。
流程图如下:

image.png

第三章 应用程序进程启动过程

上一章讲解了Android系统如何启动的,这一章我们就来看一下"应用程序进程启动流程",注意不是"应用程序启动过程"。这个知识点虽然没有后面提及的多,但也是大厂面试常客了,不要和后者混淆就好。

应用程序进程简介:
AMS在启动应用程序之前会检查这个应用程序所需的进程是否存在,如果没有就会请求Zygote进程启动所需的应用程序进程。之前说过在Zygote的Java层,也就是ZygoteInit中会创建一个服务端的Socket,这个Socket,就是用来等待AMS向Zygote请求创建应用程序进程。Zygote进程通过fork自身创建应用程序进程,同时创建Binder线程池和消息循环。这样我们的应用程序就可以使用Binder进行进程间通信了。
应用程序进程启动主要分为两部分:
①AMS发送启动应用程序进程请求
②Zygote接收请求并创建应用程序进程

AMS发送启动应用程序进程请求

image.png

AMS 通过调用startProcessLocked方法向Zygote进程发送请求,


image.png

image.png

image.png

拿到用户id(uid)和用户组ID(gid),调用Process.start方法。接着会调用ZygoteProcess里的start方法,ZygoteProcess用于保持与Zygote进程的通信状态。

image.png

start方法里最终会会走ZygoteProcess里的startViaZygote(~)方法中,可以看到这个方法的注释:通过zygote机制创建一个新的进程!可以看出来,此方法就是我们应用程序创建的核心流程所在了。
argsForZygote字符串列表会存储应用进程的启动参数。
从上图还可以看出有个位运算实际运用的场景:控制权限。
可以通过与、或运算来控制权限,在权限较多的情况下,通过位运算来控制权限十分方便。这里提供一个通过位运算来控制权限的工具类:

public class NewPermission {
    //通过二进制位来判断权限,比如1111,说明所有权限都有;1110,只有除了查询之外的权限;
    //1010,只有删除和插入权限,so on...

    public static final int ALLOW_SELECT = 1 << 0; // 0001
    public static final int ALLOW_INSERT = 1 << 1; // 0010
    public static final int ALLOW_UPDATE = 1 << 2; // 0100
    public static final int ALLOW_DELETE = 1 << 3; // 1000
    //存储目前权限状态
    private int flag;

    public int getCurrentPermission(){
        return flag;
    }

    public void resetPermission(int permission) {
        flag = permission;
    }

    //添加一项或者多项权限
    public void enable(int permission) {
        flag |= permission;
    }

    //移除一项或者多项权限
    public void disable(int permission) {
        flag &= ~permission;
    }

    //是否有用某项权限
    public boolean hasPermission(int permission) {
        return (flag & permission) == permission;
    }

    //是否禁用了某些权限
    public boolean hasNotPermission(int permission) {
        return (flag & permission) == 0;
    }

    //是否禁拥有某些权限
    public boolean isOnlyAllow(int permission) {
        return flag == permission;
    }


}

使用:

image.png

也可以像源码中一样通过与运算,来判断是否拥有某种权限,十分的方便!
言归正传:
image.png

image.png

openZygoteSocketIfNeeded方法中,注释①处,AMS会与Zygote建立Socket连接。此方法返回的ZygoteState是ZygoteProcess的静态内部类,用于表示与Zygote进程通信的状态。
如果通过zygote主模式建立的socket与启动应用程序所需的ABI不一致,就会启动辅模式来进行AMS和Zygote的socket连接。都失败,就会抛出ZygoteStartFailedException异常。
到这里,实际上我们的第一步就完成了,也就是AMS向Zygote发送启动应用程序进程请求。

Zygote接受请求并创建应用程序进程

image.png

时序图如上。
我们回到之前说的Zygote进程创建的时间点,在Zygote的Java层,也就是ZygoteInit的main方法中曾创建了一个服务端的Socket:
image.png

① 创建了一个Server端的Socket,socketName的值为"zygote"
②预加载类和资源
开启死循环等待AMS请求
image.png

可以看到while(true)这个Socket会一直运行等待新的请求。同时我们也可以看到,当有新的连接建立时,会调用ZygoteConnection的runOnce方法来处理AMS发过来的请求数据
image.png

获取应用程序进程的启动参数,如果参数为空,直接关闭本次socket连接。

image.png

①处调用Zygote.forkAndSpecialize方法,传入用户的uid、用户组id,创建应用程序进程,并返回进程id(pid).此方法主要就是通过fork当前进程来创建一个子进程的。
②处,pid等于0就表明应用程序进程创建成功了!接着会调用handleChildProc方法来处理我们的应用程序进程。 如注释所以,如果pid<0,则说明创建失败了。
handleChildProc方法中会调用ZygoteInit.nativeZygoteInit()方法,如下图:

image.png

注释1处,也就是ZygoteInit.nativeZygoteInit(),会在新创建的应用程序中创建Binder线程池。
注释2处,调用RuntimeInit的applicationInit()方法,顾名思义,此方法用于在新的应用进程中创建Application.此方法会调用invokeStaticMain方法:
c

image.png

image.png

通过反射获得了android.app.ActivityThread(①),并获取ActivityThread的main方法(②)。抛出异常被ZygoteInit的main方法捕获后会调用invoke ActivityThread的 main方法,这样应用程序进程就创建完成了并且运行了主线程的管理类ActivityThread.

Binder线程池启动过程

前面说过ZygoteInit的zygoteInit方法中会调用nativeZygoteInit()方法来创建Binder线程池


image.png

可以看出这个一个JNI方法,会调用到ProcessState.cpp中的startThreadPool方法来创建Binder线程池:


image.png

image.png

重点来了:
支持Binder通信的进程中都有一个ProcessState类,它里面有个mThreadPoolStarted变量,用来表示Binder线程池是否已经被启动过,默认值为false。在每次调用startThreadPool函数时,都会检查这个标记,确定一个应用程序进程的Binder线程池只会被启动一次。如果未被启动,就会调用spawnPooledThread函数来创建线程池中的第一个线程,也就是线程池的主线程。
Binder线程为一个PoolThread,run方法中会调用IPCThreadState的joinThreadPool函数,将当前线程也就是Binder主线程注册到Binder驱动程序中,这样我们创建的线程就加入了Binder线程池中,新创建的应用程序进程就支持Binder进程通信了。

消息循环创建过程

应用程序进程启动后会创建消息循环。前面我们讲Zygote进程创建应用程序进程时,最后会调用ActivityThread的main方法,创建应用程序的主线程。消息循环的创建就在此main方法中:

image.png

首先调用Looper.prepareMainLooper()方法,创建主线程Looper.之后thread.getHandler()会创建主线程H类,这是ActivityThread的内部类,用于处理主线程的消息循环!最后调用Looper.loop()方法开始工作,进入消息循环。

四大组件的工作过程(activity等启动流程)

本章十分十分十分重要!是整个Android知识体系的核心内容之一,对于理解和掌握整个Android知识体系起着重大的作用!!同时本章也是理解插件化原理的必知点。
Activity的启动流程分为两种:
1.根Activity的启动过程
2.普通Activity的启动流程,也就是从一个Activity跳到另外一个Activity
我们要分析的就是根Activity的启动流程。

根Activity的启动流程

根Activity的启动流程,分为三个部分:
①分别是Launcher请求AMS过程
②AMS到ApplicationThread的调用过程
③ActivityThread启动Activity

1.Launcher请求AMS过程
P82页时序图

image.png

当我们点击应用程序的快捷图标时,就会调用Launcher的startActivitySafely方法
将FLAG设置为Intent.FLAG_ACTIVITY_NEW_TASK,这样根Activity会在新的任务栈中启动。

startActivity会调用startActivityForResult方法,接着会调用Instrumentation的execStartActivity。Instrumentation主要用来监控应用程序和系统的交互。
image.png

image.png

首先调用ActivityManage的getService方法获取到AMS的代理对象:ActivityManagerProxy。这里的单例对象创建的过程中使用的是AIDL技术,这是8.0新增的,8.0之前用的是类似AIDL的形式。总之execStartActivity方法就是通过AIDL拿到AMS,调用其startActivity方法。
2.AMS到ApplicationThread的调用过程
P86时序图

image.png

ActivityManagerService中的startActivity方法会调用startActivityAsUser,这个方法会获得调用者的UserId,通过此ID来确定调用者的权限。在此之前的方法会判断调用者进程是否被隔离,两者都可能会抛出SecurityException.
然后会调用ActivityStarter里的startActivity方法。[ActivityStarter是7.0新增的类,是加载Activity的控制类。此类会收集所有的逻辑来决定如何将Intent和Flags转换为Activity]

image.png

image.png

此方法中,通过mService.getRecordForAppLocked得到Launcher进程的ProcessRecord【ProcessRecord用于描述进程信息】,如果进程不存在就会将状态置为START_PERMISSION_DENIED.
接着会创建即将要启动的Activity的描述类ActivityRecord。startActivity方法调用了startActivityUnchecked方法
image.png

其内部会创建TaskRecord,用来描述一个Activity任务栈,这个任务栈是一个假想的模型,并不真实存在。
image.png

在创建好两个Record之后,在ActivityStack中判断当前要启动Activity对应的ActivityRecord是否为空,如果不为空或者Activity的状态不为resumed,就会走到ActivityStackSupervisor的startSpecificActivityLocked方法中去:
image.png

此方法中会获取即将启动的Activity所在的应用程序进程,并判断要启动的Activity所在的应用程序进程是否已经运行,如果已经运行就会调用realStartActivityLocked方法
image.png

image.png

此方法调用的app.thread.scheduleLauncheActivity方法中的app.thread指的是IApplicationThread,它的实现是ActivityThread的内部类ApplicationThread,以上的代码都运行在AMS所在的进程中,也就是SystemServer进程中。

image.png

ApplicationThread继承了IApplicationThread.Stub[Binder机制],可以看出AMS就是通过Binder机制来与应用程序进行通信。ApplicationThread就是AMS所在进程(SystemServer )与应用程序进程的通信桥梁。

ActivityThread启动Activity的过程

时序图

1417629-50a4962ca419692e.png

上面我们走到了ApplicationThread的scheduleLaunchActivity里,ApplicationThread是ActivityThread的内部类。
image.png

此方法主要就是将启动Activity的参数封装成ActivityClientRecord.发送LAUNCH_ACTIVITY消息给H类,此H类是ActivityThread的内部类并继承Handler,它是应用程序进程中主线程的消息管理类。因为ApplicationThread是一个Binder,它的调用逻辑运行在Binder线程池中,所以我们需要将H代码的逻辑切换到主线程中。
友情提示,9.0已经去除了H类。
image.png

H类中接收到LAUNCH_ACTIVITY消息后,解析参数:将LoadedApk类型的对象赋值给ActivityClientRecord的成员变量packageInfo.应用程序进程要启动Activity时需要将该Activity所属的APK加载进来,而LoadedApk就是用来描述已加载的APK文件的。
接着调用handleLaunchActivity方法
image.png

此方法中的performLaunchActivity用来启动Activity。handleResumeActivity用来将Activity的状态置为Resume.如果activity为null,就会通知AMS停止启动Activity.
看一下启动Activity的核心方法:performLaunchActivity.这个方法十分重要,我们一步一步来:
image.png

①获取ActivityInfo,存储AndroidManifes设置的Activity和Receiver节点信息
②获取APK文件的描述类LoadedApk.
③获取要启动Activity的ComponentName类。在此类中存储了Activity的包名和类名。
④创建Activity的上下文环境。
⑤根据ComponentName中存储的Activity类名,用类加载器来创建Activity实例。

image.png

image.png

image.png

image.png

⑥makeApplication创建Application,内部会调用Application的onCreate
⑦创建Window对象[PhoneWindow]并与Activity自身进行关联
⑧最后调用Instrumentation的callActivityOnCreate方法来启动Activity!(此方法中会调用performCreate方法,内部会调用Activity的onCreate方法。)

至此,简单分析根Activity的启动流程已经OK了。
还有一些疑惑点:// TODO

①比如清单文件里的各种属性值是怎么存到ActivityInfo里,每个字段值对应的逻辑是如何处理的,主Activity那个字段怎么判断的;
②Activity除了onCreate之外的其他生命周期如何调用
后续补上。

根Activity启动过程中涉及的进程

根Activity启动过程中会涉及4个进程:
Zygote进程、Launcher进程、AMS所在进程(SystemServer进程)、应用程序进程(主进程)
根Activity启动涉及进程图

image.png

image.png

首先Launcher进程向AMS请求创建根Activity,AMS会判断根Activity所需的应用程序进程是否存在并启动,如果不存在就会请求Zygote进程创建应用程序进程。应用程序进程启动后,AMS会请求创建应用程序进程并启动根Activity.其中AMS与Zygote采用的是Socket通信。1和4,也就是Launcher进程和AMS进程通信以及AMS进程与应用进程通信采用的是Binder通信。

如果是普通Activity启动,涉及到的进程就两个:AMS所在进程和应用程序进程。

Service的启动过程

service的启动过程主要分为两个部分:
**
①ContextImpl到ActivityManagerService的调用过程
②ActivityThread启动Service
**

ContextImpl到AMS的调用过程

image.png

要启动service,我们会调用startService方法,它在ContextWrapper中实现:
image.png

这里的mBase,实际上就是我们ActivityThread的内部类H调用的performLaunchActivity里创建的:
image.png

image.png

在Activity的attach方法中将ContextImpl赋值给ContextWrapper的成员变量mBase.mBase指向的就是ContexImpl。也就是说startService的实际逻辑在ContextImpl的startService方法中!
image.png

调用的是AMS的startService方法
AMS的startService方法中调用ActiveService的startServiceLocked方法。
image.png

此方法会查找是否有与参数service对应的ServiceRecord,如果没有找到则调用PackageManagerService去获取参数service对应的Service信息,并将其封装到ServiceRecord中,最后将ServiceRecord封装为ServiceLookupResult返回。
再拿到ServiceRecord后,在方法最底部会调用startServiceInnerLocked方法:
内部会接着调用bringUpServiceLocked方法
image.png

①处就是用来描述描述Service想要在哪个进程中运行,默认是当前进程。可以在清单文件中设置android:process属性来开启一个新的进程。
②处查询是否存在一个与Service对应的ProcessRecord类型的对象app,ProcessRecord主要用来描述运行的应用程序进程信息。
此方法就是用来判断运行Service的应用程序进程是否存在,如果不存在则调用AMS的startProcessLocked方法来创建对应进程。如果存在则调用realStartServiceLocked方法来启动Service.如下图所示
image.png

image.png

image.png

内部会调用ApplicationThread的scheduleCreateService()方法
image.png

将参数封装成CreateServiceData,发送事件给H类;跟Activity的启动流程类似了,所以其实现还是在H类中的handleMessage方法中:
image.png

调用handleCreateService()方法:
image.png

获取APK文件的描述类LoadedApk,从而获取到类加载器,创建Service实例。创建Service的上下文环境ContextImpl对象,作为参数传入attach方法中来初始化Service,接着调用Service的onCreate方法,这样Service就启动了。
Service启动流程大概是这样的,下面我们看一下Service的绑定过程。

Service的绑定过程

绑定Service的过程比启动Service的过程更复杂一些。
绑定Service分为两个部分:
1.ContextImpl到AMS的调用过程
2.Service的绑定过程

ContextImpl到AMS的调用过程

bindService里的实现也是在ContextImpl里,其内部调用了bindServiceCommo方法:

image.png

此方法中将ServiceConnection封装成IServiceConnection,实现了Binder机制,这样service的绑定过程就支持了跨进程。接着调用AMS的bindService方法。
接下来会调用bindServiceLocked-->bringUpServiceLocked方法-->realStartServiceLocked方法
最终由ActivityThread来调用Service的onCreate方法启动Service,说明bindService里也会启动Service.
image.png

AppBindRecord中intent的received存储了当前应用程序进程已经接收到绑定Service时返回的Binder。这样应用程序进程就可以通过Binder来获取要绑定的Service的访问接口。(AppBindRecord维护Service与应用程序进程之间的关联。)
TODO//为了赶进程,Service这块我们只捡一些核心的说,准备一个月投简历,这本书不能细读了。
接着会调用到ApplicationThread里的scheduleBindService方法,其内部会将Service的信息封装成BindServiceData对象发送BIND_SERVICE事件到H类中,在handleMessage里调用handleBindSerivce方法,根据BindServiceData里的rebind方法来判断是否已经绑定过Service
image.png

如果未绑定的话,会调用AMS的publishService方法。接着调用ServiceDispatcher.InnerConnection里的connect方法,此方法内部会调用H类的post方法将RunConnection对象的内容运行在主线程。RunConnection实现了Runnable接口,其内部的doConnect方法调用了ServiceConnection里的onServiceConnected方法。这样ServiceConnection接口类的onServiceConnected方法就会被执行,Service的绑定过程也就完成了。

广播的注册、发送和接收过程

TODO

ContentProvider的启动过程

你可能感兴趣的:(进阶之光笔记一)