Android高级面试问题及答案(1)——Android Framework篇

问题1.Android系统的启动过程?

主要分为几个部分:

init进程启动

1.按下电源,启动引导程序 BootLoader,启动linux内核,init进程启动,所以init是android系统的第一个进程,进程号为1。
2.init进程主要做以下几件事:
1)创建和挂载启动所需要的文件目录
2)初始化和启动属性服务,属性值的更改仅能在init进程中进行,通过socket来响应其它进程提交的申请。

主要方法逻辑在init.cpp

	......
	//创建一块共享的内存空间,用于属性服务
	property_init();
	......
 	//启动属性服务器,此处会调用epoll_ctl设置property fd可读的回调函数
    start_property_service();  
   	....... 

3.处理子进程( Zygote 进程)异常退出,也是通过socket
主要目的:回收僵尸进程
在Linux内核中,如父进程不等待子进程的结束直接退出,会导致子进程在结束后变成僵尸进程,占用系统资源

......
sigchld_handler_init();//注册子进程死亡监听socket
......

4.解析并执行init.rc文件
5.init.rc中命令启动Zygote

详细源码解析见Android Framework分析(1)-init

初始化epoll,依次设置signal、property、keychord这3个fd可读时相对应的回调函数;
进入无限循环状态

init进程在开机之后的核心工作就是响应property变化事件和回收僵尸进程。当某个进程调用property_set来改变一个系统属性值时,系统会通过socket向init进程发送一个property变化的事件通知,那么property fd会变成可读,init进程采用epoll机制监听该fd则会 触发回调handle_property_set_fd()方法。回收僵尸进程,在Linux内核中,如父进程不等待子进程的结束直接退出,会导致子进程在结束后变成僵尸进程,占用系统资源。为此,init进程专门安装了SIGCHLD信号接收器,当某些子进程退出时发现其父进程已经退出,则会向init进程发送SIGCHLD信号,init进程调用回调方法handle_signal()来回收僵尸子进程。

Zygote进程启动

zygote由java编写而成,不能直接由init进程启动运行。必须先创建虚拟机,然后在虚拟机上运行ZygoteInit类。执行这一任务的就是app_process程序。

1.init.rc中使用android初始化语言,通过service命令启动app_process,以64位系统的init.zygote64.rc为例子:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

2.app_process64也就是Zygote进程启动,执行app_main.cpp下的main方法,通过AndroidRuntime的start执行ZygoteInit的方法

if (zygote) {
        //zygote进程
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        //普通java进程
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    }

3.AndroidRuntime的start中做了如下逻辑:
1)创建java虚拟机
2)注册jni函数,这样就可以调用java方法
3)通过jni调用com.android.internal.os.ZygoteInit的main方法,ZygoteIni是java类,此时Zygote就由native世界切换到了java世界,Zygote 开创了 Java 框架层

//AppRuntime继承自AndroidRuntime
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    /* start the virtual machine */
    JniInvocation jni_invocation;
    // ① 加载指定的虚拟机的库(art或者dalvik)
    jni_invocation.Init(NULL); 
    JNIEnv* env;
    // ② 创建java虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }

    // ③ 注册JNI函数
    if (startReg(env) < 0) {
        return;
    }

    ......
    // ④ 正式进入java的世界,调用ZygoteInit.java的main方法
    jclass startClass = env->FindClass(slashClassName);
    ......
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
    ......
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
    ......
}

4.ZygoteInit类功能,main下做了如下逻辑:
1) 创建名为zygote的 socket,用来接收AMS发来的创建新Android应用进程的请求
2)预加载类和资源,后面从zygote进程fork出的应用进程可以直接共享,加快应用进程启动速度
3)forkSystemServer fork出system_server子进程
4)zygoteServer.runSelectLoop()在zygote进程中无限循环,使得zygote不会退出,等待 AMS 请求创建新的应用程序进程。

public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
    ......
    try{
        boolean startSystemServer = false;
        String socketName = "zygote";//套接字默认名称zygote
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
           }
            ......
        }

        // ① 绑定/dev/socket/zygote套接字,用来接收Android应用程序运行请求
        zygoteServer.registerServerSocketFromEnv(socketName);
        ......
          
        if (!enableLazyPreload) {
            ......
            // ② 预加载类与资源
            preload(bootTimingsTraceLog);
            ......
        }

        ......
        if (startSystemServer) {
            // ③ fork出system_server子进程
           Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

            // ③ {@code r == null}表示是父进程(zygote),{@code r != null}在子进程(system_server)
            if (r != null) {
                // ③ 如果是子进程(system_server)就执行run()方法,并返回,父进程(zygote)就继续往下执行
                r.run();
                return;
            }
        }

        Log.i(TAG, "Accepting command socket connections");

        // ④ 这轮询会在zygote进程中无限循环,而fork出的子进程(Android应用进程)会退出来
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        //system_server进程和android应用进程会关闭socket,zygote仍然在runSelectLoop中轮询监听socket
        zygoteServer.closeServerSocket();
    }
    

    // ④ Android应用进程会走到这儿,执行相应的命令
    if (caller != null) {
        caller.run();
    }
}

