Android---系统启动流程

news2024/11/27 1:37:24

目录

Android 系统启动流程

init 进程分析

init.rc 解析

Zygote 概叙

Zygote 触发过程

Zygote 启动过程

什么时Runtime?

System Server 启动流程

Fork 函数

总结

面试题

Android 是 google 公司开发的一款基于 Linux 的开源操作系统。

Android 系统启动流程

android 系统启动的大概流程如下图所示:

\bullet 第一步:启动电源以及系统启动

当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到 RAM,然后执行。

\bullet 第二步:引导程序

 引导程序是在 Android 操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如 reboot, uboot, qibootloader 或者开发自己的引导程序,它不是 Android 操作系统的一部分。引导程序是 OEM 厂商或者运营商加锁和限制的地方。

引导程序分两个阶段执行:

第一阶段:检测外部的RAM以及加载第二阶段有用的程序。

第二阶段:引导程序设置网络、内存等等。这些对于运行内核是必须的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。

Android 引导程序可以在 \bootable\bootloader\regacy\usbloader 找到。传统的加载器包含两个文件,需要在这里说明:

init.s 初始化堆栈,清零 BBS 段,调用 main.c 的 main()  函数;

main.c 初始化硬件(闹钟、主板、键盘、控制台) ,创建 linux 标签

 \bullet 第三步:内核(Kernel)

Android 内核与桌面 linux 内核启动方式差不多。内核启动时,设置缓存、保护存储器、计划列表、加载驱动。当内核完成系统设置,它首先在系统文件种寻找 "init" 文件,然后启动 root 进程或者系统的第一个进程。

 \bullet 第四步:init 进程

init 进程是 Linux 系统中用户空间的第一个进程,进程号固定为1。Kernel 启动后,在用户空间启动 init 进程,并调用 init 中的 main() 方法执行 init 进程的职责。

 \bullet 第五步:启动 Lancher App

init 进程分析

其中 init 进程是 Android 系统中及其重要的第一个进程,init 进程做了如下三件事:

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

  2. 初始化和启动属性服务

  3. 解析 init.rc 配置文件并启动 zygote 进程

init.rc 解析

init.rc 是一个非常重要的配置文件,它是由 Android 初始化语言(Android Init Language) 编写的脚本,它主要包含五种类型语句:Action(Action 中包含了一系列的 Command)、Commands(init 语言中的命令)、Services(由 init 进程启动的服务)、Options(对服务进行配置的选项) 和 Import (导入其它配置文件)。init.rc 的配置代码如下所示:

# \system\core\rootdir\init.rc
on init # L41
sysclktz 0
# Mix device-specific information into the entropy pool
copy /proc/cmdline /dev/urandom
copy /default.prop /dev/urandom
...
on <trigger> [&& <trigger>]* //设置触发器
<command>
<command> //动作触发之后要执行的命令
service <name> <pathname> [ <argument> ]* //<service的名字><执行程序路径><传递参
数>
<option> //Options是Services的参数配置. 它们影响Service如何运行及运行时机
group <groupname> [ <groupname>\* ] //在启动Service前将group改为第一个
groupname,第一个groupname是必须有的,
//默认值为root(或许默认值是无),第二个groupname可以不设置,用于追加组(通过
setgroups)
priority <priority> //设置进程优先级. 在-20~19之间,默认值是0,能过
setpriority实现
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]//创建
一个unix域的socket,名字叫/dev/socket/name , 并将fd返回给Service. type 只能是
"dgram", "stream" or "seqpacket".
...

 Action

Action: 通过触发器 trigger,即以 on 开头的语句来决定执行相应的 service 的时机:

  \bullet on early-init: 在初始化早期阶段触发;

  \bullet on init: 在初始化阶段触发;

  \bullet on late-init: 在初始化晚期阶段触发;

  \bullet on boot/charger: 当系统启动/充电时触发;

  \bullet on property: 当属性值满足条件时触发。

 Service

 服务 Service,以 service 开头,由 init 进程启动,一般运行在 init 的一个子进程,所以启动 service 前需要判断对应的可执行文件是否存在。init 生成的子进程,定义在 rc 文件,其中每一个 service 在启动时会通过 fork 方式生成子进程

例如:service servicemanager /system/bin/servicemanager 代表的是服务名为 servicemanager,服务执行的路径为 /system/bin/servicemanager。

