总结android中一些基础且重要的知识点

当你面对浩瀚如海的源码时,你需要一些主要脉络、基础且重要的线索来帮你理清繁杂的头绪,犹如模糊不清的世界地图,它就像撬起地球的支点——虽然不是那根棒,但也比较有用。

 

java层相关

 

service = context组件 + binder

 

IntentService = Service + HandlerThread + ServiceHandler(Handler);

在onStart中把接收到的intent设置到msg.obj,并在HandlerThread的线程上下文中回调 onHandleIntent() ,每次接收到新intent时,在onStart中给的startID,单调递增,每次跑完一个intent,将该intent一起给过来的startID,传入stopSelf(startID),因为intent的msg是队列的方式丢给Handler的,那么当最后一个收到的Intent的msg处理完后,stopSelf() 的 startID等于 onStart()给的最后一个startID,那么当前service停止

简单来说,就是一个带有后台工作线程专门处理发来的intent的Service

 

JobService = Service + IJobService(Binder服务) + JobHandler(Handler,looper基于MainThread)

自定义类继承它后,实现onStartJob和onStopJob,这2个函数在JobHandler中根据IJobService这个binder接收到的函数调用(startJob或stopJob)在MainThread的Looper线程上下文中被回调。

简单来说,就是一个带有固定binder服务方法(startJob或stopJob)和参数(JobParameters类型参数)的,且把消息跑在MainThread上的,带有handler队列的service

再简化一点说,就是一个带有默认binder可以发送JobParameters 来 startJob()或stopJob() 的service

 

Messenger = Handler + IMessenger(Binder服务);

(IMessenger 是一个基于binder的aidl,在Framework层以aidl文件定义,只有send(message)这一个方法被声明,只支持让client方send一个message,server的实现是handler的内部类(MessengerImp extends IMessenger.Stub),接收到send调用后,会将binder传递过来的msg对象,用当前所属handler对象的sendMessage方法插入到messageQueue中), 可以基于binder让进程以Handler的收发message对象的方式进行IPC

这样看来其实可以不用Messenger,对于Handler的基于binder的IPC,只要自己在2个进程间用任意一个自定义的,支持发送message对象的binder服务,再加上接收到msg消息后,将他转发到handler,就可以实现一样的功能;只不过这里Messenger和Handler已经帮我们封装好了基于binder的IPC方式发送message对象到server端的Handler的方法。

 

Handler = Looper + MessageQueue

 

Looper = ThreadLocal.set(new Looper())

线程独有

一个Thread只有一个属于它的Looper,一个Looper只有一个属于他的MessageQueue,一个Looper可以有多个属于他的Handler

Threrad 1:1 Looper, Looper 1:1 MessageQueue,Looper 1:N Handler

 

一个普通的C层线程(普通的JVM进程),是如何成为 android - java 线程的MainThread(UIThread)的?

先说主要概念再说解答,主要有3个:

1.普通C层线程(linux上也就是pthread)。

2.JVM线程(普通C线程通过JavaVM->attachCurrentThread(),成为JVM上下文线程,才可以调用java方法)。

3.androidJava线程(JVM线程通过调用Looper.perpaer(),拥有Looper对象成为Looper线程(也管他叫androidJava线程),其中的一个特例是 UIThread,它也叫 MainLooperThread,的mainThread(UIThread),一个JVM中只有一个MainLooperThread)

解答:主要看Looper.prepareMainLooper(); 方法在哪里执行,一共有2个地方 

1.ActivityThread.main() - 一个普通app进程,非zygote系列进程的入口(我们的自定义APP就属于这一类)

2.SystemServer.java - main() - run() - 从zygote分裂出来用于执行Framewrok层服务集的服务进程

 

 

A1.普通C层线程的来源?

1.由操作系统系统调用完成,通过父进程(如init进程)使用fork() 创建子进程,这个子进程拥有默认的新的主线程

2.通过android封装的C层Thread 类,间接的创建 pthread 线程;或直接手动创建pthread线程

 

A2.JVM线程的来源?(也就是问普通C线程如何变为JVM上下文线程?)

1C线程成为JVM主线程:

  从init进程fork后执行app_process可执行文件,等于app_main.cpp文件中的main()函数,执行AndroidRunTime::start()方法,从该方法中启动虚拟机 startVm() -> JNI_CreateJavaVM() ->  dvmCreateJNIEnv(NULL) 让当前线程成为JVM主线程,启动虚拟机的c线程默认成为JVM的主线程;

 

2.C线程成为普通JVM线程:(也就是问在虚拟机运行起来之后的普通c线程如何成为JVM线程)

  2.1。普通C线程 pthread:

      直接调用  javaVM->AttachCurrentThread() = attachThread() -> dvmAttachCurrentThread() -> dvmCreateJNIEnv(self) 让当前C线程成为JVM线程

  2.2。创建一个通过android封装的Thread对象:

      调用在执行完AndroidRunTime::start()启动虚拟机后,调用了 【startReg() -> androidSetCreateThreadFunc() -> 修改当前进程全局变量 gCreateThreadFn函数指针 为 javaCreateThreadEtc()】 这一长串,在此之后创建一个新的C层Thread对象,那么新建的子线程便会先执行javaCreateThreadEtc() -> javaThreadShell() -> javaAttachThread() -> jvm->AttachCurrentThread() ,此时从普通C层线程成为JVM线程(和2.1一样的逻辑),然后调用指定的start() 方法 , 进入指定java类的main方法.

  2.3. JAVA层new一个Thread对象:

      重点为java层Thread.start()方法,主要从VMThread.create() 这个 Native方法开始执执行,然后接着执行【 -> java_lang_VMThread.c 的 Dalvik_java_lang_VMThread_create() -> Thread.c - dvmCreateInterpThread() -> pthread_create()】这一长串,此时创建了C层子线程,然后子线程执行 interpThreadStart() -> dvmCreateJNIEnv() 此时从普通C线程成为JVM线程;此外还有基于ART虚拟机的java线程创建;

 