详细源码解析见Android Framework分析(3)——Zygote进程源码分析

SystemServer进程创建

SystemServer 进程主要用于创建系统服务,我们熟知的 AMS WMS PMS 都是由它来创建的
主要工作如下,下面的流程均执行在SystemServer进程:
1.启动Binder线程池
主要逻辑在Runtimelnit.java的nativeZygotelnit函数

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();
        commonInit();
        nativeZygoteInit();//1
        applicationInit(targetSdkVersion, argv, classLoader);//2
    }

2.反射创建SystemServer类,反射调用其main方法
3.SystemServer.java的main中创建SystemServiceManager类(对系统的服务进行创建、启动和生命周期管理),创建系统context,启动各种服务(引导服务,核心服务,其他服务),AMS是引导服务中启动

			createSystemContext();//3
 			startBootstrapServices();//5
            startCoreServices();//6
            startOtherServices();//7

4.SystemServiceManager通过调用服务对象的构造方法和onStart方法初始化服务的相关变量;

详细源码解析见Android Framework学习(三)之SyetemServer进程启动解析

问题2.Android的Laucher是如何创建的?

1.SystemServer进程中startOtherServices中会调用到ActivityManagerService的startHomeActivityLocked方法
2.通过隐式intent启动桌面Activity,名称为Launcher,Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME
Android高级面试问题及答案(1)——Android Framework篇_第1张图片
3.Launcher中应用图标显示

  1. 创建工作区
    Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标,每一个工作区都是来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分n个单元格,每个单元格用来显示一个应用程序的快捷图标。
    2)加载系统已经安装的应用程序信息
    主要是通过Laucher进程查询系统的launcherapps服务来查询安装信息
    Android高级面试问题及答案(1)——Android Framework篇_第2张图片
    Android高级面试问题及答案(1)——Android Framework篇_第3张图片
    3) Launcher.java中mAppsView是AllAppsContainerView,AllAppsContainerView的onFinishlnflate中获取recyclerview,将返回的AppInfo绑定到recyclerview,桌面图标就显示出来了
public void bindAllApplications(ArrayList<AppInfo> apps) {
        mAppsView.getAppsStore().setApps(apps);

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.bindAllApplications(apps);
        }
    }

问题3 App的进程是如何启动起来的?

我们知道在 Zygote 在Java框架层中会创建 Server 端的 Socket ,这个 Socket 用来等待 AMS 请求 Zygote 来创建新的应用程序进程。Zygote 进程通过 fock 自身创建应用程序进程,这样应用程序进程就会获得 Zygote
进程在启动时创建的虚拟机实例,以及Binder 线程地和消息循环。

1)AMS发送创建App进程请求
Android高级面试问题及答案(1)——Android Framework篇_第4张图片
Android高级面试问题及答案(1)——Android Framework篇_第5张图片
将应用进程的启动参数 argsForZygote 写入ZygoteState 中,ZygoteState connect Zygote的socket时,就会读取这个参数

2)Zygote 接收请求并创建应用程序进程
Android高级面试问题及答案(1)——Android Framework篇_第6张图片
主要是以下几个流程:
(1)看 ZygoteServer的 runSelectLoop 方法不停轮询,等待创建新进程的socket请求
(2)请求过来调用connection.processOneCommand()传入ZygoteServer自身,在其中Zygote根据传来的argsForZygote参数,创建App进程
Android高级面试问题及答案(1)——Android Framework篇_第7张图片
(3).handleChildProc方法中ZygoteInit.zygoteInit,调用RuntimeInit.applicationInit()
Android高级面试问题及答案(1)——Android Framework篇_第8张图片

Android高级面试问题及答案(1)——Android Framework篇_第9张图片
(4)最终反射创建要启动App进程的ActivityThread类,并调用其main方法,App进程创建完毕
Android高级面试问题及答案(1)——Android Framework篇_第10张图片
Android高级面试问题及答案(1)——Android Framework篇_第11张图片

问题4:点击桌面图标,是如何启动App的Activity的

应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出这个 apk 的信息写入到 packages.xml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。
Android高级面试问题及答案(1)——Android Framework篇_第12张图片
1.点击图标,调用Launcher.startActivitySafely(),然后调用到Activity的startActivity
2.Instrumentation的execStartActivity,调用AMS的startActivity,切换到systemServer进程
Android高级面试问题及答案(1)——Android Framework篇_第13张图片

3.然后到ActivityStarter的startActivityMayWait中,这里要关注ProcessRecord用于描述应用程序,ActivityRecord用于描述Activity的信息
4.检查activity的进程启动起来没,如果没有AMS请求zygote fork出进程
ActivityStackSupervisor.java
Android高级面试问题及答案(1)——Android Framework篇_第14张图片