Command

 下面列举常用的命令:

  \bullet class_start<service_class_name>: 启动属于同一个 class 的所有服务;

  \bullet start<service_name>: 启动指定的服务,若已启动则跳过;

  \bullet stop<service_name>: 停止正在运行的服务;

  \bullet setprop: 设置属性值;

  \bullet mkdir: 创建指定目录;

  \bullet symlink<sym_link>: 创建连接到的<sym_link>符号链接;

  \bullet write: 向文件 path 中写入字符串;

  \bullet exec: fork并执行,会阻塞 init 进程直到程序完毕;

  \bullet exprot: 设置环境变量;

  \bullet loglevel: 设置 log 级别。

Options

Options 是 Service 的可选项,与 Service 配合使用

  \bullet disabled: 不随 class 自动启动,只根据 service 名才启动;

  \bullet oneshot: service 退出后不再重启;

  \bullet user/group: 设置执行服务的用户/用户组,默认都是 root;

  \bullet class: 设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为 default;

  \bullet onrestart: 当服务重启时执行相应命令;

  \bullet socket: 创建名为 /dev/socket/<name> 的socket

  \bullet critical: 在规定时间内该 service 不断重启,则系统会重启并进入恢复模式。

default: 意味着 disabled = false, oneshot = false, critical = false。

Zygote 概叙

Zygote 中文翻译为“受精卵”,它主要用于孵化子进程。在 Android 系统中有以下两种程序:Java 应用程序,主要基于 ART(Android Runtime) 虚拟机,所有的应用程序 apk 都属于这类 native 程序,也就是利用 C/C++ 语言开发的程序,如 bootanimation。所有的 Java 应用程序进程及系统服务(SystemServer)进程都由 Zygote 进程通过 Linux 的 fork() 函数卵化出来的,也就是为什么把它称为 Zygote 的原因,因为他就像一个受精卵,卵化出无数子进程,而 native 程序则由 Init 程序创建启动。Zygote 进程最初的名字不是“zygote”而是“app_process”,这个名字是在 Android.mk 文件中定义的。

Zygote 是 Android 中的第一个 ART 虚拟机,他通过 socket 的方式与其它进程进行通信。这里的“其他进程”其实主要是系统进程--SystemServer。

Zygote 是一个 C/S 模型,Zygote 进程作为服务端,它主要负责创建 Java 虚拟机,加载系统资源,启动 SystemServer 进程,以及在后续运行过程中启动普通的应用程序,其他进程作为客户端向它发出“孵化”请求,而 Zygote 接收到这个请求后就“孵化”出一个新的进程。比如,当点击 Launcher 里的应用程序图标去启动一个新的应用程序时,这个请求会到达框架层的核心服务 ActivityManagerService 中,当 AMS 收到这个请求后,它通过调用 Process 类发出一个“孵化”子进程的 Socket 请求,而 Zygote 监听到这个请求后就立刻 fork 一个新的进程出来。

Zygote 触发过程

1. init.zygoteXX.rc

import /init.${ro.zygote}.rc

