当前位置: 首页 > news >正文

Android Framework 之 启动流程

Android 系统的启动流程

Android 系统的启动流程可以分为以下几个主要步骤:

  1. 引导加载器(Bootloader)启动:当你打开一个 Android 设备时,首先启动的是引导加载器。引导加载器负责启动 Android 的核心操作系统。

  2. Linux 内核启动:引导加载器加载并启动 Linux 内核。Linux 内核负责启动系统的底层硬件,并启动 init 进程。

  3. Init 进程启动:init 进程是 Linux 系统中的第一个进程(PID = 1)。在 Android 系统中,init 进程负责启动一些重要的守护进程和服务,例如 Zygote 进程。

  4. Zygote 进程启动:Zygote 是 Android 中的一个特殊进程,负责孵化(Fork)出所有其他的应用进程。Zygote 进程在启动时会预加载大量的系统类和资源,以此来提高应用启动的速度。

  5. SystemServer 进程启动:Zygote 进程会 fork 出一个新的进程来启动 SystemServer。SystemServer 是 Android 系统中的核心服务,它管理并提供了许多系统级别的服务,例如窗口管理服务、活动管理服务等。

  6. 系统服务启动:在 SystemServer 进程中,会启动各种系统服务。这些服务在系统启动完成后,将一直运行,为应用程序提供各种服务。

  7. 启动 Launcher 应用:系统服务启动完毕后,Activity Manager Service 会启动设备的 Launcher 应用,此时,用户可以开始与设备进行交互。

这就是 Android 系统启动的整个过程。请注意,这个过程可能会因设备制造商的定制和 Android 版本的不同而有所不同,但大体流程是相同的。

Launcher的启动流程

Launcher 的启动过程更具体的说明如下:

  1. 当 Android 系统启动完成,并且所有的系统服务都已经启动后,ActivityManagerService (AMS)会开始处理用户的交互。AMS 是 Android 中负责管理所有活动的系统服务。

  2. AMS 会发送一个包含 ACTION_MAIN 和 CATEGORY_HOME 的 Intent。这个 Intent 的目的是寻找并启动设备上配置为主屏幕(HOME)的应用,通常这就是 Launcher 应用。

  3. 这个 Intent 会通过 Android 的 Intent 解析系统,寻找所有能够响应这个 Intent 的应用。由于 Launcher 在其清单文件(AndroidManifest.xml)中声明了相应的 ,因此它会被选中来响应这个 Intent。

  4. 一旦 Launcher 被选中,AMS 就会请求 Launcher 启动。如果这是设备第一次启动,或者 Launcher 进程尚未启动,那么 AMS 会请求 Zygote 启动一个新的进程来托管 Launcher。如果 Launcher 进程已经存在,AMS 就会在该进程中启动新的 Launcher 活动实例。

  5. 当 Launcher 启动后,它会创建并显示用户的主屏幕。这个屏幕上会显示应用的图标、小部件等,用户可以通过这个界面启动和切换应用。

startActivity 详细说明

  1. 发送 Intent:源应用程序(App1)调用 startActivity 方法,传递一个 Intent。该 Intent 包含要启动的目标应用程序(App2)的 Activity 的信息。

  2. 验证权限和 Intent:在 ActivityManagerService (AMS) 中,startActivity 方法会对 Intent 进行检查和验证。这包括验证调用者的权限,查找 Intent 对应的 Activity,处理各种启动模式等。

  3. 判断目标应用程序进程状态:接着,AMS 会判断目标应用程序 App2 的进程是否已经存在。如果已经存在,AMS 会使用已经存在的进程;如果不存在,AMS 会向 Zygote 发送请求,要求它创建一个新的进程。

  4. 创建新的应用程序进程:Zygote 在收到 AMS 的请求后,会创建一个新的应用程序进程,然后在这个进程中创建一个 Application 对象,并执行其 onCreate 方法。

  5. 创建 ActivityRecord:与此同时,AMS 会创建一个新的 ActivityRecord 对象,来代表要启动的 Activity。

  6. 调度启动 Activity:然后,AMS 会通过 Binder IPC 向新的应用程序进程发送一个 LAUNCH_ACTIVITY 消息。

  7. 接收 LAUNCH_ACTIVITY 消息:新的应用程序进程在接收到 LAUNCH_ACTIVITY 消息后,会创建目标 Activity 的实例,然后调用其 onCreate、onStart 和 onResume 方法。

