MTK系统启动流程

news2024/11/25 10:14:35

MTK系统启动流程

boot rom -> preloader ->lk ->kernel ->Native -> Android

1、Boot rom:系统开机,最先执行的是固化在芯片内部的bootrom,其作用主要有
a.初始化ISRAM和EMMC
b.当系统全擦后 ,也会配置USB,用来仿真USB端口下载镜像。
c.从EMMC中加载preloader到ISRAM中执行。

2、Preloader:主要完成平台基础设备的初始化,如DDR等硬件,下载握手连接,加载lk到DDR中,跳转到lk

3、Lk:打开MMU,加速lk执行,显示log、充电相关,从emmc中boot分区取出boot.img进行解压,将根文件系统,linux kernel加载到Dram,完成kernel前的准备工作并拉起kernel(start_kernel)。

4Kernel:初始化调度、内存管理、io、中断等linux操作系统基本功能、识别OTBO,创建init进程,完成模块的初始化,执行init主程序。

5Native:启动系统关键进程init、void、surfaceflinger等

init 进程的作用大致分为3部分:

1、创建备结点,挂载跟文件系统,

2、开启selinux安全策略,初始化资源文件,启动属性服务等;

3、解析initrc 文件;

6、Android:init fork zygote进程,再由zygote去创建所有安卓的应用进程

基本流程图如下:

属性查看是否第一次开机

persist.sys.device_provisioned开机向导是否完成

persist.sys.device_first_boot是否第一次开机

一、preloader(汇编/C)

1.1 作用

1、完成平台基础设备的初始,如DDR等硬件

2、与flashtoolUSB握手,download 相关检测 & sec boot检测;

3、将lk加载到DRAM

4、跳转到Ik

1.2 入口代码

/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mtXXXX/src/init/init.s

init.s:初始化寄存器、清空bss段、初始化stack、设置CPSR、切换到SVC模式、禁止中断;完成以上基本初始化后jump to main

  setup_stk :
      /* setup stack */
      LDR r0, stack
      LDR r1, stacksz
  
      /* buffer overflow detect pattern */
      LDR r2, =0xDEADBEFF
      STR r2, [r0]
  
      LDR r1, [r1]
      SUB r1, r1, #0x04
      ADD r1, r0, r1
  
      MOV sp, r1
  
  entry :
      LDR r0, =bldr_args_addr
      B   main
  
  .globl jump

/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mtXXXX/src/core/main.c