${ro.zygote} 会被替换成 ro.zygote 的属性值,这个是由不同的硬件厂商自己制定的,由四个值:

    \bullet zygote32: zygote进程对应的执行程序是 app_process(纯32bit 模式)

    \bullet zygote64: zygote进程对应的执行程序是 app_process64(纯32bit 模式)

    \bullet zygote32_64: 启动两个 zygote 进程(名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process32(主模式)、approcess63

     \bullet zygote64_32: 启动两个 zygote 进程(名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process64(主模式)、app_precess32

2. start zygote

位置:system\core\rootdir\init.rc,zygote-start 是在 on late-init 中触发的。

3. app_processXX

位置 \frameworks\base\cmds\app_process\

Zygote 启动过程

位置 \frameworks\base\cmds\app_process\app_main.cpp
在 app_main.cpp 的 main 函数中,主要做的事情就是参数解析。这个函数有两种启动模式:
        1. zygote 模式,也就是初始化 zygote 进程,传递的参数有 --start-system-server --socket - name = zygote,前者表示启动 SystemServer,后者指定 socket 的名称。
        2. application模式,也就是启动普通应用程序,传递的参数有 class 名字以及 class 带的参数
两者最终都是调用 AppRuntime 对象的 start 函数,加载 ZygoteInit 或 RuntimeInit 两个 Java 类,并将之前整理的参数传入进去。

 app_process 里面定义了三种应用程序类型:

   1. Zygote: com.android.internal.os.ZygoteInit

   2. SystemServer 不单独启动,而是由 Zygote 启动

   3. 其他指定类名的 Java 程序

什么时Runtime?

Runtime 是支撑程序运行的基础库,它是与语言绑定在一起的。比如:

  \bullet C Runtim: 就是 C standard lib,也就是我们常说的 libc。(有意思的是,Wiki 会自动将" C Runtime" 重定向到"C Standard Library")。

  \bullet Java Runtime: 同样,Wiki 将其重定向到" Java Virtual Machine",这里当然包括 Java 的支撑类库(.jar)。

  \bullet AndroidRuntime: 显而易见,就是为 Android 应用运行所需要的运行时环境。这个环境包括以下内容:

        1. Dalvik VM: Android 的 Java VM, 解释运行 Dex 格式 Java 程序。每个进程运行一个虚拟机(什么叫运行虚拟机?说白了,就是一些 C 代码,不停的去解释 Dex 格式的二进制码(Bytecode),把它们转成机器码(Machine code),然后执行,当然,限制大多数的 Java 虚拟机都支持 JIT,也就是说,bytecode 可能在运行前就以及被转换成机器码,从而大大提高了性能。过去一个普遍的认识是 Java 程序比 C/C++ 等静态编译的语言慢,但随着 JIT 的介入和发展,这个有已经完全是过去式了,JIT 的动态性运行允许虚拟机根据运行时环境,优化机器码的生成,在某些情况下,Java 甚至可以比 C/C++ 跑得更快,同时又兼具平台无关性的特性。

        2. Android 的 Java 类库,大部分来自于 Apache Hamony,开源的 Java API 实现,如 java.lang, java.util, java.net。但去除了 AWT,Swing 等部件。

        3. JNI: C 和 Java 互掉的接口。

        4. Libc: Android 也有很多 C 代码,自然少不了 libc,注意的是,Android 的 libc 叫 bionic C

// \frameworks\base\core\jni\androidRuntime.cpp start() L1091
void AndroidRuntime::start(const char* className, const Vector<String8>&
options, bool zygote)
{
...
JNIEnv* env;
//JNI_CreateJavaVM L1015
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
}

  \bullet Java 虚拟机的启动大致做了以下一些事情:

        1. 从 property 读取一系列启动参数。

        2. 创建和初始化结构体全局对象(每个进程)GDVM,及对应于 JavaVM 和 JNIEnv 的内部结构体 JavaVMExt, JNIEnvExt.

        3. 初始化 java 虚拟机,并创建虚拟机线程。

        4. 注册系统的 JNI,Java 程序通过这些 JNI 接口来访问底层的资源。

loadJniLibrary("javacore");
loadJniLibrary("nativehelper");

        5. 为 Zygote 的启动做最后的准备,包括设置 SID/UID,以及 mount 文件系统。

        6. 返回 JavaVM 给 Native 代码,这样它就可以向上访问 Java 的接口。

System Server 启动流程

System Server 是 Zygote fork 的第一个 java 进程,这个进程非常重要,因为他们有很多的系统线程,提供所有核心的系统服务。

看到大名鼎鼎的 WindowManager,ActivityManager 了吗?对了,它们都是运行在 system_server 的进程里。还有很多 "Binder-x" 的线程,它们是各个 Service 为了响应应用程序远程调用请求而创建的。除此之外,还有很多内部线程,比如”UI thread", "InputReader", "InputDispatch" 等等,现在我们只关心 System Server 是如何创建起来的。

SystemServer 的 main() 函数。

public static void main(String[] args) {
new SystemServer().run();
}

接下来我们分成4部分详细分析 SystemServer.run 方法的初始化流程:

\bullet 初始化必要的 SystemServer 环境参数,比如系统时间、默认时区,语言、load 一些 Library 等等。

\bullet 初始化 Looper,我们在主线程中使用到的 looper 就是在 SystemServer 中进行初始化的

\bullet 初始化 Context,只有初始化一个 Context 才能进行启动 Service 等操作,这里看一下源码:

private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
final Context systemUiContext = activityThread.getSystemUiContext();
systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
看到没有 ActivityThread 就是这个时候生成的。继续看ActivityThread 中如何生成 Context:
public ContextImpl getSystemContext() {
    synchronized (this) {
        if (mSystemContext == null) {
            mSystemContext = ContextImpl.createSystemContext(this);
        }
    return mSystemContext;
    }
}

ContextImpl 是 Context 类的具体实现,里面封装完成了几种常用的 createContext 的方法:

static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
//省略代码
return context;
}
static ContextImpl createSystemUiContext(ContextImpl systemContext) {
final LoadedApk packageInfo = systemContext.mPackageInfo;
//省略代码
return context;
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk
packageInfo) {
if (packageInfo == null) throw new
IllegalArgumentException("packageInfo");
//省略代码
return context;
}
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder
activityToken, int displayId,
Configuration overrideConfiguration) {
//省略代码
return context;
}

初始化 SystemServiceManager,用来管理启动 Service,SystemServiceManager 中封装了启动 Service 的 startService 方法启动系统必要的 Service,启动 service 的流程又分成三步:

// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
//
} finally {
traceEnd();
}