ActivityManagerService 启动

**ActivityManagerService (AMS) **是 Android 中最为关键的系统服务之一,它负责管理系统中的进程,以及四大组件(Activity、Service、BroadcastReceiver 和 ContentProvider)的生命周期。这里将详细解释 AMS 的内部启动流程和工作流程:

AMS的启动流程:

实例化:AMS 是在 SystemServer 中被实例化的。SystemServer 会首先创建一个 ContextImpl 对象,然后利用这个 ContextImpl 创建 AMS。

服务初始化:接下来,调用 AMS 的 init 方法进行初始化,这个方法会创建和初始化一些需要的数据结构和服务,比如 BroadcastQueue、IntentFirewall 和 ActivityStackSupervisor 等。

准备完成:完成初始化后,调用 systemReady 方法来通知 AMS 系统准备就绪。在这个方法中,AMS 会完成一些后期初始化的工作,例如启动系统的 Home Activity。

AMS的工作流程:

AMS 主要的工作就是管理系统中的四大组件和进程。以下是它们分别的工作流程:

Activity的管理:AMS 使用 ActivityStackSupervisor 来管理系统中所有的 Activity。当应用程序调用 startActivity 方法时,会通过 Binder IPC 机制调用 AMS 中的 startActivity 方法。AMS 会根据 Intent 解析出需要启动的 Activity,创建一个 ActivityRecord 对象并添加到 ActivityStack 中。然后,AMS 会向应用程序发送 LAUNCH_ACTIVITY 消息,告诉应用程序启动新的 Activity。

Service的管理:当应用程序调用 startService 或 bindService 方法时,AMS 会创建一个 ServiceRecord 对象来保存 Service 的状态。然后,AMS 会向应用程序发送 CREATE_SERVICE 或 BIND_SERVICE 消息,告诉应用程序创建或绑定 Service。

BroadcastReceiver的管理:当应用程序调用 sendBroadcast 方法时,AMS 会创建一个 BroadcastRecord 对象,保存广播的信息。然后,AMS 会将 BroadcastRecord 添加到 BroadcastQueue 中,等待处理。

ContentProvider的管理:当应用程序调用 getContentResolver().query() 或其他方法时,AMS 会查找对应的 ContentProviderRecord,然后通过 Binder IPC 机制向目标 ContentProvider 发送请求。

进程的管理:AMS 使用 ProcessList 和 ProcessRecord 来管理系统中的进程。当需要创建新的进程时,AMS 会向 Zygote 发送请求,然后由 Zygote 创建新的进程。同时,AMS 也负责进程的调度和回收。

主要信息

startProcessLocked

在 Android 中,startProcessLocked() 方法主要是在 ActivityManagerService 中,用于启动新的应用进程。这个方法会被系统在需要启动新的应用进程时调用,例如,当用户启动一个新的应用或者服务需要在新的进程中运行时。以下是一些主要的步骤和操作:

检查是否已经存在相同的进程:首先,系统会检查是否已经存在一个相同名字的进程。如果已经存在,则不会再创建新的进程。

检查系统资源限制:系统会检查当前的系统资源,如内存使用情况等,来决定是否有足够的资源启动新的进程。

创建进程记录:如果可以启动新的进程,系统会创建一个新的 ProcessRecord 对象来保存新进程的信息。

启动新进程:使用 Zygote 启动新进程。Zygote 是 Android 中的一个特殊进程,它预加载了大量的系统资源和常用库,新的应用进程会通过 fork Zygote 进程的方式启动,这样可以提高进程启动的速度。

设置进程的参数:系统会设置新进程的各种参数,例如进程的优先级、所属用户等。

更新系统状态:系统会更新当前的系统状态,例如更新当前运行的进程列表等。

runOnce