static void bldr_pre_process(void)
{
    int isLocked = 0;
    int tempnoboot = 0;
    uint32_t ret = 0;
	......
	//初始化timer/pll/gpio/uart/WDT/storage/PMIC
    platform_pre_init();

    pal_log_info("\n%s Build Time: %s\n", MOD, BUILD_TIME);

	......

    /* hardware initialization */
	//初始化RTC/PM/batter/DDR/storage
    platform_init();
    tempnoboot = oplus_bq28z610_temp();
    no_boot_log_to_storage(tempnoboot);
	......
}
 void main(u32 *arg)
 {
     struct bldr_command_handler handler;
     u32 jump_addr, jump_arg;
......
	 //初始化平台环境
     bldr_pre_process();
 
.......
 
     BOOTING_TIME_PROFILING_LOG("before bldr_handshake");
	 //与下载工具握手连接
     bldr_handshake(&handler);
     BOOTING_TIME_PROFILING_LOG("bldr_handshake");
 
	 //初始化安全环境
     trustzone_pre_init();
     BOOTING_TIME_PROFILING_LOG("trustzone pre init");
 #endif
 
 #if !(CFG_BYPASS_LOAD_IMG_FORCE_ATF)
     /* Do not load ATF, lk, load by JTAG */
	 //加载LK镜像到DRAM
     if (0 != bldr_load_images(&jump_addr)) {
         pal_log_err("%s Second Bootloader Load Failed\n", MOD);
 #if !CFG_BYPASS_EMI
         goto error;
 #endif //SLT
	 //完成preloader剩余的初始化,主要对电池的初始化
     bldr_post_process();
	.......
	 //跳转到lk
     bldr_jump64(jump_addr, jump_arg, sizeof(boot_arg_t));
	.......
 }

bldr_pre_process 初始化平台环境

platform_pre_init:初始化timer/pll/gpio/uart/WDT/storage/PMIC

platform_init:初始化RTC/PM/batter/DDR/storage

bldr_handshake 与下载工具握手连接

trustzone_pre_init 安全环境初始化

bldr_load_images 加载LK镜像到DRAM

bldr_post_process 完成preloader剩余的初始化,主要对电池的初始化

bldr_jump64跳转到lk

二、LK(汇编/C)

2.1 作用

1、打开MMU,使能I/D-cache,加速lk执行,显示logo、充电相关

·2、从emmc中boot分区取出bootimg解压,将根文件系统(ramdisk)、linux kernel load到DRAM:

3、解析dtb,写入到DRAM指定区域:

4、关闭MMU、irg /fg,关闭ID-cache,拉起 kernel(startkemel);

2.2 入口代码:

/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/lk/arch/arm/crt0.S

crt0.s:添加TZ symbol,执行abort stack等初始化操作。跳转到kmain

2.3 kmain

/MTXXXX_13_Master/vnd/vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c

void kmain(void)
{
	//初始化工作队列、线程表、创建bootstrap线程开始后面初始化
	thread_init_early();

	// 初始化MMU、cache
	arch_early_init();

	//平台初始化。如timmer、gpio、pmic等,建立lk基本运行环境
	platform_early_init();
.......
 
 #if (!ENABLE_NANDWRITE)
 	// create a thread to complete system initialization
 	dprintf(SPEW, "creating bootstrap completion thread\n");
 
	//thread_bs2:创建bootstrap2线程,用于完成后续的初始化并加载app bootstrap2
 	thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL,
 		DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
......
 }

1. 初始化系统任务所需的线程、链表和相关队列。
2. 初始化硬件平台,搭建lk基本运行环境
3. 初始化定时器等
4. 创建一个新线程bootstrap2,并执行。当前线程置于空闲状态

2.4 bootstrap2

static int bootstrap2(void *arg)
{
    dprintf(SPEW, "top of bootstrap2()\n");

    print_stack_of_current_thread();

    arch_init();

    // XXX put this somewhere else
#if WITH_LIB_BIO
    bio_init();
#endif
#if WITH_LIB_FS
    fs_init();
#endif
    // Allocate LK memory from mb, free before jump to kernel
    mboot_allocate_lk_scratch_from_mblock();

    // initialize the rest of the platform
    dprintf(SPEW, "initializing platform\n");
    platform_init();

    // initialize the target
    dprintf(SPEW, "initializing target\n");
    target_init();

    dprintf(SPEW, "calling apps_init()\n");
    apps_init();

    return 0;
}

bootstrap2线程主函数:初始化bio、fs、platform、app

app_init 逐个app初始化并运行

mt_boot执行后续启动流程,最终加载kernel的app

三、Kernel(汇编/C)

3.1 作用

初始化调度、内存管理、io、中断等linux操作系统基本功能、识别DTBO、创建init进程、完成模块的初始化,执行init主程序

3.2 入口代码

/MTXXXX_13_Master/vnd/kernel/kernel-5.10/arch/arm64/kernel/head.S

MMU、CPU、页表、Cache等初始化,跳转到start_kernel

3.3 start_kernel

/MTXXXX_13_Master/vnd/kernel/kernel-5.10/init/main.c

在一系列基本初始化完成后,rest_init->kernel_init 创建init进程,并在/sbin/etc/bin依次寻找init可执行文件

3.4 DTBO识别流程

start_kernel->setup_arch->unflatten_device_tree->unflatten_device_tree->unflatten_dt_nodes

在unflatten_dt_nodes中遍历每个节点,对每个节点调用populate_node,将每个节点的信息转化为device_node结构;

unflatten_dt_alloc创建device_node结构

populate_propertites创建property结构,并将device_node属性添加进去

3.5 platform bus初始化流程

do_basic_setup->driver_init

devices_init:创建/sys/devices /sys/dev两个设备根节点,创建/sys/dev/block /sys/dev/char

buses_init:创建/sys/bus bus根节点

platform_bus_init

注册platform_bus设备,创建/sys/devices/plaform节点,此节点是所有platform设备的根节点

注册platform_bus_type总线类型,创建/sys/bus/platfrom节点,此节点是所有platform设备的总线类型根节点

3.6 将设备树种的设备加入platform devices:

入口函数

/MTXXXX_13_Master/vnd/kernel-5.10/drivers/of/platform.c

通过arch_initcall_sync将此函数加入kernel初始化函数集

通过of_platform_default_populate->of_plattform_populate->platform_bus_create此调用流程挑选合适的设备加入platform bus

最后通过of_plaform_device_create_pdata->of_device_add将设备添加到platform devices

四、Native(C/C++)

4.1 作用

启动系统关键进程init、void、surfaceflinger

4.2 init入口代码

/MTXXXX_13_Master/sys/system/core/init/main.cpp

int main(int argc, char** argv) {
......

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
    //init第一阶段
    return FirstStageMain(argc, argv);
}

4.3 init第一阶段 FirstStageMain

/MTXXXX_13_Master/sys/system/core/init/first_stage_main.cpp

1、创建系统目录、挂载对应分区

2、初始化init阶段log到kernel log

3、加载SElinux安全策略

4.4 init第二阶段 SecondStageMain

/MTXXXX_13_Master/sys/system/core/init/init.cpp

1、初始化属性系统,从指定位置读取属性设置:-->Propertyinit()

2、挂载apex/分区-->MountExtraFilesystem s ()

3、SElinux第二阶段-->SelinuxRestoreContext() :

4、启动属性服务,以便增加、修改、获取属性-->StartPropertyService ()

5、初始化文件上下文-->InitializeSubcontext()

6、将am、sm添加到集合中,以便后续按顺序执行-->LoadBootscripts (am , sm )

7、执行init.rc

4.5 initrc语法:安卓启动脚本专用语法

四要素:Action、Command、Service、Option

4.5.1 Action

由一组命令和一个触发器组成,触发器语句以on开头,on后的条件决定执行的时机,当一些条件满足触发器的条件时,该Action中定义的命令会被添加到要执行命令队列的尾部(如果这组命令已经在队列中,则不会再次添加)。

常用的triggers如下:

  1. early-init 在初始化早期阶段触发
  2. late-init 在初始化晚期阶段触发
  3. init 在初始化阶段触发
  4. late-init 在初始化晚期阶段触发
  5. boot/charger 当系统启动/充电时触发
  6. property:<key>=<value> 当属性值满足条件时触发 如:on property:ro.debuggable=1
  7. fs 挂载mtd分区时触发
  8. boot 基本网络的初始化,内存管理等时触发
  9. post-fs 改变系统目录的访问权限时触发
  10. device-added-<path> 设备节点添加时触发
  11. device-removed-<path> 设备节点删除时触发
  12. service-exited-<name> 在特定服务(service)退出时触发

on earty-init创建文件目录,给进程设置限制(nice、fd)启动 ueventd

on init创建文件目录,给各节点分用户组,启动logd、Imkd、servicemanager等服务

on late-init

on early-fs:启动voId

on fs:挂载文件目录

on postfs:挂载文件系统 rootfs(remount)。

on late-fs:存储加密解锁前所需的 HALs如(keyasten)

on post-fs-data:挂载data,启动apexd,初始化第一个用户,启动fuse,

zygote-start:需和加密状态一起,启动zygote.netdzygote-secondnary

on boot:启动 hal,启动core service

4.5.2 command

常用命令:

1).import <filename>          
  导入init.XX.rc、xxx.conf等文件  
   Parse an init config file, extending the current configuration.