启动 BootstrapServices,就是系统必须需要的服务,这些服务直接耦合性很高,所以就干脆放在一个方法里面一起启动,比如 PowerManagerService、RecoverySystemService、DisplayMangerService、ActivityManagerService 等等启动以基本的核心 Service,很简单,只有三个 BatteryService、UsageStatsService、WebViewUpdateService 启动其它需要用到的 Service 比如 NetworkScoreService、AlarmManagerService

Fork 函数

pid_t fork(void)
1. 参数:不需要参数
2. 需要的头文件 <sys/types.h> <unistd.h>
3. 返回值分两种情况:
        返回0 表示成功创建子进程,并且接下来进入子进程执行流程
        返回PID >0 ),成功创建子进程,并且继续执行父进程流程代码
        返回非正数(<0 ),创建子进程失败,失败原因主要有:
        进程数超过系统所能创建的上限,errno 会被设置为 EAGAIN 系统内存不足, errno 会被设置为
        ENOMEM

 

使用 fork() 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空
间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈、打开的文件描述符、信号控
制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只有小量信
息)。因此,使用 fork() 函数的代价是很大的

         

总结

1. init 根据 init.rc 运行 app_process,并携带“-zygote" 和"-startSystemServer"参数。

2. AndroidRuntime.cpp::start() 里将启动 JavaVM,并且注册所有 framework 相关的系统 JNI 接口

3. 第一次进入 Java 世界,运行 ZygoteInit.java::main() 函数初始化 Zygote,并创建 Socket 的 Server 端。

4. 然后 fork 一个新的进程并在新进程里初始化 SystemServer.Fork 之前,Zygote 是 preload 常用的 Java 类库,以及系统的 resource,同时 GC 清理内存空间,为子进程省去重复的工作。

5. SystemServer 将所有的系统 Service 初始化,包括 ActivityManager 和 WindowManager,他们是应用程序运行起来的前提。

6. 依次同时,Zygote 监听服务端 Socket,等待新的应用启动请求。

7. ActivityManager ready 之后寻找系统的 “Startup" Application,将请求发给 Zygote。

8. Zygote 收到请求后,fork 出一个新的进程。

9. Zygote 监听并处理 SystemServer 的 SIGCHID 信号,一旦 SystemServer 崩溃,立即将自己 kill 掉。init 会重启 Zygote。

面试题

1. 你了解 Android 系统启动流程吗?
答:当按电源键触发开机,首先会从 ROM 中预定义的地方加载引导程序 BootLoader RAM 中,并执 行 BootLoader 程序启动 Linux Kernel , 然后启动用户级别的第一个进程: init 进程。 init 进程会解析 init.rc 脚本做一些初始化工作,包括挂载文件系统、创建工作目录以及启动系统服务进程等,其中系统 服务进程包括 Zygote service manager media 等。在 Zygote 中会进一步去启动 system_server 进 程,然后在 system_server 进程中会启动 AMS WMS PMS 等服务,等这些服务启动之后, AMS 中就 会打开 Launcher 应用的 home Activity ,最终就看到了手机的 " 桌面 "
2.  system_server 为什么要在 Zygote 中启动,而不是由 init 直接启动呢?
答:Zygote 作为一个孵化器,可以提前加载一些资源,这样 fork() 时基于 Copy-On-Write 机制创建的其 他进程就能直接使用这些资源,而不用重新加载。比如 system_server 就可以直接使用 Zygote 中的 JNI 函数、共享库、常用的类、以及主题资源。
3. 为什么要专门使用 Zygote 进程去孵化应用进程,而不是让 system_server 去孵化呢?
答:首先 system_server 相比 Zygote 多运行了 AMS WMS 等服务,这些对一个应用程序来说是不需要 的。另外进程的 fork() 对多线程不友好,仅会将发起调用的线程拷贝到子进程,这可能会导致死锁,而 system_server 中肯定是有很多线程的。
4. 能说说具体是怎么导致死锁的吗?
答:在 POSIX 标准中, fork 的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write 的策略, 所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别 的线程,到了子进程中都是突然蒸发掉的,对于锁来说,从 OS 看,每个锁有一个所有者,即最后一次 lock 它的线程。假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。 fork 以后,在子进程中,所有的额外线程都 人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。 当子进程想 lock 这个锁时,不再有任何手段可以解开了。程序发生死锁
5.  Zygote 为什么不采用 Binder 机制进行 IPC 通信?
答:Binder 机制中存在 Binder 线程池,是多线程的,如果 Zygote 采用 Binder 的话就存在上面说的 fork() 与 多线程的问题了。其实严格来说, Binder 机制不一定要多线程,所谓的 Binder 线程只不过是 在循环读取 Binder 驱动的消息而已,只注册一个 Binder 线程也是可以工作的,比如 service manager 就是这样的。实际上 Zygote 尽管没有采取 Binder 机制,它也不是单线程的,但它在 fork() 前主动停止 了其他线程,fork() 后重新启动了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Web3中文|一波未平一波又起:Silvergate将走向何处

