资讯专栏INFORMATION COLUMN

App启动流程

geekidentity / 808人阅读

摘要:孵化进程相当于是系统的根进程,后面所有的进程都是通过这个进程出来的虽然进程相当于系统的根进程,但是事实上它也是由系统的进程启动的。

目录介绍

1.什么是Zygote进程

1.1 简单介绍

1.2 各个进程的先后顺序

1.3 进程作用说明

2.Zygote进程的启动流程

2.1 源码位置

2.2 ZygoteInit类的main方法

2.3 registerZygoteSocket(socketName)分析

2.4 preLoad()方法分析

2.5 startSystemServer()启动进程

3.SystemServer进程启动流程

3.1 SystemServer进程简介

3.2 SystemServer的main方法

3.3 查看run方法

3.4 run方法中createSystemContext()解析

3.5 mSystemServiceManager的创建

4.启动服务

4.1 启动哪些服务

4.2 启动服务流程源码分析

4.3 启动部分服务

好消息

博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!

链接地址:https://github.com/yangchong2...

如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

1.什么是Zygote进程 1.1 简单介绍

Zygote进程是所有的android进程的父进程,包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。Zygote(孵化)进程相当于是android系统的根进程,后面所有的进程都是通过这个进程fork出来的

虽然Zygote进程相当于Android系统的根进程,但是事实上它也是由Linux系统的init进程启动的。

1.2 各个进程的先后顺序

init进程 --> Zygote进程 --> SystemServer进程 -->各种应用进程

1.3 进程作用说明

init进程:linux的根进程,android系统是基于linux系统的,因此可以算作是整个android操作系统的第一个进程;

Zygote进程:android系统的根进程,主要作用:可以作用Zygote进程fork出SystemServer进程和各种应用进程;

SystemService进程:主要是在这个进程中启动系统的各项服务,比如ActivityManagerService,PackageManagerService,WindowManagerService服务等等;

各种应用进程:启动自己编写的客户端应用时,一般都是重新启动一个应用进程,有自己的虚拟机与运行环境;

2.Zygote进程的启动流程 2.1 源码位置

位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

Zygote进程mian方法主要执行逻辑:

初始化DDMS;

注册Zygote进程的socket通讯;

初始化Zygote中的各种类,资源文件,OpenGL,类库,Text资源等等;

初始化完成之后fork出SystemServer进程;

fork出SystemServer进程之后,关闭socket连接;

2.2 ZygoteInit类的main方法

init进程在启动Zygote进程时一般都会调用ZygoteInit类的main方法,因此这里看一下该方法的具体实现(基于android23源码);

调用enableDdms(),设置DDMS可用,可以发现DDMS启动的时机还是比较早的,在整个Zygote进程刚刚开始要启动额时候就设置可用。

之后初始化各种参数

通过调用registerZygoteSocket方法,注册为Zygote进程注册Socket

然后调用preload方法实现预加载各种资源

然后通过调用startSystemServer开启SystemServer服务,这个是重点

public static void main(String argv[]) {
    try {
        //设置ddms可以用
        RuntimeInit.enableDdms();
        SamplingProfilerIntegration.start();
        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }

        registerZygoteSocket(socketName);
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
            SystemClock.uptimeMillis());
        preload();
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
            SystemClock.uptimeMillis());
        SamplingProfilerIntegration.writeZygoteSnapshot();

        gcAndFinalize();
        Trace.setTracingEnabled(false);

        if (startSystemServer) {
            startSystemServer(abiList, socketName);
        }

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

        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

2.3 registerZygoteSocket(socketName)分析

调用registerZygoteSocket(String socketName)为Zygote进程注册socket