**runOnce()**方法在Android的Zygote进程中非常关键,它是处理进程启动请求的主要逻辑。

在Android系统中,新的应用进程是通过fork Zygote进程来创建的。具体来说,当需要启动新的应用进程时,系统会通过一个特殊的socketZygote进程进行通信,向Zygote进程发送一个包含新进程需要的信息的请求,Zygote进程在接收到请求后,会执行**runOnce()**方法来处理这个请求。

以下是runOnce()方法的主要步骤:

读取请求参数runOnce()方法首先会从Zygote socket中读取请求参数,这些参数包括新进程的一些信息,例如应用的包名、启动类名等。

fork新进程:读取完请求参数后,runOnce()方法会调用forkAndSpecialize()forkSystemServer()方法来fork一个新的进程。这两个方法的主要区别在于,forkAndSpecialize()方法是用于创建普通的应用进程,而forkSystemServer()方法是用于创建System Server进程。

初始化新进程fork新进程后,**runOnce()**方法会对新进程进行一些初始化操作,例如设置新进程的环境变量、加载应用的dex文件等。

启动新进程的主类:初始化完成后,runOnce()方法会调用RuntimeInit.zygoteInit()方法来启动新进程的主类。对于普通的应用进程,主类通常是应用的Application类;对于System Server进程,主类是com.android.server.SystemServer类。

返回新进程的PID:最后,**runOnce()**方法会将新进程的PID返回给系统。这个PID是新进程的唯一标识,系统可以使用这个PID来管理新进程。

ActivityThread的main函数

ActivityThread 是 Android 中的一个非常重要的类,它是每个 Android 应用程序主线程的入口点,也就是应用程序的主线程(“main” thread)。在 ActivityThread 的 main 方法中,执行了一系列的初始化操作来启动和设置应用程序。

以下是 ActivityThread 的 main 方法主要做了哪些事情:

设置 Thread 属性:主线程的名称会被设置为** “main”**。

创建 Looper:在 Android 中,主线程需要一个 Looper 对象来处理消息队列。Looper.prepareMainLooper() 方法会创建一个绑定到主线程的 Looper 对象。

创建 ActivityThread 对象:创建 ActivityThread 实例并调用其 attach 方法,这个方法会完成一些重要的初始化工作,包括设置应用的上下文,创建应用的 Instrumentation 对象等。

设置 Android 默认的异常处理器:如果应用抛出未捕获的异常,这个处理器将会被调用。

开始循环:通过调用 Looper.loop() 来开始主线程的消息循环。

在应用进程启动后,需要向 ActivityManagerService (AMS) 报告是因为 AMS 是 Android 系统中管理所有应用程序生命周期的关键组件。当一个新的应用程序进程被创建时,它需要告诉 AMS 它已经启动并且准备好接收指令。此外,这也是一个错误检查机制:如果 AMS 启动了一个进程,但是这个进程在一段时间内没有报告回来,那么 AMS 会认为这个进程启动失败,会采取相应的操作,如重新启动这个进程或者报告一个错误。

启动binder机制

Binder 机制主要在应用程序启动时进行初始化,并在其进程生命周期内保持活动状态,用于处理进程间通信(IPC)的请求。关于 Binder 机制的启动,这主要发生在应用程序的主线程(ActivityThread)初始化过程中。

以下是 Binder 机制的启动过程:

创建应用的主线程:每个** Android** 应用都有一个主线程,它是应用程序的入口点。当新的应用程序进程创建时,Zygote会复制其内存空间,并在新的进程空间中启动应用的主线程。主线程的入口函数是 ActivityThread.main()

初始化 Looper:在 ActivityThread.main() 函数中,会调用 Looper.prepareMainLooper() 来为主线程创建一个 LooperLooper 是一个用于处理消息队列的工具,是实现事件驱动编程的关键组件。

创建 ActivityThread 对象:接下来,会创建一个 ActivityThread 对象,并调用其 attach() 方法来进行一些必要的初始化工作。在这个过程中,会创建应用的 ContextInstrumentation 对象等。