2).chmod <octal-mode> <path>  
   Change file access permissions.

3).chown <owner> <group> <path>  
   Change file owner and group.  
    
4).chdir <directory>  
   Change working directory.  
    
5).chroot <directory>   
  改变进程根目录  
    
6).insmod <path>     
  加载XX.ko驱动模块

7).start <service>  
   Start a service running if it is not already running.

8).stop <service>  
   Stop a service from running if it is currently running.

9).class_start <serviceclass>  
   Start all services of the specified class if they are not already running.

10).class_stop <serviceclass>  
   Stop all services of the specified class if they are currently running.  
       
   class_reset <serviceclass>   //重启class下面所有的服务  
       
11).setprop <name> <value>    
   Set system property <name> to <value>.  
   通过getprop命令可以查看当前系统的属性值  
    
12).export <name> <value>         
  设置全局环境变量,这个变量值可以被所有进程访问(全局的,一直存在)  
  在代码中通过value = getenv("name")接口可以获取这个环境变量的值  
    
13).mkdir <path> [mode] [owner] [group]  
   创建目录,后面项缺省值为 mode,owner,group: 0755 root root

14).trigger <event>  
   Trigger an action.  Used to queue an action from another action.  
   例:trigger post-fs-data

15).exec <path> [ <argument> ]*       
   执行<path>指定的Program,并可以带有执行参数。  
   exec在调用进程内部执行一个可执行文件,并会阻塞当前进程,直到运行完成。  
   最好避免和那些builtin commands一样使用exec命令,否则容易造成阻塞 or stuck ( maybe there should be a timeout?)