private static void registerZygoteSocket(String socketName) {
    if (sServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }

        try {
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            sServerSocket = new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket "" + fileDesc + """, ex);
        }
    }
}

2.4 preLoad()方法分析

源码如下所示

static void preload() {
    Log.d(TAG, "begin preload");
    preloadClasses();
    preloadResources();
    preloadOpenGL();
    preloadSharedLibraries();
    preloadTextResources();
    // Ask the WebViewFactory to do any initialization that must run in the zygote process,
    // for memory sharing purposes.
    WebViewFactory.prepareWebViewInZygote();
    Log.d(TAG, "end preload");
}

大概操作是这样的:

preloadClasses()用于初始化Zygote中需要的class类;

preloadResources()用于初始化系统资源;

preloadOpenGL()用于初始化OpenGL;

preloadSharedLibraries()用于初始化系统libraries;

preloadTextResources()用于初始化文字资源;

prepareWebViewInZygote()用于初始化webview;

2.5 startSystemServer()启动进程

这段逻辑的执行逻辑就是通过Zygote fork出SystemServer进程

private static boolean startSystemServer(String abiList, String socketName)
        throws MethodAndArgsCaller, RuntimeException {
    long capabilities = posixCapabilitiesAsBits(
        OsConstants.CAP_BLOCK_SUSPEND,
        OsConstants.CAP_KILL,
        OsConstants.CAP_NET_ADMIN,
        OsConstants.CAP_NET_BIND_SERVICE,
        OsConstants.CAP_NET_BROADCAST,
        OsConstants.CAP_NET_RAW,
        OsConstants.CAP_SYS_MODULE,
        OsConstants.CAP_SYS_NICE,
        OsConstants.CAP_SYS_RESOURCE,
        OsConstants.CAP_SYS_TIME,
        OsConstants.CAP_SYS_TTY_CONFIG
    );
    /* Hardcoded command line to start the system server */
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

3.SystemServer进程启动流程 3.1 SystemServer进程简介

SystemServer进程主要的作用是在这个进程中启动各种系统服务,比如ActivityManagerService,PackageManagerService,WindowManagerService服务,以及各种系统性的服务其实都是在SystemServer进程中启动的,而当我们的应用需要使用各种系统服务的时候其实也是通过与SystemServer进程通讯获取各种服务对象的句柄的。

3.2 SystemServer的main方法

如下所示,比较简单,只是new出一个SystemServer对象并执行其run方法,查看SystemServer类的定义我们知道其实final类型的,所以我们一般不能重写或者继承。

3.3 查看run方法

代码如下所示

首先判断系统当前时间,若当前时间小于1970年1月1日,则一些初始化操作可能会处所,所以当系统的当前时间小于1970年1月1日的时候,设置系统当前时间为该时间点。

然后是设置系统的语言环境等

接着设置虚拟机运行内存,加载运行库,设置SystemServer的异步消息

private void run() {
    if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
        Slog.w(TAG, "System clock is before 1970; setting to 1970.");
        SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
    }

    if (!SystemProperties.get("persist.sys.language").isEmpty()) {
        final String languageTag = Locale.getDefault().toLanguageTag();

        SystemProperties.set("persist.sys.locale", languageTag);
        SystemProperties.set("persist.sys.language", "");
        SystemProperties.set("persist.sys.country", "");
        SystemProperties.set("persist.sys.localevar", "");
    }

    Slog.i(TAG, "Entered the Android system server!");
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());

    SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

    if (SamplingProfilerIntegration.isEnabled()) {
        SamplingProfilerIntegration.start();
        mProfilerSnapshotTimer = new Timer();
        mProfilerSnapshotTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                SamplingProfilerIntegration.writeSnapshot("system_server", null);
            }
        }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
    }

    // Mmmmmm... more memory!
    VMRuntime.getRuntime().clearGrowthLimit();

    // The system server has to run all of the time, so it needs to be
    // as efficient as possible with its memory usage.
    VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

    // Some devices rely on runtime fingerprint generation, so make sure
    // we"ve defined it before booting further.
    Build.ensureFingerprintProperty();

    // Within the system server, it is an error to access Environment paths without
    // explicitly specifying a user.
    Environment.setUserRequired(true);

    // Ensure binder calls into the system always run at foreground priority.
    BinderInternal.disableBackgroundScheduling(true);

    // Prepare the main looper thread (this thread).
    android.os.Process.setThreadPriority(
            android.os.Process.THREAD_PRIORITY_FOREGROUND);
    android.os.Process.setCanSelfBackground(false);
    Looper.prepareMainLooper();

    // Initialize native services.
    System.loadLibrary("android_servers");

    // Check whether we failed to shut down last time we tried.
    // This call may not return.
    performPendingShutdown();

    // Initialize the system context.
    createSystemContext();

    // Create the system service manager.
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

    // Start services.
    try {
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    }

    // For debug builds, log event loop stalls to dropbox for analysis.
    if (StrictMode.conditionallyEnableDebugLogging()) {
        Slog.i(TAG, "Enabled StrictMode for system server main thread.");
    }

    // Loop forever.
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

然后下面的代码是:

// Initialize the system context.
createSystemContext();

// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

// Start services.
try {
    startBootstrapServices();
    startCoreServices();
    startOtherServices();
} catch (Throwable ex) {
    Slog.e("System", "******************************************");
    Slog.e("System", "************ Failure starting system services", ex);
    throw ex;
}

3.4 run方法中createSystemContext()解析

调用createSystemContext()方法:

可以看到在SystemServer进程中也存在着Context对象,并且是通过ActivityThread.systemMain方法创建context的,这一部分的逻辑以后会通过介绍Activity的启动流程来介绍,这里就不在扩展,只知道在SystemServer进程中也需要创建Context对象。

private void createSystemContext() {
    ActivityThread activityThread = ActivityThread.systemMain();
    mSystemContext = activityThread.getSystemContext();
    mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}

3.5 mSystemServiceManager的创建

看run方法中,通过SystemServiceManager的构造方法创建了一个新的SystemServiceManager对象,我们知道SystemServer进程主要是用来构建系统各种service服务的,而SystemServiceManager就是这些服务的管理对象。

然后调用:

将SystemServiceManager对象保存SystemServer进程中的一个数据结构中。

LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

最后开始执行:

// Start services.
try {
    startBootstrapServices();
    startCoreServices();
    startOtherServices();
} catch (Throwable ex) {
    Slog.e("System", "******************************************");
    Slog.e("System", "************ Failure starting system services", ex);
    throw ex;
}

里面主要涉及了是三个方法:

startBootstrapServices() 主要用于启动系统Boot级服务

startCoreServices() 主要用于启动系统核心的服务

startOtherServices() 主要用于启动一些非紧要或者是非需要及时启动的服务

4.启动服务 4.1 启动哪些服务

在开始执行启动服务之前总是会先尝试通过socket方式连接Zygote进程,在成功连接之后才会开始启动其他服务。

4.2 启动服务流程源码分析

首先看一下startBootstrapServices方法:

private void startBootstrapServices() {
    Installer installer = mSystemServiceManager.startService(Installer.class);

    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

    mActivityManagerService.initPowerManagement();

    // Manages LEDs and display backlight so we need it to bring up the display.
    mSystemServiceManager.startService(LightsService.class);

    // Display manager is needed to provide display metrics before package manager
    // starts up.
    mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

    // We need the default display before we can initialize the package manager.
    mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

    // Only run "core" apps if we"re encrypting the device.
    String cryptState = SystemProperties.get("vold.decrypt");
    if (ENCRYPTING_STATE.equals(cryptState)) {
        Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
        mOnlyCore = true;
    } else if (ENCRYPTED_STATE.equals(cryptState)) {
        Slog.w(TAG, "Device encrypted - only parsing core apps");
        mOnlyCore = true;
    }

    // Start the package manager.
    Slog.i(TAG, "Package Manager");
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    mFirstBoot = mPackageManagerService.isFirstBoot();
    mPackageManager = mSystemContext.getPackageManager();

    Slog.i(TAG, "User Service");
    ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());

    // Initialize attribute cache used to cache resources from packages.
    AttributeCache.init(mSystemContext);

    // Set up the Application instance for the system process and get started.
    mActivityManagerService.setSystemProcess();

    // The sensor service needs access to package manager service, app ops
    // service, and permissions service, therefore we start it after them.
    startSensorService();
}

先执行:

Installer installer = mSystemServiceManager.startService(Installer.class);

mSystemServiceManager是系统服务管理对象,在main方法中已经创建完成,这里我们看一下其startService方法的具体实现:

可以看到通过反射器构造方法创建出服务类,然后添加到SystemServiceManager的服务列表数据中,最后调用了service.onStart()方法,因为传递的是Installer.class

public  T startService(Class serviceClass) {
    final String name = serviceClass.getName();
    Slog.i(TAG, "Starting " + name);

    // Create the service.
    if (!SystemService.class.isAssignableFrom(serviceClass)) {
        throw new RuntimeException("Failed to create " + name
                + ": service must extend " + SystemService.class.getName());
    }
    final T service;
    try {
        Constructor constructor = serviceClass.getConstructor(Context.class);
        service = constructor.newInstance(mContext);
    } catch (InstantiationException ex) {
        throw new RuntimeException("Failed to create service " + name
                + ": service could not be instantiated", ex);
    } catch (IllegalAccessException ex) {
        throw new RuntimeException("Failed to create service " + name
                + ": service must have a public constructor with a Context argument", ex);
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException("Failed to create service " + name
                + ": service must have a public constructor with a Context argument", ex);
    } catch (InvocationTargetException ex) {
        throw new RuntimeException("Failed to create service " + name
                + ": service constructor threw an exception", ex);
    }

    // Register it.
    mServices.add(service);

    // Start it.
    try {
        service.onStart();
    } catch (RuntimeException ex) {
        throw new RuntimeException("Failed to start service " + name
                + ": onStart threw an exception", ex);
    }
    return service;
}

看一下Installer的onStart方法:

很简单就是执行了mInstaller的waitForConnection方法,这里简单介绍一下Installer类,该类是系统安装apk时的一个服务类,继承SystemService(系统服务的一个抽象接口),需要在启动完成Installer服务之后才能启动其他的系统服务。

@Override
public void onStart() {
    Slog.i(TAG, "Waiting for installd to be ready.");
    mInstaller.waitForConnection();
}

然后查看waitForConnection()方法:

通过追踪代码可以发现,其在不断的通过ping命令连接Zygote进程(SystemServer和Zygote进程通过socket方式通讯,其他进程通过Binder方式通讯)

public void waitForConnection() {
    for (;;) {
        if (execute("ping") >= 0) {
            return;
        }
        Slog.w(TAG, "installd not ready");
        SystemClock.sleep(1000);
    }
}

继续看startBootstrapServices方法:

这段代码主要是用于启动ActivityManagerService服务,并为其设置SysServiceManager和Installer。ActivityManagerService是系统中一个非常重要的服务,Activity,service,Broadcast,contentProvider都需要通过其余系统交互。

// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
        ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);

首先看一下Lifecycle类的定义:

可以看到其实ActivityManagerService的一个静态内部类,在其构造方法中会创建一个ActivityManagerService,通过刚刚对Installer服务的分析我们知道,SystemServiceManager的startService方法会调用服务的onStart()方法,而在Lifecycle类的定义中我们看到其onStart()方法直接调用了mService.start()方法,mService是Lifecycle类中对ActivityManagerService的引用

public static final class Lifecycle extends SystemService {
    private final ActivityManagerService mService;

    public Lifecycle(Context context) {
        super(context);
        mService = new ActivityManagerService(context);
    }

    @Override
    public void onStart() {
        mService.start();
    }

    public ActivityManagerService getService() {
        return mService;
    }
}

4.3 启动部分服务

启动PowerManagerService服务:

启动方式跟上面的ActivityManagerService服务相似都会调用其构造方法和onStart方法,PowerManagerService主要用于计算系统中和Power相关的计算,然后决策系统应该如何反应。同时协调Power如何与系统其它模块的交互,比如没有用户活动时,屏幕变暗等等。

mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

然后是启动LightsService服务

主要是手机中关于闪光灯,LED等相关的服务;也是会调用LightsService的构造方法和onStart方法;

mSystemServiceManager.startService(LightsService.class);

然后是启动DisplayManagerService服务

主要是手机显示方面的服务

mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

然后是启动PackageManagerService,该服务也是android系统中一个比较重要的服务

包括多apk文件的安装,解析,删除,卸载等等操作。

可以看到PackageManagerService服务的启动方式与其他服务的启动方式有一些区别,直接调用了PackageManagerService的静态main方法

Slog.i(TAG, "Package Manager");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();

看一下其main方法的具体实现:

可以看到也是直接使用new的方式创建了一个PackageManagerService对象,并在其构造方法中初始化相关变量,最后调用了ServiceManager.addService方法,主要是通过Binder机制与JNI层交互

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    ServiceManager.addService("package", m);
    return m;
}

然后查看startCoreServices方法:

可以看到这里启动了BatteryService(电池相关服务),UsageStatsService,WebViewUpdateService服务等。

private void startCoreServices() {
    // Tracks the battery level.  Requires LightService.
    mSystemServiceManager.startService(BatteryService.class);

    // Tracks application usage stats.
    mSystemServiceManager.startService(UsageStatsService.class);
    mActivityManagerService.setUsageStatsManager(
            LocalServices.getService(UsageStatsManagerInternal.class));
    // Update after UsageStatsService is available, needed before performBootDexOpt.
    mPackageManagerService.getUsageStatsIfNoPackageUsageInfo();

    // Tracks whether the updatable WebView is in a ready state and watches for update installs.
    mSystemServiceManager.startService(WebViewUpdateService.class);
}

总结:

SystemServer进程是android中一个很重要的进程由Zygote进程启动;

SystemServer进程主要用于启动系统中的服务;

SystemServer进程启动服务的启动函数为main函数;

SystemServer在执行过程中首先会初始化一些系统变量,加载类库,创建Context对象,创建SystemServiceManager对象等之后才开始启动系统服务;

SystemServer进程将系统服务分为三类:boot服务,core服务和other服务,并逐步启动

SertemServer进程在尝试启动服务之前会首先尝试与Zygote建立socket通讯,只有通讯成功之后才会开始尝试启动服务;

创建的系统服务过程中主要通过SystemServiceManager对象来管理,通过调用服务对象的构造方法和onStart方法初始化服务的相关变量;

服务对象都有自己的异步消息对象,并运行在多带带的线程中;

参考博客

https://www.jianshu.com/p/064...

http://blog.csdn.net/qq_23547...

http://www.xuebuyuan.com/2178...

https://www.jianshu.com/p/e69...

http://blog.csdn.net/luosheng...

http://blog.csdn.net/ericming...

关于其他内容介绍 01.关于博客汇总链接

1.技术博客汇总

2.开源项目汇总

3.生活博客汇总

4.喜马拉雅音频汇总

5.其他汇总

02.关于我的博客

我的个人站点:www.yczbj.org,www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

简书:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜马拉雅听书:http://www.ximalaya.com/zhubo...

开源中国:https://my.oschina.net/zbj161...

泡在网上的日子:http://www.jcodecraeer.com/me...

邮箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault头条:https://segmentfault.com/u/xi...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72062.html

相关文章

  • 马蜂窝 iOS App 启动治理:回归用户体验

    摘要:马蜂窝旅游历经几十个版本的开发迭代,在启动流程上积累了一定的技术债务。我们定义启动广告曝光率启动广告曝光启动广告加载。 增长、活跃、留存是移动 App 的常见核心指标,直接反映一款 App 甚至一个互联网公司运行的健康程度和发展动能。启动流程的体验决定了用户的第一印象,在一定程度上影响了用户活跃度和留存率。因此,确保启动流程的良好体验至关重要。 「马蜂窝旅游」App 是马蜂窝为用户提供...

    Jinkey 评论0 收藏0
  • koa2 总体流程原理浅析(一) 之 koa 启动服务器解析

    摘要:启动流程主要的启动流程就是下面的步引入包实例化编写中间件监听服务器引入包引入包其实就是引入的一个继承于原生的类的类其中就包含了等原型方法实例化执行,将等对象封装在实例中编写中间件首先判断的类型,不是方法直接抛错是生成器函数的话用封装是函数 启动流程 koa 主要的启动流程就是下面的 4 步:引入 koa 包 => 实例化 koa => 编写中间件 => 监听服务器 const koa ...

    fsmStudy 评论0 收藏0
  • Laravel 启动流程

    摘要:年月日阶段划分请求到响应的整个执行阶段归纳为个程序启动准备阶段文件自动加载服务容器实例化基础服务提供者的注册核心类的实例化请求实例化阶段实例化实例请求处理阶段准备请求处理的环境将请求实例通过中间件处理及通过路由和控制器的分发控制响应发送和 Last-Modified: 2019年5月10日16:19:07 阶段划分 Laravel 5.5请求到响应的整个执行阶段归纳为 4 个: ...

    VPointer 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<