创建 Binder 线程池:在 ActivityThreadattach() 方法中,会调用 BinderInternal.addGcWatcher()BinderInternal.createBinderThreadPool() 来为当前进程创建 Binder 线程池。

addGcWatcher() 方法会添加一个 GC(垃圾回收)监听器,该监听器会在每次完成 Binder 事务后执行一次 GC,以防止 Binder 事务造成的内存泄漏。

createBinderThreadPool() 方法会创建一个 Binder 线程池。这个线程池会在后台运行,用于处理来自其他进程的 Binder 请求。

启动消息循环:最后,主线程的 Looper 对象会调用其 loop() 方法来启动消息循环。在这个消息循环中,主线程会不断地从消息队列中取出消息并处理,包括处理来自 Binder 线程池的消息。

Binder Native 层

打开 Binder 驱动:在 Android 系统启动的过程中,会加载 Binder 驱动。在每个进程创建的过程中,会打开 /dev/binder 设备,这样,该进程就可以使用 Binder 驱动进行 IPC 通信了。

映射内存:当进程打开 /dev/binder 设备后,会通过 mmap 系统调用映射一块内存空间作为进程和 Binder 驱动之间的通信区域。这样,进程和 Binder 驱动就可以通过这块共享内存进行数据交换,提高了通信效率。

创建 Binder 线程池:每个进程都需要创建一个 Binder 线程池来处理来自其他进程的 Binder 请求。Binder 线程池是一个由多个线程组成的线程池,每个线程都会使用 ioctl 系统调用进入到 Binder 驱动的等待队列,等待来自其他进程的 Binder 请求。

当一个进程通过 Binder 机制向另一个进程发送请求时,Binder 驱动会唤醒等待队列中的一个线程来处理这个请求。这个线程会读取共享内存中的数据,处理请求,并将结果写回到共享内存中。然后,这个线程会再次进入到 Binder 驱动的等待队列,等待下一次的请求。

冷启动 App 全流程

  1. 点击桌面图标后,Launcher 应用会构建一个 intent 并发送给 AMS,通知 AMS 启动 App;
  2. AMS 收到 intent 消息后,首先做一些校验,然后判断 App 对应的进程是否启动,如果没有启动,则通知 Zygote 进程启动 App;
  3. AMS 通过 socket 与 Zygote 进程通信,将必要的启动参数传递过去,Zygote 进程收到后,通过 fork 调用创建新的进程,并且在主进程中将子进程的 pid 返回给 AMS 所在的进程;
  4. fork 出来的进程也就是 App 进程,进程启动后首先会初始化 Binder 机制,具体为打开 Binder 驱动、通过 mmap 映射内存缓存,启动 binder 线程池;
  5. App 进程在 Binder 启动后会创建一个 ApplicationThread 的 Binder 实体,通过ServerManager 获取 AMS 的 Binder 代理,将 ApplicationThread 这个 Binder 传递给 AMS;
  6. AMS 收到 attach 后,保存 ApplicationThread 对象的 Binder 代理对象,以方便后续与 App 进程进行通信。AMS 发送 attachApplication 请求,该请求最后会在 App 所在进程的 Binder 线程被执行,然后构建一个 Message 对象发送给主线程执行 Application 对象的初始化;
  7. App 的主线程收到消息后,构建 LoadedApk 对象,该对象存储 App 的一些基本信息,紧接着创建 ContentImpl 对象,并且通过反射创建 Application 对象,接着调用其 attach 方法,传入 ContentImpl 对象,最后调用其 onCreate 方法;
  8. 再回到 AMS 刚刚通知 App 创建 Application 的位置,AMS 在执行完该事后,会立马通知 App 启动 launch类型的 Activity 以及一些 service、广播等
  9. App 在收到启动首页 Activity 事件后,通过反射创建 Activity 对象,并且同时创建一个 ContentImpl 对象,接着执行 Activity 的 onCreate 方法,设置布局文件;
  10. 接下来 onResume 方法中,通过 WMS 的 addView 方法,将 ViewRoot 中的视图添加到 WMS 中,并且视图树会执行 attachToWindow 回调;
  11. ViewRootImpl 会通过 Choreographer 注册 vsyn 信息,在下一个 vsyn 信号到来之后,会执行 msasure、layout、draw ,在 draw 方法执行完之后,其内部通过 canvas 的 api 调用绘制指令,这些指令会被记录下来,最后通过 RenderThread 线程进行计算执行,最终通过 GPU进行渲染;
  12. 渲染的数据会放到 Surface 缓冲区中,SufaceFlinger 将所有的窗口对象的 Surface 数据区域进行合成,并发送到屏幕的后缓冲区域;
  13. 下一个 vsync 信号到来之后,后缓冲区的图像就会显示到屏幕上;