Silvergate Capital&#xff08;SI&#xff09;这一加密公司曾经的重要银行合作伙伴&#xff0c;现在正处于崩溃的边缘。这家总部位于加州拉荷亚的公司上周五晚上表示&#xff0c;其暂停了Silvergate交易所网络&#xff08;SEN&#xff1a;Silvergate Exchange Network&#xf…

Foxit PDF SDK ActiveX 5.9.7 Crack

Foxit PDF SDK ActiveX对于刚接触PDF或不愿投入过多精力学习PDF技术的产品管理者及开发者来说&#xff0c;Foxit PDF SDK ActiveX无疑是理想的选择。破解版它拥有操作简单的特性&#xff0c;提供可支持定制的可视化编程组件&#xff0c;开发者通过简单的拖放动作&#xff0c;就…

扬帆配资|建筑业景气度持续回升,多只概念股业绩有望增长

新式城镇化概念股遭到商场重视。 今天早盘&#xff0c;新式城镇化概念股冲高&#xff0c;恒锋信息、ST花王涨停。蕾奥规划、筑博规划一度冲高至15%&#xff0c;冠龙节能、杭州园林、美晨生态跟涨。 国家出台一系列城镇化相关方针 城镇化&#xff0c;是人口向城镇会集的进程。…

【Kubernetes】第二十三篇 - 布署 nodejs 后端项目(上)

一&#xff0c;前言 上一篇&#xff0c;介绍了 MySQL 服务的部署&#xff1b; 本篇&#xff0c;介绍 nodejs 后端项目的布署&#xff08;将后端项目构建成为 docker 镜像&#xff0c;并推送至镜像仓库&#xff09;&#xff1b; 二&#xff0c;准备项目 创建后端项目&#xf…

8、LSM树

一、前言 最近在调研NoSQL数据库&#xff0c;发现RocksDB、LevelDB、HBase以及Prometheus等&#xff0c;其底层的存储引擎都是基于LSM树&#xff0c;于是决定花时间彻底吃透LSM树这一数据结构。 不幸的是&#xff0c;在查阅资料学习的过程中&#xff0c;发现网上各种文章汗牛…

浅谈对Promise的理解以及在工作中的应用

浅谈对Promise的理解以及在工作中的应用Promise的概念背景知识JavaScript的同步和异步JavaScript事件循环回调函数进行异步操作解决方案&#xff1a;PromisePromise 在工作中的运用创建PromisePromise封装AJAXPromise链式操作Promise.all()Promise.race()async和await总结Promi…

轻松转换文档:antennahouse/Office Server Document Converter

关于 Office Server 文档转换器 (OSDC)破解版 无需 Microsoft Office 或 Adob​​e 软件即可快速准确地转换文档。 Office Server 文档转换器 (OSDC) 会将您在 Microsoft Office&#xff08;Word、Excel、PowerPoint&#xff09;中创建的重要文档转换为高质量的 PDF 或图像格式…

国内32位MCU在电机控制上的应用方案

电机&#xff08;Electric machinery&#xff0c;俗称“马达”&#xff09;是依据电磁感应定律&#xff0c;实现电能转换或传递的一种电磁装置&#xff0c;其主要作用是产生驱动转矩&#xff0c;为用电器或各类机械提供动力。电机作为工业世界的动力之源&#xff0c;几乎用于所…

ThinkPHP 6.1 模板篇之布局与继承

