前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android高级面试问题及答案(1)——Android Framework篇

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

作者头像
老马的编程之旅
发布2022-06-22 14:32:44
2.7K0
发布2022-06-22 14:32:44
举报
文章被收录于专栏:深入理解Android深入理解Android

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

主要分为几个部分:

init进程启动

1.按下电源,启动引导程序 BootLoader,启动linux内核,init进程启动,所以init是android系统的第一个进程,进程号为1。

2.init进程主要做以下几件事:

1)创建和挂载启动所需要的文件目录

2)初始化和启动属性服务,属性值的更改仅能在init进程中进行,通过socket来响应其它进程提交的申请。

主要方法逻辑在init.cpp

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

3.处理子进程( Zygote 进程)异常退出,也是通过socket

主要目的:回收僵尸进程

在Linux内核中,如父进程不等待子进程的结束直接退出,会导致子进程在结束后变成僵尸进程,占用系统资源

代码语言:javascript
复制
......
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为例子:

代码语言:javascript
复制
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的方法

代码语言:javascript
复制
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 框架层

代码语言:javascript
复制
//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 请求创建新的应用程序进程。

代码语言:javascript
复制
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函数

代码语言:javascript
复制
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是引导服务中启动

代码语言:javascript
复制
			createSystemContext();//3
代码语言:javascript
复制
 			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

3.Launcher中应用图标显示

  1. 创建工作区 Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标,每一个工作区都是来描述一个抽象桌面的,它由n个屏幕组成,每个屏幕又分n个单元格,每个单元格用来显示一个应用程序的快捷图标。 2)加载系统已经安装的应用程序信息 主要是通过Laucher进程查询系统的launcherapps服务来查询安装信息

3) Launcher.java中mAppsView是AllAppsContainerView,AllAppsContainerView的onFinishlnflate中获取recyclerview,将返回的AppInfo绑定到recyclerview,桌面图标就显示出来了

代码语言:javascript
复制
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进程请求

将应用进程的启动参数 argsForZygote 写入ZygoteState 中,ZygoteState connect Zygote的socket时,就会读取这个参数

2)Zygote 接收请求并创建应用程序进程

主要是以下几个流程:

(1)看 ZygoteServer的 runSelectLoop 方法不停轮询,等待创建新进程的socket请求

(2)请求过来调用connection.processOneCommand()传入ZygoteServer自身,在其中Zygote根据传来的argsForZygote参数,创建App进程

(3).handleChildProc方法中ZygoteInit.zygoteInit,调用RuntimeInit.applicationInit()

(4)最终反射创建要启动App进程的ActivityThread类,并调用其main方法,App进程创建完毕

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

应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出这个 apk 的信息写入到 packages.xml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。

1.点击图标,调用Launcher.startActivitySafely(),然后调用到Activity的startActivity

2.Instrumentation的execStartActivity,调用AMS的startActivity,切换到systemServer进程

3.然后到ActivityStarter的startActivityMayWait中,这里要关注ProcessRecord用于描述应用程序,ActivityRecord用于描述Activity的信息

4.检查activity的进程启动起来没,如果没有AMS请求zygote fork出进程

ActivityStackSupervisor.java

5.结合activity的启动模式,查看activity的任务栈是否创建,如果没有创建则创建栈,任务栈是理想模型,并不真实存在

6.ActivityStackSupervisor的realStartActivityLocked方法,会调用要启动App的scheduleTransaction方法,传入的参数是ClientTransaction

7.Handler发送EXECUTE_TRANSACTION消息

8.调用TransactionExecutor的execute,然后执行executeCallbacks方法

这里的item即为LaunchActivityItem

9.调用ActivityThread的handleLaunchActivity

10.performLaunchActivity中使用classloader加载activity,同时如果application还没创建,同样使用classloader创建,instrumentation.callApplicationOnCreate

11.然后调用 mInstrumentation.callActivityOnCreate,这样activity的onCreate就调用了

12.之前android源码中通过发送handler message方式加载activity已经被删除,改为了excution方式

13.TransactionExecutor的execute中executeCallbacks后又执行executeLifecycleState

14.会调用到ResumeActivityItem的execute,对activity进行resume

问题5:service的启动流程

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

1.Contextimpl和AMS通信

ContextWrapper中的mBase就是ContextImpl,activity中赋值是在如下代码中:

contextImpl中其实就是获取ams的binder代理

2.ActivityThread启动service

如果进程存在,AMS中通过方法层层调用会在realStartServiceLocked方法中,调用ActivityThread的scheduleCreateService方法中,进程不存在则先请求zygote创建进程

其中就是通过Handler来发送消息来实现逻辑

收到消息后,通过classloader创建service,创建contextImpl绑定,如果这时候application还没创建,还会创建application,调用service的attach绑定 contextimpl,然后手动调用其oncreate 方法

3.AMS调用ActivityThread使得service的onStartCommond被调用

还是AMS的realStartServiceLocked方法中,创建完service后会调用sendServiceArgsLocked方法

其中回到了ActivityThread的scheduleServiceArgs方法

同样是Handler发送消息

最终调用service的onStartCommand

问题6:service的绑定流程t

1.contextImpl到AMS

通过LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,将ServiceConnection封装为IServiceConnection类型的对象sd,从IServiceConnection的名字我们就能得知它实现了Binder机制,使得Service的绑定就支持跨进程。

调用AMS的bindIsolatedService方法,里面做了如下逻辑:

1.调用了 ServiceRecord 的 retrieveAppBindingLocked 方法 来获得 AppBindRecord , retrieveAppBindingLocked 方法内部创建 IntentBindRecord ,并对 IntentBindRecord 的成员变量进行赋值

2.如果flags为Context.BIND_AUTO_CREATE,如果service还没有创建,会先走启动service的流程

3.调用connected进行链接

其中 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 )。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题1.Android系统的启动过程?
    • init进程启动
      • Zygote进程启动
        • SystemServer进程创建
        • 问题2.Android的Laucher是如何创建的?
        • 问题3 App的进程是如何启动起来的?
        • 问题4:点击桌面图标,是如何启动App的Activity的
        • 问题5:service的启动流程
          • 1.Contextimpl和AMS通信
            • 2.ActivityThread启动service
            • 问题6:service的绑定流程t
              • 1.contextImpl到AMS
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档