相关文章:

Android Framework 之 启动流程

Android 系统的启动流程 Android 系统的启动流程可以分为以下几个主要步骤: 引导加载器(Bootloader)启动:当你打开一个 Android 设备时,首先启动的是引导加载器。引导加载器负责启动 Android 的核心操作系统。 Linux…...

Qt、C/C++环境中内嵌LUA脚本、实现LUA函数的调用执行

Qt、C/C环境中内嵌LUA脚本、实现LUA函数的调用执行 Chapter1. Qt、C/C环境中内嵌LUA脚本、实现LUA函数的调用执行1、LUA简介2、LUA脚本的解释器和编译器3、C环境中内嵌LUA执行LUA函数调用4、Qt内嵌LUA执行LUA函数调用5、运行结果6、内嵌LUA脚本在实际项目中的案例应用 Chapter1…...

超详细 | 模拟退火算法及其MATLAB实现

模拟退火算法(simulated annealing,SA)是20世纪80年代初期发展起来的一种求解大规模组合优化问题的随机性方法。它以优化问题的求解与物理系统退火过程的相似性为基础,利用Metropolis算法并适当地控制温度的下降过程实现模拟退火,从而达到求解…...

在线餐饮油烟实时监测系统的设计与实现

安科瑞 华楠 摘 要:为了解决传统油烟检测方法中成本高、效率低、实时性差等问题,设计开发了一种在线油烟实时监测系统;系统由采集、通讯、服务器和用户交互四个模块组成;采集模块采集油烟数据,通过GPRS通讯技术将数据发…...

7-2 凯撒密码 (20分)

7-2 凯撒密码 (20分) 为了防止信息被别人轻易窃取,需要把电码明文通过加密方式变换成为密文。输入一个以回车符为结束标志的字符串(少于80个字符),再输入一个整数offset,用凯撒密码将其加密后输出。恺撒密码是一种简单…...

LeetCode_贪心算法_中等_763.划分字母区间

目录 1.题目2.思路3.代码实现(Java) 1.题目 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍…...

【算法提高:动态规划】1.5 状态压缩DP TODO