本文主要讲述ThinkPHP 6.1版本模板几种布局的方法和如何实现继承&#xff0c; 可以与《ThinkPHP 6.1 模板篇之文件加载》结合来看。 模板布局 布局方式有两种可以实现。 布局方法1 开启配置 默认情况下&#xff0c;不支持模版布局功能&#xff0c;需要在配置文件中开启&…

如何快速通过PMP考试?

我建议准备的最短时间至少一个月&#xff0c;我用了一个半月&#xff0c;我每天集中精力备考大约4个小时&#xff0c;大家可以根据自己的专注力的长短去调节每天的备考时间。 准备5月的&#xff0c;还没备考的&#xff0c;现在开始也来得及。5月没有报名的可以准备8月的&#…

【Linux系统编程】05:多进程

多进程 OVERVIEW多进程一、进程创建1.创建1个子进程2.创建多个子进程二、进程控制1.进程结束2.进程等待3.子进程操作14.子进程操作2三、进程体系1.守护进程2.进程调度程序&#xff1a;一种已经编译好的、存在磁盘中的二进制文件&#xff08;脚本为普通文件&#xff09;。进程&a…

超图iServer扩展开发记录Restlet 3

HTTP 请求在达到 REST 应用对象&#xff0c;交给资源实现类处理的时候&#xff0c;先要解析 HTTP 请求中的参数&#xff0c;然后才会进入业务逻辑进行处理。参数解析的工作由参数解析器&#xff08;Decoder&#xff09;进行&#xff0c;即可以实现将请求参数转换为 Java 对象。…

qt tcp通讯

TCP 协议&#xff08;Transmission Control Protocol&#xff09;全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。tcp服务端使用QTcpServer、QTcpSocket。tcp客户端使用QTcpSocket1.在工程文件(工程文件.pro)中的第一行添加network 如QT core gui …

WeSpeaker支持C++部署链路

WeSpeaker正式更新C部署链路&#xff0c;推理引擎使用OnnxRuntime&#xff0c;支持从语音中提取Speaker Embedding信息&#xff0c;代码详见WeSpeaker/runtime[1]。 Libtorch和onnx的选择? Speaker Embedding提取任务流程简单&#xff0c;并且声纹模型&#xff08;如ResNet\E…

前端js学习

1. js入门 1.1 js是弱类型语言 1.2 js使用方式 1.2.1 在script中写 1.2.2 引入js文件 1.2.3 优先级 1.3 js查错方式 1.4 js变量定义 1.4 js数据类型 数据类型英文表示示例数值类型number1.1 1字符串类型string‘a’ ‘abc’ “abc”对象类型object布尔类型booleannumber函数…

包教包会的Node.js

一、简介 1、什么是Node.js 简单的说 Node.js 就是运行在服务端的 JavaScript。 Node.js是一个事件驱动I/O服务端JavaScript环境&#xff0c;基于Google的V8引擎&#xff0c;V8引擎执行Javascript的速度非常快&#xff0c;性能非常好。 2、Node.js有什么用 如果你是一个前…

风起|微软突发声明:始终严格保护并捍卫用户隐私

开放隐私计算 3 月 9 日消息&#xff0c;微软中国今天发布了声明&#xff0c;针对日前国内某些自媒体传播的有关个人用户使用微软消费类产品和服务的误解&#xff0c;特做了相关说明。微软表示&#xff0c;微软始终严格遵守个人隐私保护与数据安全等方面的各项法律法规。微软提…

深眸科技突破革新机器视觉技术,加速实现工业自动化与智能化发展

随着现代生活水平的不断提高&#xff0c;人们对产品的品质需求持续提升&#xff0c;且在智能制造这一大环境下&#xff0c;多数制造企业积极转型&#xff0c;寻求更高效的检测方式。而机器视觉及相关技术的发展&#xff0c;让多数公司通过创新机器视觉应用产品&#xff0c;以及…

面试必会-MySQL篇

1. Mysql查询语句的书写顺序Select [distinct ] <字段名称>from 表1 [ <join类型> join 表2 on <join条件> ]where <where条件>group by <字段>having <having条件>order by <排序字段>limit <起始偏移量,行数>2. Mysql查询语…

vue3使用nextTick

发现nextTick必须放在修改一个响应式数据之后&#xff0c;才会在onUpdated之后被调用&#xff0c;如果nextTick是放在所有对响应式数据修改之前&#xff0c;则nextTick里面的回调函数会在onBeforeUpdate方法执行前就被调用了。可是nextTick必须等到onUpdated执行完成之后执行&a…