Android Framework 之了解系统启动流程二

Android Framework 源码阅读系列篇章有:

  1. 系统启动流程一之init进程和zygote进程启动分析
  2. 系统启动流程二之SystemServer进程启动分析

1. SystemServer 进程启动分析

在 系统启动流程一之init进程和zygote进程启动分析 中分析 zygote 进程时,我们知道了 zygote 调用 forkSystemServer() 方法 fork 了 SystemServer 进程。

看一下 forkSystemServer() 方法:

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {... // 请求 fork SystemServer 进程pid = Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}/* For child process */// pid 为0,表示子线程,即 SystemServer 进程创建成功。if (pid == 0) { if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}zygoteServer.closeServerSocket();return handleSystemServerProcess(parsedArgs);}return null;}
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {// set umask to 0077 so new files and directories will default to owner-only permissions.Os.umask(S_IRWXG | S_IRWXO);if (parsedArgs.mNiceName != null) {Process.setArgV0(parsedArgs.mNiceName);}final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");if (systemServerClasspath != null) {// 对 SystemServer 的类路径进行 dex 优化,提升性能performSystemServerDexOpt(systemServerClasspath);// Capturing profiles is only supported for debug or eng builds since selinux normally// prevents it.if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {try {Log.d(TAG, "Preparing system server profile");prepareSystemServerProfile(systemServerClasspath);} catch (Exception e) {Log.wtf(TAG, "Failed to set up system server profile", e);}}}if (parsedArgs.mInvokeWith != null) {String[] args = parsedArgs.mRemainingArgs;// If we have a non-null system server class path, we'll have to duplicate the// existing arguments and append the classpath to it. ART will handle the classpath// correctly when we exec a new process.if (systemServerClasspath != null) {String[] amendedArgs = new String[args.length + 2];amendedArgs[0] = "-cp";amendedArgs[1] = systemServerClasspath;System.arraycopy(args, 0, amendedArgs, 2, args.length);args = amendedArgs;}// 使用 WrapperInit.execApplication 启动新的进程WrapperInit.execApplication(parsedArgs.mInvokeWith,parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");} else {ClassLoader cl = null;if (systemServerClasspath != null) {// 创建类加载器,加载 SystemServer 的类路径cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);// 设置当前线程的上下文类加载器Thread.currentThread().setContextClassLoader(cl);}//将剩余的参数传递给 SystemServer,并调用 ZygoteInit.zygoteInit 初始化 SystemServerreturn ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, cl);}/* should never reach here */}
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.javapublic static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {if (RuntimeInit.DEBUG) {Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");// 重定向日志流,确保日志输出到正确的位置RuntimeInit.redirectLogStreams();// 初始化运行环境,包括设置默认的未捕获异常处理器、时区等RuntimeInit.commonInit(); // 调用 native 方法,启动 Binder 线程池,使进程能够支持 Binder 通信// 该方法在 AndroidRuntime.cpp 中实现ZygoteInit.nativeZygoteInit();// 通过反射创建应用程序的入口方法(main 方法)的 Method 对象,// 并返回一个 Runnable 对象,用于启动应用程序return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,classLoader);}
// frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,String[] argv, ClassLoader classLoader) {nativeSetExitWithoutCleanup(true);VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);// 解析传入的参数,封装到 Arguments 对象中final Arguments args = new Arguments(argv);// The end of of the RuntimeInit event (see #zygoteInit).Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);// 将剩余的参数传递给启动类的静态 main 方法// args.startClass: 如果 AMS 通过 socket 传递过来的是 ActivityThreadreturn findStaticMain(args.startClass, args.startArgs, classLoader);}protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {Class<?> cl;try {// 通过类加载器加载指定的类cl = Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {throw new RuntimeException("Missing class when invoking static main " + className,ex);}Method m;try {// 通过反射获取类的 main 方法m = cl.getMethod("main", new Class[] { String[].class });} catch (NoSuchMethodException ex) {throw new RuntimeException("Missing static main on " + className, ex);} catch (SecurityException ex) {throw new RuntimeException("Problem getting static main on " + className, ex);}int modifiers = m.getModifiers();if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {throw new RuntimeException("Main method is not public and static on " + className);}/** 返回一个 MethodAndArgsCaller 对象,该对象封装了 main 方法和参数* 这个 throw 会被 ZygoteInit.main() 捕获,并调用其 run() 方法* 这种设计可以清除所有在设置进程时所需的堆栈帧*/return new MethodAndArgsCaller(m, argv);}
// 实现 Runnable 接口的 run 方法,执行对应类的 main 方法(例如 SystemServer 或 ActivityThread)
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;}// 通过反射调用静态的 main 方法public void run() {try {mMethod.invoke(null, new Object[] { mArgs });} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InvocationTargetException ex) {Throwable cause = ex.getCause();if (cause instanceof RuntimeException) {throw (RuntimeException) cause;} else if (cause instanceof Error) {throw (Error) cause;}throw new RuntimeException(ex);}}}

forkSystemServer() -> handleSystemServerProcess -> ZygoteInit.zygoteInit -> RuntimeInit.applicationInit -> findStaticMain

这个链路方法调用所做的事情是:

  1. SystemServer 进程创建:在 forkSystemServer() 方法中fork 了 SystemServer 进程;
  2. SystemServer 进程初始化:在 forkSystemServer() 中执行 handleSystemServerProcess(),然后又调用 ZygoteInit.zygoteInit() 函数:
    (1)初始化运行环境,像日志、网络等;
    (2)nativeZygoteInit() 方法启动 binder 线程池;
    (3)反射拿到 SystemServer 的 main() 函数;
  3. SystemServer 进程运行:执行 runnable() 从而执行 SystemServer 的 main 函数;

2. SystemServer 进程运行基本流程分析

接下来看 SystemServer 的 main 函数:

// frameworks/base/services/java/com/android/server/SystemServer.javapublic static void main(String[] args) {new SystemServer().run();}

很简单,就执行了 run() 函数。

private void run() {// 创建一个计时和日志跟踪对象,用于记录系统启动的性能数据TimingsTraceAndSlog t = new TimingsTraceAndSlog();try {// 开始跟踪 "InitBeforeStartServices" 阶段t.traceBegin("InitBeforeStartServices");// 记录系统启动的进程信息到系统属性中SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount));SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime));SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime));// 记录系统启动事件到 EventLog 中EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START,mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime);// 如果时区未设置,默认设置为 GMTString timezoneProperty = SystemProperties.get("persist.sys.timezone");if (timezoneProperty == null || timezoneProperty.isEmpty()) {Slog.w(TAG, "Timezone not set; setting to GMT.");SystemProperties.set("persist.sys.timezone", "GMT");}// 如果系统设置了 "persist.sys.language" 等属性,将其替换为 "persist.sys.locale"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", "");}// 设置 Binder 调用在阻塞时发出警告Binder.setWarnOnBlocking(true);// 强制系统服务器加载安全的标签PackageItemInfo.forceSafeLabels();// 设置 SQLite 的默认同步模式为 FULLSQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;// 在设置提供程序初始化之前,停用 SQLiteCompatibilityWalFlagsSQLiteCompatibilityWalFlags.init(null);// 记录系统服务器启动日志Slog.i(TAG, "Entered the Android system server!");final long uptimeMillis = SystemClock.elapsedRealtime();EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);if (!mRuntimeRestart) {FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START,uptimeMillis);}// 设置系统属性以同步当前运行时SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());// 清除虚拟机的内存增长限制VMRuntime.getRuntime().clearGrowthLimit();// 确保设备指纹属性已定义Build.ensureFingerprintProperty();// 在系统服务器中,访问环境路径时必须显式指定用户Environment.setUserRequired(true);// 在系统服务器中,任何传入的 Bundle 都应被拆解以避免抛出 BadParcelableExceptionBaseBundle.setShouldDefuse(true);// 在系统服务器中,序列化异常时包含堆栈跟踪Parcel.setStackTraceParceling(true);// 确保系统服务器中的 Binder 调用始终以前台优先级运行BinderInternal.disableBackgroundScheduling(true);// 增加系统服务器中的 Binder 线程数BinderInternal.setMaxThreads(sMaxBinderThreads);// 准备主线程(当前线程)android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND);android.os.Process.setCanSelfBackground(false);Looper.prepareMainLooper();Looper.getMainLooper().setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);// 启用服务未找到时的 WTF 日志SystemServiceRegistry.sEnableServiceNotFoundWtf = true;// 代码1 初始化本地服务System.loadLibrary("android_servers");// 允许堆和性能分析initZygoteChildHeapProfiling();// 如果是调试版本,启动线程以监控文件描述符泄漏if (Build.IS_DEBUGGABLE) {spawnFdLeakCheckThread();}// 检查上次是否未能正常关闭,此调用可能不会返回performPendingShutdown();// 代码2 初始化系统上下文createSystemContext();// 调用主模块的初始化ActivityThread.initializeMainlineModules();// 代码3 创建系统服务管理器mSystemServiceManager = new SystemServiceManager(mSystemContext);mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime);LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);// 准备用于并行化初始化任务的线程池SystemServerInitThreadPool.start();// 如果是调试版本且设置了系统属性,附加 JVMTI 代理if (Build.IS_DEBUGGABLE) {String jvmtiAgent = SystemProperties.get("persist.sys.dalvik.jvmtiagent");if (!jvmtiAgent.isEmpty()) {int equalIndex = jvmtiAgent.indexOf('=');String libraryPath = jvmtiAgent.substring(0, equalIndex);String parameterList = jvmtiAgent.substring(equalIndex + 1, jvmtiAgent.length());try {Debug.attachJvmtiAgent(libraryPath, parameterList, null);} catch (Exception e) {Slog.e("System", "*************************************************");Slog.e("System", "********** Failed to load jvmti plugin: " + jvmtiAgent);}}}} finally {// 结束 "InitBeforeStartServices" 阶段的跟踪t.traceEnd();}// 设置默认的 WTF 处理器RuntimeInit.setDefaultApplicationWtfHandler(SystemServer::handleEarlySystemWtf);// 启动服务try {t.traceBegin("StartServices");startBootstrapServices(t);  // 代码4 启动引导服务startCoreServices(t);       // 代码5 启动核心服务startOtherServices(t);      // 代码6 启动其他服务} catch (Throwable ex) {Slog.e("System", "******************************************");Slog.e("System", "************ Failure starting system services", ex);throw ex;} finally {t.traceEnd(); // 结束 "StartServices" 阶段的跟踪}// 初始化虚拟机的 StrictMode 默认设置StrictMode.initVmDefaults(null);// 如果不是重启且不是首次启动或升级,记录系统服务器启动完成的时间if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {final long uptimeMillis = SystemClock.elapsedRealtime();FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_READY,uptimeMillis);final long maxUptimeMillis = 60 * 1000;if (uptimeMillis > maxUptimeMillis) {Slog.wtf(SYSTEM_SERVER_TIMING_TAG,"SystemServer init took too long. uptimeMillis=" + uptimeMillis);}}// 检查运行时是否运行在 boot image 中if (!VMRuntime.hasBootImageSpaces()) {Slog.wtf(TAG, "Runtime is not running with a boot image!");}// 代码7 进入主线程的消息循环Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");
}

run() 方法做的事情:

  1. System.loadLibrary(“android_servers”); 加载动态库 libandroid_server.so
  2. createSystemContext(); 创建系统上下文;
  3. new SystemServiceManager() 创建 SystemServiceManager;
    startService() :
    (1)反射创建服务,需要一参的构造方法;
    (2)执行服务的 onStart() 方法;
    (3)返回该服务对象;
  4. startBootstrapServices(t); 启动系统引导服务
    (1)ATM 启动
    (2)AMS 启动
    (3)AMS.setSystemProcess() 将 AMS 等服务添加到 ServiceManager 中
    (4)PMS 启动
    (5)PKMS 启动
  5. startCoreServices(t); 启动核心服务
    (1)电池服务
  6. startOtherServices(t); 启动其他服务
    (1)WMS 服务
    (2)AMS.systemReady() 启动桌面
  7. Looper.loop 一直循环

3. 系统服务介绍

在 SystemServer 的 run() 方法中可以看到官方把系统服务氛围了三种类型:引导服务、核心服务和其他服务。

系统服务大约有90多个:

  • 引导服务 Boot Service(10个):
    在这里插入图片描述
  • 核心服务 Core Service(9个):
    在这里插入图片描述
  • 其他服务 Other Service (70个+):
    在这里插入图片描述

4. SystemServer 如何管理服务

因为 SystemServer 是系统服务进程,用于管理服务。SystemServiceManager 是管理 Service,所以服务都必须封装 SystemService 这个类。

以启动引导服务为例:

 private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {...// Activity manager runs the show.t.traceBegin("StartActivityManager");// 启动 Activity 管理器服务(ActivityTaskManagerService 和 ActivityManagerService)ActivityTaskManagerService atm = mSystemServiceManager.startService(ActivityTaskManagerService.Lifecycle.class).getService(); // 启动 ATMSmActivityManagerService = ActivityManagerService.Lifecycle.startService(mSystemServiceManager, atm); // 启动 AMSmActivityManagerService.setSystemServiceManager(mSystemServiceManager);mActivityManagerService.setInstaller(installer);mWindowManagerGlobalLock = atm.getGlobalLock();t.traceEnd();...}

在 startBootstrapServices() 方法中以 AMS 为例,是通过 SystemServiceManager.startService() 来启动的。
接着看一下 SystemServiceManager:

// frameworks/base/services/core/java/com/android/server/SystemServiceManager.javaprivate final ArrayList<SystemService> mServices = new ArrayList<SystemService>();public void startService(@NonNull final SystemService service) {// Register it.// 将 SystemService 添加到 list 中mServices.add(service);// Start it.long time = SystemClock.elapsedRealtime();try {// 启动 SystemServiceservice.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);}warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");}

在 SystemServiceManager 的 startService() 中,首先将服务添加到集合中,然后启动服务。

总结

SystemServer 在启动时主要做了:

  1. 启动 bInder 线程池,这样就可以与其他进程进行通信;
  2. 创建 SystemServiceManager 用于对系统的服务进程创建、启动和生命周期管理;
  3. 启动各种系统服务;

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云企业邮箱出现故障怎么处理?

阿里云企业邮箱出现故障怎么处理&#xff1f; 以下是处理阿里云企业邮箱故障的详细分步指南&#xff0c;帮助您快速定位问题并恢复邮箱正常使用&#xff1a; 一、初步排查&#xff1a;确认故障范围与现象 确定影响范围 全体用户无法使用 → 可能为阿里云服务端故障或网络中断。…

Python----数据分析(Pandas二:一维数组Series,Series的创建,Series的属性,Series中元素的索引与访问)

一、一维数组Series Series&#xff1a;一维数组,与Numpy中的一维array类似。它是一种类似于一维数组的对象&#xff0c;是由一组数据(各种 NumPy 数据类型)以及一组与之相关的数据标签(即索引)组成。 仅由一组数据也可产生简单的 Series 对象&#xff0c;用值列表生成 Series …

小程序配置

注册小程序账号和安装开发工具 参考文档&#xff1a;注册小程序账号和安装开发工具https://blog.csdn.net/aystl_gss/article/details/127878658 HBuilder新建项目 填写项目名称&#xff0c;选择UNI-APP&#xff0c;修改路径&#xff0c;点击创建 manifest.json 配置 需要分别…

前端UI编程基础知识:基础三要素(结构→表现→行为)

以下是重新梳理的前端UI编程基础知识体系&#xff0c;结合最新技术趋势与实战要点&#xff0c;以更适合快速掌握的逻辑结构呈现&#xff1a; 一、基础三要素&#xff08;结构→表现→行为&#xff09; 1. HTML5 核心能力 • 语义化标签&#xff1a;<header>, <nav&g…

【eNSP实战】将路由器配置为DHCP服务器

拓图 要求&#xff1a; 为 office100 和 office200 分别配置地址池 AR1接口配置 interface GigabitEthernet0/0/0ip address 192.168.100.1 255.255.255.0 # interface GigabitEthernet0/0/1ip address 192.168.200.1 255.255.255.0 AR1路由器上创建office100地址池 [AR1…

Stable Diffusion 模型具体如何设置参数?

基础参数设置 随机种子&#xff08;seed&#xff09;&#xff1a;设置一个固定的随机种子值&#xff0c;可以确保在相同文本提示下生成相同的图像。如果设置为-1&#xff0c;则每次生成的图像都是随机的。 num_inference_steps&#xff1a;控制模型推理的步数。步数越多&#…

阿里云服务器购买及环境搭建宝塔部署springboot和vue项目

云服务器ECS_云主机_服务器托管_计算-阿里云 一、前言 对于新手或者学生党来说&#xff0c;有时候就想租一个云服务器来玩玩或者练练手&#xff0c;duck不必花那么多钱去租个服务器。这些云服务厂商对学生和新手还是相当友好的。下面将教你如何快速搭建自己的阿里云服务器&…

ABAP语言的动态编程(4) - 综合案例:管理费用明细表

本篇来实现一个综合案例&#xff1a;管理费用明细表。报表在实际项目中&#xff0c;也有一定的参考意义&#xff0c;一方面展示类似的报表&#xff0c;比如管理费用、研发费用等费用的明细&#xff0c;使用业务比较习惯的展示格式&#xff1b;另一方面正好综合运用前面学习的动…

【Python办公】Excel通用匹配工具(双表互匹)

目录 专栏导读1、背景介绍2、库的安装3、核心代码4、完整代码总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——>Python办公自动化专…

2025-03-15 吴恩达机器学习2——线性回归模型

文章目录 1 概述1.1 案例1.2 分析 2 代价函数2.1 代价函数公式2.2 理解代价函数2.3 可视化代价函数 3 梯度下降3.1 实现步骤3.2 理解梯度下降3.3 学习率 4 最佳实践4.1 导入数据4.2 代码实现4.3 可视化 1 概述 ​ 线性回归模型是使用最广泛的学习算法&#xff0c;让我们从一个…

Webpack 前端性能优化全攻略

文章目录 1. 性能优化全景图1.1 优化维度概览1.2 优化效果指标 2. 构建速度优化2.1 缓存策略2.2 并行处理2.3 减少构建范围 3. 输出质量优化3.1 代码分割3.2 Tree Shaking3.3 压缩优化 4. 运行时性能优化4.1 懒加载4.2 预加载4.3 资源优化 5. 高级优化策略5.1 持久化缓存5.2 模…

实验篇| CentOS 7 下 Keepalived + Nginx 实现双机高可用

为什么要做双机高可用&#xff1f;‌ 想象一下&#xff1a;你的网站突然宕机&#xff0c;用户无法访问&#xff0c;订单流失、口碑暴跌…&#x1f4b8; ‌双机热备‌就是解决这个痛点的终极方案&#xff01;两台服务器互为备份&#xff0c;724小时无缝切换&#xff0c;保障业务…

C语言【内存函数】详解加模拟实现

目录&#xff1a; 1. memcpy使用和模拟实现 2. memmove使用和模拟实现 3. memset函数的使用 4. memcmp函数的使用 以上函数均包含在一个头文件<string.h>里面 一、memcpy的使用和模拟实现。 memcpy函数介绍&#xff1a; 函数原型&#xff1a; void * memcpy ( void…

Flutter——Android与Flutter混合开发详细教程

目录 1.创建FlutterModule项目&#xff0c;相当于Android项目里面的module库&#xff1b;2.或者编辑aar引用3.创建Android原生项目3.直接运行跑起来 1.创建FlutterModule项目&#xff0c;相当于Android项目里面的module库&#xff1b; 2.或者编辑aar引用 执行 flutter build a…

Windows根据文件名批量在文件夹里查找文件并复制出来,用WPF实现的详细步骤

项目前言 在日常工作和生活中&#xff0c;我们常常会遇到需要从大量文件中根据文件名批量查找特定文件并复制到指定位置的情况。手动一个个查找和复制文件不仅效率低下&#xff0c;还容易出错。使用 Windows Presentation Foundation (WPF) 可以创建一个用户友好的图形界面应用…

matlab 控制系统GUI设计-PID控制超前滞后控制

1、内容简介 matlab164-控制系统GUI设计-PID控制超前滞后控制 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

【大模型基础_毛玉仁】2.4 基于 Encoder-Decoder 架构的大语言模型

更多内容&#xff1a;XiaoJ的知识星球 目录 2.4 基于 Encoder-Decoder 架构的大语言模型2.4.1 Encoder-Decoder 架构2.4.2 T5 语言模型1&#xff09;T5 模型结构2&#xff09;T5 预训练方式3&#xff09;T5 下游任务 2.4.3 BART 语言模型1&#xff09;BART 模型结构2&#xff0…

AI智能代码疫苗技术,赋能数字化应用内生安全自免疫

“DevSecOps市占率持续领先&#xff0c;IAST探针覆盖率十倍增长&#xff0c;代码疫苗技术已成功帮助上千家行业用户成功抵御‘Log4j2.x’等重大未知漏洞的利用攻击。”子芽在腾讯专访中透露。 这是2021年悬镜安全交出的一张成绩单。悬镜安全是DevSecOps敏捷安全先行者&#xf…

【初级篇】如何使用DeepSeek和Dify构建高效的企业级智能客服系统

在当今数字化时代,企业面临着日益增长的客户服务需求。使用Dify创建智能客服不仅能够提升客户体验,还能显著提高企业的运营效率。关于DIfy的安装部署,大家可以参考之前的文章: 【入门级篇】Dify安装+DeepSeek模型配置保姆级教程_mindie dify deepseek-CSDN博客 AI智能客服…

【机器学习-基础知识】统计和贝叶斯推断

1. 概率论基本概念回顾 1. 概率分布 定义: 概率分布(Probability Distribution)指的是随机变量所有可能取值及其对应概率的集合。它描述了一个随机变量可能取的所有值以及每个值被取到的概率。 对于离散型随机变量,使用概率质量函数来描述。对于连续型随机变量,使用概率…