5.结合activity的启动模式,查看activity的任务栈是否创建,如果没有创建则创建栈,任务栈是理想模型,并不真实存在
6.ActivityStackSupervisor的realStartActivityLocked方法,会调用要启动App的scheduleTransaction方法,传入的参数是ClientTransaction
Android高级面试问题及答案(1)——Android Framework篇_第15张图片
7.Handler发送EXECUTE_TRANSACTION消息
Android高级面试问题及答案(1)——Android Framework篇_第16张图片
Android高级面试问题及答案(1)——Android Framework篇_第17张图片
8.调用TransactionExecutor的execute,然后执行executeCallbacks方法
Android高级面试问题及答案(1)——Android Framework篇_第18张图片
这里的item即为LaunchActivityItem
9.调用ActivityThread的handleLaunchActivity
在这里插入图片描述

Android高级面试问题及答案(1)——Android Framework篇_第19张图片
10.performLaunchActivity中使用classloader加载activity,同时如果application还没创建,同样使用classloader创建,instrumentation.callApplicationOnCreate
11.然后调用 mInstrumentation.callActivityOnCreate,这样activity的onCreate就调用了
12.之前android源码中通过发送handler message方式加载activity已经被删除,改为了excution方式
13.TransactionExecutor的execute中executeCallbacks后又执行executeLifecycleState
Android高级面试问题及答案(1)——Android Framework篇_第20张图片
14.会调用到ResumeActivityItem的execute,对activity进行resume
Android高级面试问题及答案(1)——Android Framework篇_第21张图片

问题5:service的启动流程

service的启动是通过context的startService方法来实现的,分为Contextimpl到AMS和ActivityThread启动service 2个主要流程

1.Contextimpl和AMS通信

Android高级面试问题及答案(1)——Android Framework篇_第22张图片
ContextWrapper中的mBase就是ContextImpl,activity中赋值是在如下代码中:
Android高级面试问题及答案(1)——Android Framework篇_第23张图片
Android高级面试问题及答案(1)——Android Framework篇_第24张图片
contextImpl中其实就是获取ams的binder代理
Android高级面试问题及答案(1)——Android Framework篇_第25张图片

2.ActivityThread启动service

Android高级面试问题及答案(1)——Android Framework篇_第26张图片
如果进程存在,AMS中通过方法层层调用会在realStartServiceLocked方法中,调用ActivityThread的scheduleCreateService方法中,进程不存在则先请求zygote创建进程
Android高级面试问题及答案(1)——Android Framework篇_第27张图片
其中就是通过Handler来发送消息来实现逻辑
Android高级面试问题及答案(1)——Android Framework篇_第28张图片
收到消息后,通过classloader创建service,创建contextImpl绑定,如果这时候application还没创建,还会创建application,调用service的attach绑定 contextimpl,然后手动调用其oncreate 方法
Android高级面试问题及答案(1)——Android Framework篇_第29张图片
Android高级面试问题及答案(1)——Android Framework篇_第30张图片
3.AMS调用ActivityThread使得service的onStartCommond被调用
还是AMS的realStartServiceLocked方法中,创建完service后会调用sendServiceArgsLocked方法
Android高级面试问题及答案(1)——Android Framework篇_第31张图片
其中回到了ActivityThread的scheduleServiceArgs方法
Android高级面试问题及答案(1)——Android Framework篇_第32张图片
同样是Handler发送消息
Android高级面试问题及答案(1)——Android Framework篇_第33张图片
最终调用service的onStartCommand
Android高级面试问题及答案(1)——Android Framework篇_第34张图片

问题6:service的绑定流程t

1.contextImpl到AMS

Android高级面试问题及答案(1)——Android Framework篇_第35张图片
通过LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,将ServiceConnection封装为IServiceConnection类型的对象sd,从IServiceConnection的名字我们就能得知它实现了Binder机制,使得Service的绑定就支持跨进程。
Android高级面试问题及答案(1)——Android Framework篇_第36张图片
调用AMS的bindIsolatedService方法,里面做了如下逻辑:
1.调用了 ServiceRecord 的 retrieveAppBindingLocked 方法 来获得 AppBindRecord , retrieveAppBindingLocked 方法内部创建 IntentBindRecord ,并对 IntentBindRecord 的成员变量进行赋值

2.如果flags为Context.BIND_AUTO_CREATE,如果service还没有创建,会先走启动service的流程
Android高级面试问题及答案(1)——Android Framework篇_第37张图片
3.调用connected进行链接
Android高级面试问题及答案(1)——Android Framework篇_第38张图片
其中 c.conn 指的是 IServiceConnection ,它的具体实 现为 ServiceDispatcher.InnerConnection ,其中 ServiceDispatcher 是 LoadedApk 的内部类, InnerConnection 的 connected 方法 内部会调用 H 的 post 方法 向主线程发送消息,并且解决 当前应用程序进程与 Service 跨进程通信的问题

AppBindRecord :应用程序进程通过 Intent 绑定 Service 时,会通过 AppBi ndRecord 来维护 Service 与应用程序进程之间的关联。其内部存储了谁绑定的 Service ( ProcessRecord ) 、被绑 定的 Service ( AppBindRecord )、绑定 Service 的 Intent ( IntentBindRecord )和所有绑定通信记录 的信息( ArraySet )。

关注我的公众号,了解更多干货
Android高级面试问题及答案(1)——Android Framework篇_第39张图片

你可能感兴趣的:(Android面试,Android面试题,Android高级,Android面试及答案,Android大厂)