16).ifup <interface>  
   启动某个网络接口,使其为up状态,通过netcfg可以查看,ifup eth0  等价于 netcfg eth0 up 功能一样  
    
17).hostname <name>  
   设置设备的主机名,一般默认设置为localhost,可以在终端通过hostname new_name进行修改

18).domainname <name>  
   设置网络域名localdomain

19).mount <type> <device> <dir> [ <mountoption> ]* 
    把device挂接到dir目录下面,文件系统类型为type。  
   <mountoption>s include "ro", "rw", "remount", "noatime", “nosuid”......,具体可查看[linux](http://lib.csdn.net/base/linux "Linux知识库")的mount命令说明  
    
20).setkey  
   TBD  == to be determined 暂时没有使用

21).setrlimit <resource> <cur> <max>  
  设置本服务进程的资源上限值。(使用例子??)

22).symlink <target> <path>     
   path 链接到 ---》target ;创建符号链接

23).sysclktz <mins_west_of_gmt>    
  设置系统时区(0 if system clock ticks in GMT)

24).wait <path> [ <timeout> ]  
 轮询查找给定的文件path是否存在,如果找到或者超时则返回默认超时为5秒。(使用实例???)

25).write <path> <string> [ <string> ]*  
   打开一个文件,利用write命令写入一个或多个字符串

4.5.3 service

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

服务(services)是指那些须要在系统初始化时就启动或退出时自己主动重新启动的程序.

它的语法结构例如以下:

1.  service <name> <pathname> [ <argument> ]* 
2.   <option> 
3.   <option> 
4.   ...

pathname: 必须要有可执行的权限 service的name: 在所有rc文件中不能重复