A3.Looper线程的来源?

1.JVM线程成为普通Looper线程

  java层new一个Thread对象后,(【】中的细节可忽略不看)【通过Thread.start() -> ... -> self->threadObj->clazz->vtable[gDvm.voffJavaLangThread_run] C层根据虚函数表找到run的Method并进入java层run方法执行 -> ... -> Thread.run()】,然后用子线程调用Looper.perpar() 成为Looper线程

2. JVM线程成为MainLooper线程

  从 A1.1 -> A2.1 这个情况出发,执行app_process可执行文件时,执行到AndroidRuntime::start()时,最终都会执行到Looper.prepareMainLooper()方法

  2.1.startSystemServer 参数 = false 时

    执行无参数的AndroidRuntime::start() -> AndroidRuntime::start(" com.android.internal.os.RuntimeInit") -> 此时以c层JVM主线程身份进入java层的 RuntimeInit.main()  方法,在RuntimeInit.main()中调用Looper.prepareMainLooper()成为MainLooperThread

  2.2.startSystemServer 参数 = true 时

    从init中fork执行app_process,在main() 中执行AndroidRuntime::start(“com.android.internal.os.ZygoteInit”,true) -> startSystemServer() -> Zygote.forkSystemServer() -> fork出子进程,接下来以父子进程角度分别看

      2.2.1.子进程的主线程此时以C层JVM主线程身份进入java层的 com.android.server.SystemServer.main()  方法 -> 执行Looper.prepareMainLooper(), 成为MainLooperThread

      2.2.2.父进程则继续执行AndroidRuntime::start(“com.android.internal.os.ZygoteInit”,true), 进入java层 ZygoteInit.main() -> runSelectLoopMode() / runForkMode() 进入死循环,监听UDS命令消息;此时依旧是JVM主线程身份,并没有成为MainLooperThread

 

 

一个普通C层线程从诞生,到变为jvm上下文线程,再到变为android mainLooper线程(UIThread)的过程中的关键点是?

1.成为普通c线程诞生:1.android 的c层封装了pthread为 Thread类,在Thread::androidCreateRawThreadEtc() 中创建了pthread并运行起来,2.或者由fork()直接创建新进程的默认的主线程 3.Java层new一个Thread对象,调用start()

2.成为jvm上下文线程:在普通c线程运行的第一个函数,根据mCanCallJava开关,进入AndroidRuntime::javaThreadShell() 方法,执行了jvm->javaAttachThread() 成为了jvm上下文线程

3.成为android mainLooper线程:在javaThreadShell() 方法里进入start()方法,启动java虚拟机,并进入指定java方法,这里是 com.android.internal.os.RuntimeInit.main() , 在RuntimeInit.main()中调用Looper.prepareMainLooper()成为MainLooperThread。

 

 

Native层相关 

 

sp = RefBase / LightRefBase + 基于引用计数 + 基于构造和析构函数的 模仿java强指针进行自动对象释放的C++层强指针

wp = RefBase + 基于引用计数 + 基于构造和析构函数的 模仿java弱指针进行自动对象释放的C++层弱指针

 

 

入口相关

 

-------bootloader-------

Uboot - start.S - ENTRY(_start)  bootloader 第一阶段汇编层入口

Uboot - board.c - start_armboot() bootloader 第二阶段入口

-------kernel-------

arch/arm/kernel/head.S - ENTRY(stext) - kernel第一阶段入口

init/main.c - start_kernel() - kernel第二阶段c层函数入口

-------用户态-------

init - app_main.cpp - main() 内核启动后,用户态第一个进程的入口

-------java层-------

RuntimeInit.java - main() 一个新jvm(带有虚拟机;入口来源:从Zygote fork进入,或者从android在C层封装的Thread,成为jvm上下文线程后进入;线程状态:进入main()函数后成为mainLooperThread)的java层主线程入口

ZygoteInit.java - main() init启动的从c层到java层(带有虚拟机;线程状态:不是mainLooperThread,只是普通jvm线程)的framework层入口

SystemServer.java - main() java世界的Framework服务集的入口(从ZygoteInit fork出来;线程状态:进入main()函数后成为mainLooperThread)

ActivityThread.java - main() 一个新app进程的java层入口(从ZygoteInit fork出来;线程状态:进入main()函数后成为mainLooperThread)

 

 

 

好好背题,好好面试,好好成为多汁水,耐榨汁的人力资源制造机

posted on 2020-01-07 12:25  jald  阅读(433)  评论(0编辑  收藏  举报

导航