Launch 桌面启动详解

Launch 桌面启动详解

不管是开机还是重启手机,相信我们大家都不陌生吧。大部分的 90 后都经历了从 Android 2.* 的统一开机动画,到现在 Android 10 的各种定制开机动画。

为什么 Android 系统启动时需要播放一段开机动画呢,而且播放完成后有的性能比较差的机器或者定制度比较高的 Room 都需要在最后一帧动画定格一段时间,是因为 Android 系统启动时首先需要从 Linux 系统进程 fork 一个新的进程作为 Android 系统的运行环境。

在这个 Android 进程中需要启动大量的系统服务为上层应用提供相应的接口,以达到安全隔离的作用。其中最为主要的就是 SystemServer ,他是一切服务启动的入口。

public final class SystemServer {
    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run() {
        ......
        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
        ......
        // Loop forever.
        Looper.loop();
        ......
   }
}

从 main 函数的注释可以很清楚的看到,这个方法的进入点是 zygote 进程,有关 zygote 进程的启动,我们这里简单梳理一条调用链,大概了解一下。

app_main.cpp

这个 app_main 就相当于程序的主入口,这里找到 ZygoteInit 这个类的 main 方法,然后调用。

class AppRuntime : public AndroidRuntime
{
    //这个是父类 AndroidRuntime 的方法,放倒这里为了方便查看
    void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
    {
        ......
        //通过 className 找到相应的 class
        char* slashClassName = toSlashClassName(className != NULL ? className : "");
        jclass startClass = env->FindClass(slashClassName);
        ......
        // 找到 class 的 main 方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                "([Ljava/lang/String;)V");
        ......
        // 调用 static 的 main 方法
        env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
}
int main(int argc, char* const argv[])
{
    ......
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ......
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    ......
}

到这里后就开始启动当前应用进程啦。ZygoteInit 会做一些进程的相关初始化工作。完成后调用 Zygote 的 forkSystemServer 启动 SystemServer。

public class ZygoteInit {
    public static void main(String argv[]) {
        ......
        if (startSystemServer) {
            //这里 从 Zygote 进程 fork 出 system server进程
            Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

            // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
            // child (system_server) process.
            if (r != null) {
                //标注①
                r.run();
                return;
            }
        }
        ......
    }
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ......
        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        ......
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }
        ......
    }
    private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
        ......
        // 找到 SystemServer 的 class
        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        ......
        ClassLoader cl = null;
        if (systemServerClasspath != null) {
            cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

            Thread.currentThread().setContextClassLoader(cl);
        }

        /*
         * Pass the remaining arguments to SystemServer.
         * 将其余参数传递给SystemServer
         */
        return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }
    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        ......
        //运行时相关的初始化
        RuntimeInit.commonInit();
        //初始化 ZygoteInit
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
}
public class RuntimeInit {
    protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        ......
        //根据上面找的 SystemServer 的 class 找到相应的 main 函数,将 参数传递并调用
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
    //通过反射找到 main 函数
    protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl = Class.forName(className, true, classLoader);
        ......
        Method m = cl.getMethod("main", new Class[] { String[].class });
        ......
        // 这里返回的 runnable 对象会在上面的 标注① 出进行调用
        return new MethodAndArgsCaller(m, argv);
    }
    //封装了 main 方法的签名 和 传递的参数。
    //这里返回的是一个 Runnable 对象。
    static class MethodAndArgsCaller implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            ......
            mMethod.invoke(null, new Object[] { mArgs });
            ......
        }
    }
}

这些就是有关 SystemServer 的调用链,上面这些代码执行完成后就调用到了 开始说的 SystemServer 的 main 函数。

回到 SystemServer 的 main 函数,发现里面直接new 了一个自己作为对象调用了他的 run 方法,run 方法中分别调用了三个方法,根据名字可以很直观的想到这三个方法对应的功能,启动引导服务启动内核服务启动其他服务

public final class SystemServer {
    private void startOtherServices() {
        mActivityManagerService.systemReady(() -> {
            ......
        }
    }
}
public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
        ......
        startHomeActivityLocked(currentUserId, "systemReady");
        ......
    }
    boolean startHomeActivityLocked(int userId, String reason) {
        ......
        Intent intent = getHomeIntent();
        ......
        intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
        ......
        mActivityStartController.startHomeActivity(intent, aInfo, myReason);
        ......
    }
    Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            //public static final String CATEGORY_HOME = "android.intent.category.HOME";
            //标注②
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        return intent;
    }
}

可以看到当 其他服务启动完成时,会调用 AMS 的 systemReady 函数。在这里会调用 startHomeActivityLocked 启动 Home 界面,就是我们所说的 Launch 界面了。

通过 getHomeIntent 方法获取启动 Launch 界面的 Intent。后续流程就和 Activity 的启动流程相当了,具体流程可以查看 Activity 启动流程详解

这个 Launch 应用是一个系统应用,这里附上 Launch.apk 的源码,当然,不同的系统会定制不同的 Launch 应用。

标注② 中 添加的 Intent.CATEGORY_HOME 就是 Launch 应用的主界面中声明的 category。

<activity
    android:name="com.android.launcher3.Launcher"
    ......
    android:enabled="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.HOME" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.MONKEY"/>
        <category android:name="android.intent.category.LAUNCHER_APP" />
    </intent-filter>
    ......
</activity>

至此,Launch 界面的启动就分析完成了。最后附上一个 SystemServer 的启动流程图。

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值