4.5.4 option 选项

  • class <class_name>
    说明服务属于class_name这个类。缺省值service属于 “default” 类。同一个class下面的服务可以一起启动或停止。
  • disabled
    表示当这个服务所在的class启动的时候,服务不会自动启动,
    要用start server_name 或 property_set("ctl.start", server_name);才能启动。
  • oneshot
    当服务退出后,不会再重新启动,如果没有加这个option,则服务默认退出后又会重新重启
  • user <username>
    执行服务之前,先声明服务的用户名,缺省值应该为root用户.
  • group <groupname> [ <groupname> ]*
    执行服务之前,先声明服务所属组名,可以一次声明属于多个组。
    声明多个组时,除第一个组名外,其他的为服务的补充组名(调用接口 setgroups()).
  • onrestart + command
    服务重启的时,会执行onrestart后面的command.
    eg:onrestart restart media 重启名为media的服务
  • setenv <name> <value>
    在当前服务进程中设置环境变量name的值为value。
    注意:setenv定义的环境变量仅在本进程内生效,退出该进程,或者关闭相应的程序运行窗口,该环境变量即无效)
    程序中可通过getenv("name")接口获取这个环境变量的值
    setenv和export 的区别:
    setenv csh ,本进程生效,退出后,变量无效
    export bash ,全局生效,一直存在
    格式:
    export key=value
    setenv key value
  • critical
    声明为关键服务。如果服务在四分钟内退出了四次,则设备会进入recovery模式
  • socket <name> <type> <perm> [ <user> [ <group> ] ]
    创建名为/dev/socket/<name>的unix domain socket ,并把它的句柄fd传给本服务进程
    <type> 必须为 "dgram", "stream" or "seqpacket".User and group default to 0 ,也就是root.
  • seclablel 执行服务之前改变安全上下文

五、Android(JAVA)

init fork zygote进程,再由zygote去创建所有安卓的应用进程。

5.1 ZygoteInit

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    public static void main(String argv[]) {
       //1、创建ZygoteServer
        ZygoteServer zygoteServer = new ZygoteServer();
      .......
        try {
             .......
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
           // 2、解析app_main.cpp传来的参数
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = 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.");
            }
            //3、创建一个Server端的Socket
            zygoteServer.registerServerSocket(socketName);
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                    SystemClock.uptimeMillis());
               //4、加载进程的资源和类
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                    SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }
              ........
            if (startSystemServer) {
                //5、开启SystemServer进程
                startSystemServer(abiList, socketName, zygoteServer);
            }

            Log.i(TAG, "Accepting command socket connections");
           //6、启动一个死循环监听来自Client端的消息
            zygoteServer.runSelectLoop(abiList);
           //7、关闭SystemServer的Socket
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
           //8、这里捕获这个异常调用MethodAndArgsCaller的run方法。
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

5.2 Zygote流程

1、创建java虚拟机

2、为java虚拟机注册native方法

3、在com.android.initernal.os.ZygoteInit中调用java类的主要方法

4、加载Zygotelnit class

5、注册Zygote socker

6、加载preload class

7、加载preload资源文件

8、调用Zygote::forkSystemServer、fork一个新的进程,调用SystemSercer的main方法,启动SystemServer进程

1.解析init.zygote.rc中的参数,创建AppRuntime并调用AppRuntime.start()万法

2.调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数

3.通过JNI方式调用Zygotelnitmain0),第一次进入Java世界

4.registerZygoteSocket()建立socket通道,zygote作为通信的服务端用于响应客户端请求

5.preload()预加载通用类、drawable和color资源、openGL以及共享库以及WebView,用于提高app启动效率

6.通过startSystemServer(),fork得力帮手system_server进程

7.调用runSelectLoop0(),当接收到请求创建新进程请求时立即唤醒并执行相应工作

5.3 Zygote作用

创建SystemServer

孵化应用进程

5.3 相关进程

init 进程:当内梭创建了 init 进程之后便去执行 init,init 进程的最后阶段对 init,rc脚本进行解析,启动各种进程服务,其中最重要的是启动了 zygote 进程。

zygote 进程: zygote 进程承上启下,是系统开启的第一个 java 进程,运行在 framework层;该进程主要负责创建包括 systemserver 在内的所有应用程序,以及创建虚拟机运行环境。

systemserver 进程: 启动 Binder 线程池和 SystemServiceNanager;

systemServiceManager 主要是对系统服进行创建、启动和生命局期管理,就会启动各种系统服。(android中最核心的服务 AMS 就是在 SystemServer 进程中启动的)

