美文网首页
Android从开机到点击Icon(桌面图标)中间发生了什么?

Android从开机到点击Icon(桌面图标)中间发生了什么?

作者: Hengtao24 | 来源:发表于2019-08-22 23:10 被阅读0次

    系列文章

    前言

    上文Android Activity生命周期,启动模式,启动过程详解我们讲解了Activity的生命周期,以及Activity启动过程的详细步骤,Activity承载着App对用户的内容展示,当我们在手机桌面上点开一个图标便打开了一个App,App上显示的界面对应背后的Activity,那么为什么点击图标便能打开App呢,其实桌面应用程序(Launcher)我们也可以理解为一个App,此Activity上承载着各种App图标,点击图标便有一个响应事件,这个响应事件就是打开图标对应的App。那么Launcher程序又是如何启动的呢?自然是和手机开机有关,因为我们知道手机开机后便是默认桌面,所以本文我们将从手机开机说起,梳理一下从手机开机,到启动Launcher程序,到点击Icon打开APP这个过程,下面分别介绍以上三个过程。

    本文源码基于Android-25版本

    开机过程分析

    在看Android系统启动流程前,我们先了解下计算机PC启动过程,大概分为以为四步:

    • BIOS:主要做硬件自检,转移控制权等工作;
    • 主引导记录:BIOS把控制权转交给排在第一位的储存设备(主引导记录),共512字节;
    • 硬盘启动:计算机的控制权由硬盘的某个分区控制;
    • 操作系统:计算机的控制权转交给操作系统,内核首先被载入内存,以Linux为例,其第一个运行的程序是/sbin/init。它根据配置文件产生init进程,init是Linux启动后的第一个进程,pid进程编号为1,其他进程都是它的后代。然后,init线程加载系统的各个模块,比如窗口程序和网络程序,直至执行/bin/login程序,跳出登录界面,等待用户输入用户名和密码。

    以上摘自 计算机是如何启动的?[阮一峰]

    因为Android系统是基于Linux内核的,所以系统的开机过程肯定涉及到Linux内核的启动。但是Android系统属于嵌入式系统,没有计算机那样的BIOS引导程序,取而代之的是系统引导Bootloader,为启动系统内核做好准备。Android中也没有硬盘,取而代之的是ROM,类似硬盘存放操作系统和应用程序等。整体开机流程如下图所示:

    Android开机流程

    第一步:上电复位

    开机时,通电产生一个CPU复位信号,CPU开始执行指令,第一条指令是设定好的(固化在ROM上),将引导程序(Bootloader)加载到RAM中;

    第二步:Bootloader

    Bootloader启动,引导进入Linux内核;引导程序是运行的第一个程序,不同的主板和芯片具有不同引导程序,不同的手机厂商使用不同的程序,这部分不属于Android操作系统,因此可能是厂商加锁的地方;

    第三步:Linux内核

    Linux内核启动后主要做一些初始化工作,比如初始化软硬件环境,加载驱动程序,挂载根文件系统,内核加载的最后阶段启动第一个进程init进程;

    第四步:init进程

    init进程(/system/core/init/*)是系统第一个进程,进程号为1,该进程会首先加载一个init.rc配置文件,init.rc文件是Android系统的重要配置文件,位于(/system/core/rootdir/init.rc),其主要功能是定义了系统启动时需要执行的一系列动作,设置环境变量,生成系统运行所需要的文件或目录,执行特定Services等。

    Android针对init.rc有特定的格式和规则,它由Android Init Language语言编写而成,Android Init Language主要包含四种声明:Actions(动作),Commands(命令),Services(服务),Options(选项)。

    通过init.rc脚本主要启动了以下服务:

    Action/Service 描述
    on early-init 设置init进程以及它创建的子进程的优先级,设置init进程的安全环境
    on init 设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点
    on fs 挂载mtd分区
    on post-fs 改变系统目录的访问权限
    on post-fs-data 改变/data目录以及它的子目录的访问权限
    on boot 基本网络的初始化,内存管理等等
    service servicemanager 启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference等等…
    service zygote 启动zygote作为应用进程

    本表来自Android启动过程深入解析

    init.rc最重要的的任务是启动一个Zygote(孵化器)进程,此进程负责启动Android应用进程的启动工作。init.rc通过include引入init.zygote.rc创建Zygote进程。

    init.rc的具体语法可以参考深入分析AIL语言及init.rc文件

    第五步:Zygote进程

    Zygote进程孵化了所有Android应用进程,是Android Framework的基础。在Java中,不同的虚拟机实例会为不同的应用分配不同的内存。Android应用程序是运行在Dalvik虚拟机里面的,并且每一个应用程序对应有一个单独的Dalvik虚拟机实例。但是Android应用程序中的Dalvik虚拟机实例实际上是从Zygote进程的地址空间拷贝而来的,这样就可以加快Android应用程序的启动速度,Zygote让Dalvik虚拟机共享代码,低内存占用,最小启动时间成为可能。

    Zygote其实是一个虚拟机进程,它会完成虚拟机的初始化、库的加载、预制类库、核心类库的初始化等,当系统需要一个新的虚拟机时,它会迅速复制自己,提供给系统。每当我们打开一个新的APP时都会fork之前的Zygote进程。下面介绍下Zygote启动过程:

    App_main.main()

    此函数位于(frameworks/base/cmds/app_process/App_main.cpp)中,主要添加了Android运行环境,即创建一个AppRuntime变量runtime,而AppRuntime继承自AndroidRuntime,在App_main.main()方法中执行了runtime.start()方法,也就是执行了AndroidRuntime类的start方法,由于在init.rc文件中设置了启动app_process的参数为:--zygote--start-system-server,因此实际上在main函数里最终会执行下面语句:

    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    

    AndroidRuntime.start()

    此函数位于(frameworks/base/core/jni/AndroidRuntime.cpp)中,主要做了以下三件事情:

    • startVm():创建虚拟机,主要是关于虚拟机参数的设置;
    • startReg(): 注册JNI方法;
    • env->GetStaticMethodID(): 通过JNI调用Java函数,进入Java代码中,实际上最终调用了com.android.internal.os.ZygoteInit的main函数。

    ZygoteInit.main()

    此函数位于(frameworks/base/core/java/com/android/internal/os/ZygoteInit.java)中:

    public static void main(String argv[]) {
        try {
            
            ......
            
            String socketName = "zygote";
    
            ......
    
            registerZygoteSocket(socketName);
            preload(); 
            
            ......
    
            if (startSystemServer) {
                startSystemServer(abiList, socketName);
            } 
            runSelectLoop(abiList); 
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            ......
            
        } catch (RuntimeException ex) {
            ......
            
        }
    }
    

    主要做了以下几件事情:

    • registerZygoteSocket():创建一个名为Zygote的socket接口,用来和ActivityManagerService通讯
    • preload():预加载通用类等资源,如res(drawable,xml信息,strings)等
    • startSystemServer(): 启动SystemServer等服务,在此函数内部Zygote进程通过Zygote.forkSystemServer函数来创建一个新的进程来启动SystemServer组件,如下所示:
    private static boolean startSystemServer(){
        
        ....
        // SystemServer是由Zygote通过Zygote.forkSystemServer函数fork出来的
        pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, debugFlags, null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
    
        ....
        
        // 子进程返回0,即SystemServer
        if (pid == 0) {
            ....
            handleSystemServerProcess(parsedArgs);
        }
    }
    
    private static void handleSystemServerProcess(
                ZygoteConnection.Arguments parsedArgs)
                throws ZygoteInit.MethodAndArgsCaller {
        // 关闭这里继承来的socket,因为这里的子进程并不会使用到socket      
        closeServerSocket();
        
        // 继续启动SystemServer的操作
        RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
        /* should never reach here */
    }
    
    public static final void zygoteInit(String[] argv)  
                throws ZygoteInit.MethodAndArgsCaller { 
                
        ....
        // 初始化Binder进程间通信机制
        zygoteInitNative();  
    
        ....
    }  
    
    • runSelectLoopMode(): 轮询监听socket,不断处理来自客户端的AMS请求,然后交给runOnce()处理

    至此,Zygote进程就启动完成了,总结如下:

    • init进程创建Zygote进程,而Zygote负责整个后续Android 应用程序的创建
    • Zygote进程启动时会创建SystemServer进程,SystemServer进程负责启动系统的关键服务,如ActivityManagerService,PowerManagerService,PackageManagerService等
    • 当我们准备启动一个APP时,AMS通过Socket和Zygote进程间通信,通知Zygote fork子进程,加载需要的类。

    整体过程如下图所示:

    Zygote启动过程

    SystemServer启动过程

    上述启动Zygote进程的过程中,我们提到了启动SystemServer这个Android系统核心进程,为了更清楚理解Android系统工作,这里我们再将启动SystemServer进程的过程单独列为一小节说明。

    SystemServer由Zygote fork而成,进程名为system_server,承载着framework服务。

    具体的SystemServer启动过程较为复杂,通过一系列方法最终转移到SystemServer类的main()方法中,如下图所示:


    SystemServer启动过程

    图片来自 作者:Gityuan博客 来源:Android系统启动-SystemServer上篇
    链接:http://gityuan.com/2016/02/14/android-system-server/

    SystemServer.main()方法主要的流程如下:

    SystemServer.main()           // 初始化SystemServer对象,再调用run()方法
    SystemServer.run()            // 调用以下方法
        createSystemContext()     // 创建system_server进程的上下文信息
        startBootstrapServices(); // 创建AMS,PMS,LightService,DisplayManagerService等服务
        startCoreServices();      // 启动BatteryService,UsageStatsService,WebViewUpdateService服务
        startOtherServices();     // 显示启动界面,调用AMS.systemReady()方法
        Looper.loop();            // 开启消息循环
    

    在上面的startOtherServices()方法中有一段代码如下:

    mActivityManagerService.systemReady(new Runnable() {
        public void run() {
          ...
        }
    });
    
    public final class ActivityManagerService{
    
        public void systemReady(final Runnable goingCallback) {
            
            ....
            
            startHomeActivityLocked(mCurrentUserId, "systemReady"); //启动桌面
            mStackSupervisor.resumeTopActivitiesLocked(); //恢复栈顶的Activity
        }
    }
    

    AMS的systemReady()方法中启动了WebView,SystemUI,开启WatchDog,启动桌面Launcher 程序。
    启动Launcher的过程如下:首先通过Zygote进程fork一个子进程作为APP进程,然后创建Application,再启动Activity,最后显示出实际画面。
    完整的启动过程如下:


    Android完整开机过程

    本图片摘自 作者: Jeanboydev 来源:CSDN
    链接 https://blog.csdn.net/freekiteyu/article/details/79318031

    Launcher

    从上面分析我们知道,AMS在完成服务注册等初始化工作后,在main()方法中调用systemReady()方法,进而调用startHomeActivityLocked()来启动Launcher。

    boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            return false;
        }
        // 获取启动Launcher的intent信息
        Intent intent = getHomeIntent();
        // 通过PackageManagerService获得Launcher的Activity描述信息Info
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }
        return true;
    }
    

    启动Launcher的Intent对象中添加了Intent.CATEGORY_HOME常量,代表将要启动Home界面。
    获得intent和ActivityInfo后,后续方法调用顺序为:

    ActivityStarter.startHomeActivityLocked()
    ActivityStackSupervisor.moveHomeStackTaskToTop() // 把Launcher的堆栈移到顶部
    ActivityStarter.startActivityLocked()
    ......
    

    进入ActivityStarter.startActivityLocked()方法后,后续过程就和启动一个普通的Activity没什么区别,启动一个普通Activity的过程可以参考我的上一篇文章Android Activity生命周期,启动模式,启动过程详解
    第一次启动Launcher时,执行到ActivityStackSupervisor的startSpecificActivityLocked()方法时,会判断Launcher Activity所在进程是否已经存在,如果不存在则会创建一个进程容纳Activity,创建进程的流程就是通过AMS向Zygote发起请求,Zygote收到请求后fork一个子进程,然后再继续启动Launcher。创建子进程的过程,我们会在下文中点击Icon启动一个APP的过程中进行分析。

    总而言之,Launcher的启动过程就是类似一个启动Activity的过程。但是,我们知道Launcher上放着各种应用程序图标,有着不同的状态,因此其Activity实现具体原理还可以进一步探究。可以参考Android Launcher加载流程源码分析Android M Launcher3主流程源码浅析Android系统启动流程(四)Launcher启动过程与系统启动流程

    应用安装的时候,通过PackageManagerService解析apk的AndroidManifest.xml文件,提取出这个apk的信息写入packages.xml中,包括权限、包名、icon、apk安装位置、版本、userID等信息,Launcher为已安装的程序在桌面上生成图标,点击图标便可启动应用,下面分析启动应用的过程。

    本段来自 Jeanboydev CSDN博客 一篇文章看明白 Android 从点击应用图标到界面显示的过程

    点击Icon启动APP

    其实点击Icon启动APP的过程就是启动APP主Activity的过程,即启动MainActivity的过程,从而把APP启动起来,但是当我们新启动一个APP过程时,需要判断此APP所在进程是否已经存在,如果不存在则需要fork一个子进程。下面详细介绍这个具体过程。

    Launcher.startActivitySafely

    点击图标时,桌面程序Launcher.java做出响应,调用Launcher.startActivitySafely来启动一个Activity

    public class Launcher extends Activity
            implements LauncherExterns, View.OnClickListener, OnLongClickListener,
                       LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
                       AccessibilityManager.AccessibilityStateChangeListener {
     
        ......
    
        public void onClick(View v) {
            Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
                onClickAppShortcut(v);
            } 
            
            ......
        }
        
        protected void onClickAppShortcut(final View v) {
            
            ......
            
            startAppShortcutOrInfoActivity(v);
        }
        
        private void startAppShortcutOrInfoActivity(View v) {
            ItemInfo item = (ItemInfo) v.getTag();
            Intent intent = item.getIntent();
            
            ......
            
            boolean success = startActivitySafely(v, intent, item);
    
            ......
        }
        
        public boolean startActivitySafely(Intent intent, Object tag) {
            ......
            
            // 表示在新的Task中启动此Activity
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ......
            try {
            
                ......
                
                startActivity(intent);
            } catch (ActivityNotFoundException e) {
                ......
            } catch (SecurityException e) {
                ......
            }
        }
     
        ......
     
    }
    
    

    Activity.startActivity

    Launcher继承自Activity,因此上段代码中startActivity(intent)便调用了Activity类的该方法:

    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }
    
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);
        }
    }
    

    Activity的StartActivity()方法最终调用了startActivityForResult()方法,这和我之前一篇文章Android Activity生命周期,启动模式,启动过程详解相同,后续过程基本没有区别。和前文类似,当执行到ActivityStackSupervisor的startSpecificActivityLocked()方法时,会判断APP所在进程是否已经存在,如果不存在则会fork一个进程。下面介绍fork新进程的过程:

    fork新进程

    Android创建进程的流程图大概如下:


    Android创建进程

    图片来自 作者:Gityuan博客 来源:理解Android进程创建流程
    链接:http://gityuan.com/2016/03/26/app-process-create/

    ActivityManagerService.startProcessLocked()

    ActivityStackSupervisor的startSpecificActivityLocked()的方法中有下面一段代码

    ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true);
    

    第一次启动APP时,很明显上面获得的变量app=null,在配置文件AndroidManifest.xml中我们如果没有指定process属性,系统会默认使用package的名称当做process名。而且每一个程序都有自己的uid,uid+process的组合就可以为每一个应用程序创建一个ProcessRecord,每次新建进程前都会判断此ProcessRecord是否存在,如果已经存在则不会新建进程。
    如果不存在,则新建进程:

    mService.startProcessLocked(r.processName, r.info.applicationInfotrue, 0,
            "activity", r.intent.getComponent(), false, false, true);
    

    因为startProcessLocked有多个重载形式,上述方法最终调用的方法为:

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        
        ......
            
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        ......
        
    }
    

    最终转到Process的start()方法中。

    Process.start()

    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            ......
        }
    }
    

    又继续调用Process.startViaZygote()方法:

    private static ProcessStartResult startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            
            ......
            
            // openZygoteSocketIfNeeded(abi)方法是根据当前的abi来选择与zygote还是zygote64来进行通信
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }
    

    继续调用zygoteSendArgsAndGetResult()方法:

    private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            
            ......
    
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
    
            writer.write(Integer.toString(args.size()));
            writer.newLine();
    
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }
    
            writer.flush();
    
            ProcessStartResult result = new ProcessStartResult();
            
            // 等待Zygote的socket返回新进程的pid
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();
    
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }
    

    通过socket向Zygote发送一系列参数,然后进入阻塞等待状态,直到远端的socket服务端发送回来新创建的进程pid才返回。Zygote收到请求后,开始工作,我们又回到了ZygoteInit.main()方法中。

    ZygoteInit.main()

    ZygoteInit.main()方法中主要停留在runSelectLoop函数中,等待AMS的请求,收到请求时会调用ZygoteConnection的runOnce函数来处理请求,后序函数调用逻辑为:

    ZygoteConnection.runOnce()
        Zygote.forkAndSpecialize()              // fork当前进程来创建一个子进程
        ZygoteConnection.handleChildProc()      // 启动上面fork的子进程,并切换到子进程中执行后续代码 
            RuntimeInit.zygoteInit()            // 创建Binder线程池,一些初始化工作
                RuntimeInit.invokeStaticMain()  // 利用反射ActivityThread.main()方法
    ActivityThread.main()                       // 创建消息循环,进入消息循环状态
    

    ActivityThread.main()

    public static void main(String[] args) {
    
        ......
        // 创建消息循环
        Looper.prepareMainLooper();
    
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
    
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
    
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
    
        // 进入消息循环
        Looper.loop();
    
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    

    此时只创建了应用程序的 ActivityThread 和 ApplicationThread,和开启了 Handler 消息循环机制,其他的都还未创建, ActivityThread.attach(false) 又会最终到 ActivityMangerService 的 attachApplication,这个方法其实是将本地的 ApplicationThread 传递到 ActivityMangerService。然后 ActivityMangerService 就可以通过 ApplicationThread 的代理 ApplicationThreadProxy 来调用应用程序 ApplicationThread.bindApplication,通知应用程序的 ApplicationThread 已和 ActivityMangerService 绑定,可以不借助其他进程帮助直接通信了。此时 Launcher 的任务也算是完成了。

    本段来源
    作者:Jeanboydev
    来源:CSDN
    原文:https://blog.csdn.net/freekiteyu/article/details/79318031

    下面看下ActivityMangerService的attachApplication方法:

    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            ......
            attachApplicationLocked(thread, callingPid);
            ......
        }
    }
    
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    
        ......
    
        // 检查顶层Activity是否等待被运行
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
    
        // 寻找所有需要在该进程中运行的服务
        if (!badApp) {
            try {
                didSomething |= mServices.attachApplicationLocked(app, processName);
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
                badApp = true;
            }
        }
    
        // 检查是否在这个进程中有下一个广播接收者
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            try {
                didSomething |= sendPendingBroadcastsLocked(app);
            } catch (Exception e) {
                // If the app died trying to launch the receiver we declare it 'bad'
                Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
                badApp = true;
            }
        }
        
        ......
        
        return true;
    }
    

    当发现有Activity需要被启动时,调用ActivityStackSupervisor.attachApplicationLocked()方法:

    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        ......
        
        realStartActivityLocked(hr, app, true, true);
        
        ......
    }
    

    后续具体的启动步骤又回到了启动一个普通Activity的过程中,同样可以参考上篇文章Android Activity生命周期,启动模式,启动过程详解
    最后,再引用一张图片结束本文:

    Launcher启动Activity流程

    图片来自 Jeanboydev 来源:CSDN
    链接:https://blog.csdn.net/freekiteyu/article/details/79318031

    至此,我们基本把Android从开机到点击Icon的过程理清楚了,但是中间每一部分都有很多细节值得深入,因此本文只给了一个大概流程,具体的实现细节可以分模块去查找探究,本文结束!

    参考信息

    相关文章

      网友评论

          本文标题:Android从开机到点击Icon(桌面图标)中间发生了什么?

          本文链接:https://www.haomeiwen.com/subject/pxjasctx.html