文章目录 状态压缩DP例题列表棋盘式1064. 小国王⭐🐂(好题!)做题套路总结 327. 玉米田(好题!🐂 和1064. 小国王差不多的题目)292. 炮兵阵地(和上面两道题差不多&#xff…...

建网站一般使用Windows还是liunx好?

建网站一般使用Windows还是liunx好? 1;服务器配置比较低时,最好使用linux系统。 对于一个电脑新手,刚开始做网站时,都会选择入门级的服务器,我刚开始做网站时,就是这样的。我购买了一台入门级服…...

NodeJs后端项目使用docker打包部署

docker安装看之前的文章 默认已经安装好docker并且配置没有问题 拉取项目 https://gitee.com/coder-msc/docker-node 本地跑一个看看 pnpm install pnpm start 本地访问 http://localhost:1301/getname?name%E5%93%88%E5%88%A9%E6%B3%A2%E7%89%B9项目整个上传服务器 查看…...

ARM单片机中断处理过程解析

前言 中断,在单片机开发中再常见不过了。当然对于中断的原理和执行流程都了然于胸,那么对于ARM单片机中断的具体处理行为,你真的搞清楚了吗? 今天来简单聊一聊,ARM单片机中断处理过程中的具体行为是什么样的&#xf…...

关于SEDEX会员与平台的相关问题汇总

【关于SEDEX会员与平台的相关问题汇总】 01.会员资格有效期是多久? Sedex会员资格有效期为12个月,您也可以选择更长期的会员资格。您支付会员年费时,在“订阅信息”框下的“延长订阅期限”中输入年数,即可获得更长的会员资格时效。…...

解读Spring-context的property-placeholder

在spring中&#xff0c;如果要给程序定义一些参数&#xff0c;可以放在application.properties中&#xff0c;通过<context:property-placeholder>加载这个属性文件&#xff0c;然后就可以通过value给我们的变量自动赋值&#xff0c;如果你们的程序可能运行在多个环境中&…...

【Rust】枚举类型创建单链表以及常见的链表操作方法

目录 单链表 用枚举表达链表 枚举enum Box容器 创建节点 1. 创建并打印 2. match 匹配 3. 节点初始化 4.节点嵌套 追加节点 1. 尾插法 2. 链表追加方法 3. 头插法 4. 改写成单链表方法 遍历链表 1. 递归法 2. 递推法 3. 改写成单链表方法 自定义Display tr…...

Excel 两列数据中相同的数据进行同行显示

一、要求 假设您有两个列&#xff0c;分别是A列和B列&#xff0c;需要在C列中找出A列对应的B列的值。 二、方案 方法1&#xff1a;寻常思路 凸显重复项对A列单独进行筛选–按颜色进行排序&#xff0c;然后升序对B列重复上述操作即可 方法2&#xff1a;两个公式 VLOOKUP 纵向查找…...

Windows本地安装配置Qcadoo MES系统

简介 Qcadoo MES是一款功能强大且灵活的开源MES&#xff08;制造执行系统&#xff09;&#xff0c;旨在为制造业务提供全面的管理和监控解决方案。本篇博客将教您如何在Windows操作系统上安装和配置Qcadoo MES系统&#xff0c;以便您能够轻松管理和监控制造过程。 环境要求 …...

涛思数据与拾贝云达成战略合作,携手赋能工业数字化转型

2023 年 7 月 27 日&#xff0c;北京涛思数据科技有限公司&#xff08;以下简称“涛思数据”&#xff09;与广州拾贝云科技有限公司&#xff08;以下简称“拾贝云”&#xff09;于广州签署战略合作协议。双方围绕电力行业的需求与痛点展开积极讨论&#xff0c;就如何量身打造最…...

nginx 配置多域名多站点 Ubuntu

nginx 配置多域名多站点 Ubuntu 一、安装 nginx apt install nginx二、配置文件说明 nginx 的配置文件在 /etc/nginx 目录下&#xff0c;它的默认内容是这样的 root2bd0:/etc/nginx# ll total 72 drwxr-xr-x 8 root root 4096 Jul 31 15:21 ./ drwxr-xr-x 104 root root …...

Docker实践:使用Docker搭建个人开发环境(极简版)

文章目录 说明教程1. 编写 Dockerfile2. 编写 docker-compose.yml3. 使用容器创建容器启动容器进入容器命令行VSCode 4. 关闭容器5. 备份容器导出导入 6. 重置容器 相关资料文章合集详细了解本文在个人电脑上安装 Docker容器使用 NVIDIA 显卡托管镜像运行GUI程序 说明 本文是在…...

SQL从三个表中根据时间分别查询并汇总数量一行展示

需求&#xff1a;如果您要从三个表中根据时间分别查询并汇总数量&#xff0c;然后将结果以时间和数量一行展示&#xff0c;可以使用子查询和条件聚合。 入库主表 入库明细表 出库主表 出库明细表 退货主表 退货明细表 SQL代码 SELECT time,sum(a.inQty) as inQty,sum(a.outQty…...

同样是跨端框架,React会不会被VUE取代?

看到知乎上有比较多的类似问题&#xff0c;正好这两个框架在以往的一些项目中都有实践过&#xff0c;就借着本篇文章说说我个人的看法。 先摆个结论&#xff1a;不会&#xff0c;毕竟各有千秋&#xff0c;除非跨端框架有被更好的概念所替代&#xff0c;又或者App已经彻底过气了…...

Excel·VBA定量装箱、凑数值金额、组合求和问题

如图&#xff1a;对图中A-C列数据&#xff0c;根据C列数量按照一定的取值范围&#xff0c;组成一个分组装箱&#xff0c;要求如下&#xff1a; 1&#xff0c;每箱数量最好凑足50&#xff0c;否则为47-56之间&#xff1b; 2&#xff0c;图中每行数据不得拆分&#xff1b; 3&…...

通过Jmeter压测存储过程

目录 一、存储过程准备&#xff1a; 二、测试工具准备&#xff1a; 三、工具配置及执行&#xff1a; 1、配置JDBC Connection Configuration&#xff1a; 2、配置吞吐量控制器&#xff08;可跳过&#xff09;&#xff1a; 3、配置JDBC Request&#xff1a; 对于存储过程…...

Spring笔记之Spring对IoC的实现

文章目录 IoC控制反转依赖注入set注入注入外部Bean注入内部Bean注入简单类型通过注入方式实现javax.sql.DateSource接口测试简单类型 级联属性赋值&#xff08;了解&#xff09;注入数组注入List集合注入Set集合注入Map集合注入Properties注入null和空字符串不给属性赋值使用 注…...

【eNSP】Telnet远程登录

Telnet远程登录 eNSP软件TelnetTelnet远程登录-路由连接关闭防火墙eNSP根据图1画图路线配置路由端口IP配置路由R1改名配置接口IP 配置路由R2 配置R2的远程登录设置登录用户授权级别退出登录超时时间 Telnet测试 eNSP软件 eNSP(Enterprise Network Simulation Platform)是一款由…...

SOP/详解*和**/python数据结构(iter,list,tuple,dict)/ 解包

一、错误解决合集 1. > combined_seq.named_children() 2. isinstance 2th parameter : must be a type or tuple of types > 改为tuple&#xff0c;不要用列表。改为 LLLayer (nn.Conv2d,nn.Linear) 3. File “test.py”, line 90, in calculate_fin_fout print(“hi”…...

使用webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

1、前言 在我们使用 Selenium 进行 UI 自动化测试时&#xff0c;常常会因为浏览器驱动与浏览器版本不匹配&#xff0c;而导致自动化测试无法执行&#xff0c;需要手动去下载对应的驱动版本&#xff0c;并替换原有的驱动&#xff0c;可能还会遇到跨操作系统进行测试的时候&…...

【vue】Vue中debugger报错 unexpected ‘debugger’ statement no-debugger

前言&#xff1a; Vue中debugger报错 unexpected ‘debugger’ statement no-debugger &#xff08;意外的“调试器”语句没有调试器&#xff09; eslink规则没有开启’debugger’ &#xff0c;被规则屏蔽了&#xff0c;需要手动放开 解决方法 方式一&#xff1a; 找到.esl…...

课题方向a

首先在无线感知的研究方向下,辅以深度学习和计算机视觉的技术和知识,可以从事哪些具体课题的研究?请你尽可能多的给出课题名称供我选择 在无线感知的研究方向下,辅以深度学习和计算机视觉的技术,有很多具体课题可以进行研究。以下是一些供您选择的课题名称: 基于深度学习…...

【Matter】基于Ubuntu 22.04 交叉编译chip-tool

编译工程之际&#xff0c;记录一下编译过程&#xff0c;免得后续遗忘&#xff0c;总结下来chip-tool 交叉编译涉及到的知识点&#xff1a; 需要了解如何支持交叉编译&#xff0c;基于GN编译框架需要理解应用库如何交叉编译&#xff0c;理解pkg-config的使用meson 编译&#xf…...

Qt/C++音视频开发50-不同ffmpeg版本之间的差异处理

一、前言 ffmpeg的版本众多&#xff0c;从2010年开始计算的项目的话&#xff0c;基本上还在使用的有ffmpeg2/3/4/5/6&#xff0c;最近几年版本彪的比较厉害&#xff0c;直接4/5/6&#xff0c;大版本之间接口有一些变化&#xff0c;特别是一些废弃接口被彻底删除了&#xff0c;…...