Launcher 进程: launcher 进程是android 系统启动的最后一步,主要负责将已经安装好的应用程序显示到界面上。

5.4 谷歌官方开机优化资料

https://source.android.com/devices/tech/perf/boot-times

 

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

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

相关文章

Android:RecyclerView封装,打造列表极简加载

前言 mBinding.recycler.linear().divider().set<OrdinaryListBean> {addLayout(R.layout.layout_ordinary_item)}.setList(getList()) 如果我要说&#xff0c;除了数据和布局之外&#xff0c;以上的几行代码&#xff0c;就实现了一个列表加载&#xff0c;有老铁会相信…

T形积木(T puzzle)

目录 积木绘制 积木拼接 练习 1. 停止标志 2. 跳跃旋转 3. 小步平移 积木绘制 &#xff08;1&#xff09;复数欧拉公式&#xff1a; &#xff08;2&#xff09;复数的极坐标形式&#xff1a; 其中 &#xff08;3&#xff09;T形积木问题利用了复数乘以将该复数值旋转b角的…

Spring源码解析(五):循环依赖

Spring源码系列文章 Spring源码解析(一)&#xff1a;环境搭建 Spring源码解析(二)&#xff1a;bean容器的创建、默认后置处理器、扫描包路径bean Spring源码解析(三)&#xff1a;bean容器的刷新 Spring源码解析(四)&#xff1a;单例bean的创建流程 Spring源码解析(五)&…

Ubuntu 20.04.4 LTS安装Terminator终端(Linux系统推荐)

Terminator终端可以在一个窗口中创建多个终端&#xff0c;并且可以水平、垂直分割&#xff0c;运行ROS时很方便。 sudo apt install terminator这样安装完成后&#xff0c;使用快捷键Ctrl Alt T打开的就是新安装的terminator终端&#xff0c;可以使用以下方法仍然打开ubuntu默…

IAR for STM8L标准库基于DMP库驱动MPU6050

IAR for STM8L标准库基于DMP库驱动MPU6050 ✨移植到STM8上&#xff0c;主要对接的是I2C对应的接口函数&#xff0c;也没有什么难度&#xff0c;该型号目前不属于新设计推荐的型号了&#xff0c;如果使用DMP库最好还是需要配合磁力计才能输出比较稳定的数据&#xff0c;使用MPU9…

【App管理04-Bug修正 Objective-C语言】

一、咱们刚才已经把这个给大家做完了吧 1.这个Label怎么显示到上面去了, 我们现在是把它加到我们的控制器的View里面吧 我们看一下这个坐标是怎么算的,来,我们找一个坐标, 咱们的坐标,是不是用这个View的frame,减的吧 来,咱们在这里,输出一下这个Frame,看一下吧 在…

idea的Plugins中搜索不到插件

1、ctrlalts 打开设置 ; 2、搜索框输入plugins; 3、点击plugins; 4、点齿轮按钮&#xff0c;选择HTTP Proxy settings; 如下操作&#xff1a; 5、刷新DNS&#xff0c;ipconfig /flushdns 6、重新打开idea 的plugins 插件列表出来了

EC200U-CN学习(五)

预留抓取CP日志 U15-B引脚学习 LOUDSPK_P: 一个连接到一个功率放大器的音频输出引脚。 MIC_P: MIC_P是一个用于连接麦克风的阳性引脚。通常情况下&#xff0c;MIC_P引脚用于连接麦克风的正极&#xff0c;而MIC_N引脚则用于连接麦克风的负极。麦克风的正极和负极之间通常需要连…

springboot+mybatis-plus+vue+element+vant2实现短视频网站,模拟西瓜视频移动端

目录 一、前言 二、管理后台 1.登录 2.登录成功&#xff0c;进入欢迎页 ​编辑 3.视频分类管理 4. 视频标签管理 5.视频管理 6.评论管理 ​编辑 7.用户管理 8.字典管理 &#xff08;类似于后端的枚举&#xff09; 9.参数管理&#xff08;富文本录入&#xff09; 10.管…

Flask get post请求

Flask get &post请求 一、环境描述二、初始化flask 程序三、get请求3.1 代码3.2 分析3.3 验证3.4 请求结果 四、post请求4.1 代码4.2 分析4.3 验证4.3.1 postman 请求头application/json参数4.3.2 postman 请求头application/x-www-form-urlencoded参数4.3.3 postman 请求头…

【ESP32】Espressif-IDE及ESP-IDF安装

一、下载Espressif-IDE 2.10.0 with ESP-IDF v5.0.2 1.打开ESP-IDF 编程指南 2.点击快速入门–>安装–>手动安装–>Windows Installer–>Windows Installer Download 3.点击下载Espressif-IDE 2.10.0 with ESP-IDF v5.0.2 二、安装Espressif-IDE 2.10.0 wit…

Docker 全栈体系(七)

Docker 体系&#xff08;高级篇&#xff09; 五、Docker-compose容器编排 1. 是什么 Compose 是 Docker 公司推出的一个工具软件&#xff0c;可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml&#xff0c;写好多个容器之间的调…

4、Linux驱动开发:设备-设备号设备号注册

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

Unity游戏源码分享-ARPG游戏Darklight.rar

Unity游戏源码分享-ARPG游戏Darklight.rar 玩法 项目地址&#xff1a;https://download.csdn.net/download/Highning0007/88105464

1.jquery遍历数组2.layui框架的理解

1.jquery遍历数组 2.layui框架的理解 layui.use(["form", "laydate"], 是使用 layui 框架中的模块加载方法 use 来加载并使用 form 和 laydate 这两个模块。 在 layui 框架中&#xff0c;可以使用 use 方法来加载所需的模块&#xff0c;然后使用这些模块…

[CrackMe]Chafe.1.exe的逆向及注册机编写

上手先试一下, 发现其没有对话框, 只有字符串, 搜索"Your serial is not valid"字符串 \ 上来就直接发现关键跳转, 难道这题这么简单吗? 仔细一看实际上远远要复杂 往上一翻发现没有生成serial key的代码, 而是看到了一个SetTimer, 时间间隔设置成了1ms, 之前输入…

访问:http://localhost:8070/actuator/bus-refresh 问题

1、请求发送不出去 原因&#xff1a; 自己 config-server端 application.yml 配置的端口号是8888&#xff0c;访问server修改为配置的端口号 2、请求报错405 几个解决办法&#xff1a; 1、版本问题变为busrefresh 2、bus-refresh加单引号或双引号尝试 3、加配置尝试&#xff1a…

嵌入式_GD32看门狗配置

嵌入式_GD32独立看门狗配置与注意事项 文章目录 嵌入式_GD32独立看门狗配置与注意事项前言一、什么是独立看门狗定时器&#xff08;FWDGT&#xff09;二、独立看门狗定时器原理三、独立看门狗定时器配置过程与注意事项总结 前言 使用GD3单片机时&#xff0c;为了提供了更高的安…

服务器数据恢复-Windows服务器RAID5数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器挂载三台IBM某型号存储设备&#xff0c;共64块SAS硬盘&#xff0c;组建RAID5磁盘阵列&#xff1b; 服务器操作系统&#xff1a;Windows Server&#xff1b;文件系统&#xff1a;NTFS。 服务器故障&#xff1a; 一台存储中的一块硬盘离…

STM32 串口学习(二)

要用跳线帽将PA9与RXD相连&#xff0c;PA10与TXD相连。 软件设计 void uart_init(u32 baud) {//UART 初始化设置UART1_Handler.InstanceUSART1; //USART1UART1_Handler.Init.BaudRatebound; //波特率UART1_Handler.Init.WordLengthUART_WORDLENGTH_8B; //字长为 8 位数据格式U…