Android 源码解读-应用是如何启动的

news2024/12/24 8:49:02

作者:Android帅次

前言

作为多年的 Android 开发,写了不少应用,但是一个App到底是怎么启动起来的?你要说桌面点一下就启动了,那也对。但是它的启动过程呢?带着这样的疑问,咱们来一步步学习。

Android 启动过程

一般在任何平台上,都会逐步加载和执行以下组件:

  • Boot loader
  • U-boot (optional)
  • Kernel
  • Android

Android进程有以下顺序:

  • Init
  • Zygote
  • System Server
  • Service Manager
  • Other Daemons and processes
  • Applications

具体情况如下图,这两幅图结合起来比较有意思:

  • Boot ROM:当电源按下时,引导芯片代码会从预定义的地方(固化在ROM)开始执行,加载引导程序BootLoader到RAM,然后执行。(这一步由"芯片厂商"负责设计和实现)

  • Boot loader:Bootloader开始执行,首先负责完成硬件的初始化,引导操作系统启动。(这一步由"设备厂商"负责设计和实现)

  • Kernel:Linux 内核是 Android 的核心,负责进程创建、进程间通信、设备驱动程序、文件系统管理等。 Android 在主流内核上应用自定义补丁来支持 Android 运行所需的某些功能,如唤醒锁等。内核可以作为未压缩图像或压缩图像加载。在加载时,它挂载根文件系统(通常作为内核命令行参数传递)并启动用户空间中的第一个应用程序。(这一步则是Android内核开发过程中需要涉及的地方)

  • Android:Android系统以及各大Linux的发行版,他们的Linux内核部分启动过程都是差不多的,他们之间最大的区别就在于init程序的不同,因为init程序决定了系统在启动过程中,究竟会启动哪些守护进程和服务,以及呈现出怎样的一个用户UI界面。

因此,init程序是分析Android启动过程中最核心的程序。

  • init 和 init.rc:启动内核时执行的第一个用户空间应用程序是位于根文件夹中的 init 可执行文件。该进程解析称为"init.rc"脚本的启动脚本。这是用一种专为 android 设计的语言编写的,用于启动所有必要的进程、守护程序和服务,以便 android 正常运行。它提供了各种类型的执行时间,例如 early-init、on-boot、on-post-fs 等。(用户空间的鼻祖)

  • Demons and Services:init 进程创建了各种守护进程和进程,如 rild、vold、mediaserver、adb 等,每个进程负责自己的功能。这些进程的描述不在本文的范围内。相反,我们将更多地讨论"Zygote"进程。

  • Service Manager:Service Manager进程 管理系统中运行的所有Service。创建的每个服务都会在此进程中注册自己,并且此信息供其他进程/应用程序将来参考。

  • Zygote:Zygote 是启动时创建的第一个 init 进程之一。术语"合子"是基于生物学"形成的初始细胞分裂产生后代"。类似地,"zygote in android"初始化 Dalivik VM(ART) 和 fork 以创建多个实例来支持每个 android 进程。它有助于在 VM 实例之间使用共享代码,从而减少内存占用和加载时间,非常适合嵌入式系统。Zygote 除了在服务器套接字上安装侦听器外,还预加载了稍后在 Android 应用程序中使用的类和资源。完成后,系统服务器启动。

  • System Server:SystemServer 进程启动 Android 中可用的所有服务。

本文咱们重点从 init 开始到应用启动。

1、Zygote是什么

在Android系统里面,zygote是一个进程的名字。Android是基于Linux System的,当你的手机开机的时候,Linux的内核加载完成之后就会启动一个叫"init"的进程。在Linux System里面,所有的进程都是由init进程fork出来的,我们的zygote进程也不例外。

Zygote是一个虚拟机进程,同时也是一个虚拟机实例的孵化器,每当系统要求执行一个Android应用程序,Zygote就会fork(分裂)出一个子进程来执行该应用程序。

1.1 app_main.cpp

frameworks/base/cmds/app_process/app_main.cpp

在Zygote启动后就会执行 app_main.cpp。不管是C/c++/java,他们的入口就是 main(),就跟看到 Activity 咱们直接找 onCreate() 方法一样。

1.1.1 main()

int main(int argc, char* const argv[])
{
    ...
    //注释1:初始化AppRuntime(AndroidRunTime)
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ...
    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        //注释2:设置zygote模式
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } 
        ...
    }
    Vector<String8> args;
    if (!className.isEmpty()) {
        ...
    } else {
        // 我们处于 zygote 模式。
        maybeCreateDalvikCache();

        // 注释3:在 zygote 模式下,将参数传递给 ZygoteInit.main() 方法。
        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        //PROP_VALUE_MAX = 92;
        char prop[PROP_VALUE_MAX];
        ...
        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }    
    if (zygote) {
        //注释4:调用 AndroidRuntime.start() 方法
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        ...
    } else {
        ...
    }
}

注释1:初始化 AppRuntime ,其实就是 AndroidRuntime(ART)。

注释2:设置zygote模式。

注释3:将参数传递给 ZygoteInit.main() 方法。

注释4:启动 ZygoteInit 。这里的 ZygoteInit 就是 zygote 进程的启动类。这个下面讲到。咱们先看看AndroidRuntime 的 start() 方法。

1.2 AndroidRuntime.cpp

frameworks/base/core/jni/AndroidRuntime.cpp

Android 虚拟机

1.2.1 start()

/*
 * Start the Android runtime.  This involves starting the virtual machine and calling the "static void main(String[] args)" method in the class named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //注释1:启动虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    //注释2:注册安卓功能(JNI)
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ...
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    ...
    /*
     * 启动虚拟机。 该线程成为VM的主线程,直到VM退出才会返回。
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ...
    } else {
        ...
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ...
        } else {
            //注释3
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
        }
    }
    ...
}

注释1:启动VM(虚拟机)

注释2:注册安卓功能(JNI)

注释3:便用JNI调用 Zygotelnit 的 main() 方法。这里的 Zygotelnit 是class文件,也就是说从这里开始就进入java领域喽。

JNI:连接 native(C/C++) 层 和 java 层的桥梁。

1.3 ZygoteInit.java

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

/**
 * zygote 进程的启动类。
 */
public class ZygoteInit {
    ...
}

这是 Zygote 进程的入口点。 它创建 Zygote 服务,加载资源,并处理与准备分叉到应用程序的过程相关的其他任务。

1.3.1 main()

    @UnsupportedAppUsage
    public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        try {
            ...
            boolean startSystemServer = false;
            //argv:用于指定 Zygote 配置的命令行参数。
            ...
            if (!enableLazyPreload) {
                //注释1:预加载资源。
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            }
            ...
            //注释2:创建Zygote 的 LocalServerSocket 。
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                //注释3:开始fork我们的SystemServer进程。
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                ...
            }
            ...
            // 注释4:zygote 永久循环。
            caller = zygoteServer.runSelectLoop(abiList);            
        } catch (Throwable ex) {
            ...
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }
        ...
    }

注释1:预加载资源。

注释2:创建Zygote 的 LocalServerSocket 。

注释3:开始 fork 我们的 SystemServer 进程。

注释4:zygote 永久循环。

这里咱们看看 forkSystemServer() ;

1.3.2 forkSystemServer()

    /**
     * Prepare the arguments and forks for the system server process.
     *
     * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
     * process; {@code null} in the parent.
     */
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ...
        //命令行来启动SystemServer
        //ZygoteInit.main(String argv[])里面的argv 跟这个类似
        String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        //处理与 zygote spawner 相关的 args 的参数解析。
        ZygoteArguments parsedArgs;
        int pid;
        try {
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
            try {
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            } catch (EOFException e) {
                throw new AssertionError("Unexpected argument error for forking system server", e);
            }
            commandBuffer.close();
            ...

            //请求 fork 系统服务器进程
            /* Request to fork the system server process */
            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 */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

这里启动了一个 system server 。下面咱们就看看他。

2、SystemServer

system server 也就是 SystemServer。SystemServer也是一个进程,包括ActivityTaskManagerService、ActivityManagerService、PackageManagerService、WindowManagerService等92种服务。

Android Framework里面两大非常重要的进程:

  • SystemServer进程。

  • Zygote进程。

2.1 SystemServer.java

frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer {
    ...
}

2.1.1 main()

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
    public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
        ...
    }    

下面 咱们看看 run () 里面都用什么?

2.1.2 run()

    private void run() {
        try {
            ...
            // 注释1:加载动态库libandroid_service.so。
            System.loadLibrary("android_servers");

            // 注释2:创建系统上下文。
            createSystemContext();

            // 调用每个进程的主线模块初始化。
            ActivityThread.initializeMainlineModules();

            // 注释3:创建 SystemServiceManager。
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // 为可并行化的 init 任务准备线程池
            SystemServerInitThreadPool.start();
            ...
        } finally {

        }
        // 注释4:Start services。
        try {
            //下面咱们看看这个三个方法启动什么服务
            startBootstrapServices(t);
            startCoreServices(t);
            startOtherServices(t);
        } catch (Throwable ex) {
            ...
        } finally {
            t.traceEnd(); // StartServices
        }

        ...
        // 注释5:Loop 永久循环。
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

注释1:加载动态库libandroid_service.so。

注释2:创建系统上下文。

注释3:创建 SystemServiceManager。

注释4:启动服务(startBootstrapServices、startCoreServices、startOtherServices)

注释5:Loop 永久循环。

2.1.3 createSystemContext()

    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);
    }

初始化系统上下文对象mSystemContext,并设置默认的主题,mSystemContext实际上是一个Context(ContextImpl)对象。

调用ActivityThread.systemMain()的时候,会调用ActivityThread.attach(true),而在attach()里面,则创建了Application对象,并调用了Application.onCreate()。

2.1.4 startBootstrapServices()

    /**
     * 启动系统引导服务,因为这些服务之间有复杂的相互依赖关系,所以都放在了这个方法里面。
     */
    private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
        ...
        final String TAG_SYSTEM_CONFIG = "ReadingSystemConfig";
        SystemServerInitThreadPool.submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);

        // PlatformCompat Service 由 ActivityManagerService, PackageManagerService 和 其他服务做使用
        PlatformCompat platformCompat = new PlatformCompat(mSystemContext);
        ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
        ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
                new PlatformCompatNative(platformCompat));
        AppCompatCallbacks.install(new long[0]);

        mSystemServiceManager.startService(FileIntegrityService.class);
        Installer installer = mSystemServiceManager.startService(Installer.class);
        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
        mSystemServiceManager.startService(UriGrantsManagerService.Lifecycle.class);
        startMemtrackProxyService();

        // StartActivityManager
        ActivityTaskManagerService atm = mSystemServiceManager.startService(
                ActivityTaskManagerService.Lifecycle.class).getService();
        //初始化 ActivityManagerService
        mActivityManagerService = ActivityManagerService.Lifecycle.startService(
                mSystemServiceManager, atm);
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        mWindowManagerGlobalLock = atm.getGlobalLock();

        mDataLoaderManagerService = mSystemServiceManager.startService(
                DataLoaderManagerService.class);

        mIncrementalServiceHandle = startIncrementalService();
        t.traceEnd();

        //初始化PowerManagerService(电源服务),需要提前启动,因为其他服务需要它。
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
        mSystemServiceManager.startService(ThermalManagerService.class);

        // 电源管理已经开启,ActivityManagerService负责电源管理功能
        mActivityManagerService.initPowerManagement();

        mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
        ...

        mSystemServiceManager.startService(LightsService.class);

        // Package manager isn't started yet; need to use SysProp not hardware feature
        if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
            mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS);
        }

        // 初始化DisplayManagerService(显示管理器)
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

        mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

        // Start the package manager.
        try {
            mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        } finally {

        }

        // 现在PackageManagerService已经启动,注册 dex 加载报告器来捕获系统服务加载的任何 dex 文件。
        // 这些 dex 文件将由 BackgroundDexOptService 优化。
        SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);

        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        ...
        //将AMS等添加到ServiceManager中
        mActivityManagerService.setSystemProcess();
        if (!mOnlyCore) {
            boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                    false);
            if (!disableOtaDexopt) {
                try {
                    OtaDexoptService.main(mSystemContext, mPackageManagerService);
                } catch (Throwable e) {

                } finally {
                }
            }
        }

        ...
        mSensorServiceStart = SystemServerInitThreadPool.submit(() -> {
            TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
            startSensorService();
        }, START_SENSOR_SERVICE);

        // startBootstrapServices
    }

改动比较大的地方:

  • ActivityTaskManagerService(ATMS):负责管理除Activity和进程,包括生命周期和状态切换。

  • ActivityManagerService(AMS):AMN的子类,负责管理三大组件(除Activity)和进程,包括生命周期和状态切换。AMS因为要和ui交互,所以极其复杂,涉及window。

ActivityTaskManagerService:把 Activity 相关的内容从 ActivityManagerService 剥离出来而产生的。

PowerManagerService(PMS):电源管理服务。

PackageManagerService(PKMS):包管理服务,不叫PMS是为了和电源管理服务区分开。

2.1.5 startCoreServices()

    /**
     * 启动核心服务。
     */
    private void startCoreServices(@NonNull TimingsTraceAndSlog t) {
        // Service for system config
        mSystemServiceManager.startService(SystemConfigService.class);
        // Tracks the battery level.  Requires LightService.
        mSystemServiceManager.startService(BatteryService.class);
        ...
        mSystemServiceManager.startService(LooperStatsService.Lifecycle.class);

        mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS);

        mSystemServiceManager.startService(NativeTombstoneManagerService.class);

        mSystemServiceManager.startService(BugreportManagerService.class);

        mSystemServiceManager.startService(GpuService.class);

        // startCoreServices
    }

2.1.6 startOtherServices()

    /**
     * 启动其他服务。
     */
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {

        final Context context = mSystemContext;
        VibratorService vibrator = null;
        DynamicSystemService dynamicSystem = null;
        IStorageManager storageManager = null;
        NetworkManagementService networkManagement = null;
        IpSecService ipSecService = null;
        VpnManagerService vpnManager = null;
        VcnManagementService vcnManagement = null;
        NetworkStatsService networkStats = null;
        NetworkPolicyManagerService networkPolicy = null;
        NsdService serviceDiscovery = null;
        WindowManagerService wm = null;
        SerialService serial = null;
        NetworkTimeUpdateService networkTimeUpdater = null;
        InputManagerService inputManager = null;
        TelephonyRegistry telephonyRegistry = null;
        ConsumerIrService consumerIr = null;
        MmsServiceBroker mmsService = null;
        HardwarePropertiesManagerService hardwarePropertiesService = null;
        PacProxyService pacProxyService = null;
        ...
        // 现在便可以开始启动三方APP应用(如Launcher启动桌面)
        mActivityManagerService.systemReady(() -> {
        ...
         }, t);       
        // startOtherServices
    }

经过上面这些步骤,我们调用调用createSystemContext()创建系统上下文的时候,也已经完成了mSystemContext和ActivityThread的创建。

ATMS、AMS、WMS、PKMS等对象已经创建好了,并且完成了成员变量初始化。

注意:这是系统进程开启时的流程,在这之后,会开启系统的 Launcher程序,完成系统界面的加载与显示。

在Android的框架设计中,服务器端指的就是所有App共用的系统服务,比如我们这里提到的ATMS、AMS、WMS、PKMS等等,这些基础的系统服务是被所有的App公用的。

3、Launcher是什么

在Android系统中,应用程序是由Launcher启动起来的,其实,Launcher本身也是一个应用程序,其它的应用程序安装后,就会Launcher的界面上出现一个相应的图标,点击这个图标时,Launcher就会对应的应用程序启动起来。

当然也可以在 其他应用 启动应用。但是本质上都是调用startActivity()。

3.1 LauncherActivity.java

frameworks/base/core/java/android/app/LauncherActivity.java

/**
 * Displays a list of all activities which can be performed
 * for a given intent. Launches when clicked.
 *
 * @deprecated Applications can implement this UI themselves using
 *   {@link androidx.recyclerview.widget.RecyclerView} and
 *   {@link android.content.pm.PackageManager#queryIntentActivities(Intent, int)}
 */
@Deprecated
public abstract class LauncherActivity extends ListActivity {
    ...
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = intentForPosition(position);
        startActivity(intent);
    }
}

所以为了帮助到大家更好的了解Android Framework框架中的知识点,这边查阅大量的素材,整理了一下的 Android Framework 核心知识点手册,里面记录了:有Handler、Binder、AMS、WMS、PMS、事件分发机制、UI绘制……等等,几乎把更Framework相关的知识点全都记录在册了

《Framework 核心知识点汇总手册》https://qr18.cn/AQpN4J

Handler 机制实现原理部分:
1.宏观理论分析与Message源码分析
2.MessageQueue的源码分析
3.Looper的源码分析
4.handler的源码分析
5.总结

Binder 原理:
1.学习Binder前必须要了解的知识点
2.ServiceManager中的Binder机制
3.系统服务的注册过程
4.ServiceManager的启动过程
5.系统服务的获取过程
6.Java Binder的初始化
7.Java Binder中系统服务的注册过程

Zygote :

  1. Android系统的启动过程及Zygote的启动过程
  2. 应用进程的启动过程

AMS源码分析 :

  1. Activity生命周期管理
  2. onActivityResult执行过程
  3. AMS中Activity栈管理详解

深入PMS源码:

1.PMS的启动过程和执行流程
2.APK的安装和卸载源码分析
3.PMS中intent-filter的匹配架构

WMS:
1.WMS的诞生
2.WMS的重要成员和Window的添加过程
3.Window的删除过程

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

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

相关文章

C语言 | 约瑟夫问题(猴王争夺战)

约瑟夫问题&#xff08;单向循环链表的使用&#xff09; 约瑟夫问题有时也称为约瑟夫斯置换&#xff0c;是一个出现在计算机科学和数学中的问题。在计算机编程的算法中&#xff0c;类似问题又称为约瑟夫环。下面我们将用猴子争大王这一故事以及采用单向循环链表这一方法来进行讲…

Lazysysadmin靶机渗透过程

准备工作 下载好靶机到本地后 VMware导入OVA 启动靶机 扫描信息 首先扫描整个C段发现主机 进一步扫描端口 从扫描结果可知&#xff1a; Samba服务MySQLSSH端口网站端口 先对网站进行目录遍历 发现有wordpress网站和phpmyadmin管理系统 出现了非常多遍My name is togie.可能…

Leetcode171. Excel 表列序号

Every day a leetcode 题目来源&#xff1a;171. Excel 表列序号 解法1&#xff1a;数学 168. Excel表列名称的逆向题目。 本题实质上是特殊的 26 进制。 A ~ Z对应1 ~ 26。 假设 A 0&#xff0c;B 1&#xff0c;…&#xff0c;那么 AB 261 * 0 260 * 1。 而这里是A…

二叉搜索树中的搜索

1题目 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和一个整数值 val。 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在&#xff0c;则返回 null 。 示例 1: 输入&#xff1a;root [4,2,7,1,3], val 2 输出&#xff1…

[计算机图形学]材质与外观(前瞻预习/复习回顾)

一、图形学中的材质 不同的物体表面有着不同的材质&#xff0c;而不同的材质意味着它们与光线的作用不同。那么我们之前在介绍辐射度量学和渲染方程提到过其中一个函数&#xff0c;叫做BRDF&#xff0c;而在实际上&#xff0c;也就是BRDF定义了不同的材质。BRDF决定了光如何被反…

JavaScript经典教程(七)-- JavaScript基础 -- 函数、argument、匿名函数、函数深入、选项卡

188&#xff1a;JavaScript基础 - 函数、argument、匿名函数、函数深入、选项卡 1、函数 &#xff08;1&#xff09;特性 1、每个函数都有自己的作用域。 2、如果执行该变量名&#xff0c;会返回自己&#xff0c;即返回函数本身。 3、正常调用&#xff0c;返回函数中的执…

软件STM32cubeIDE下STM32F1xx使用定时器(TIM8)+DMA+PWM点亮灯带WS2812-基础样例

软件STM32cubeIDE下STM32F1xx使用定时器&#xff08;TIM8&#xff09;DMAPWM点亮灯带WS2812-基础样例 &#xff08;1&#xff09;前言&#xff08;2&#xff09;环境说明&#xff08;3&#xff09;先行了解本次调到坑里的两个点问题点&#xff08;1&#xff09;TIM3_ch2,在STM3…

真题详解(极限编程)-软件设计(六十一)

真题详解&#xff08;二分查找平均值&#xff09;-软件设计&#xff08;六十)https://blog.csdn.net/ke1ying/article/details/130417464 VLANtag属于 数据链路层实现。 数据链路层&#xff1a;网桥交换机。 网络层&#xff1a;路由器。 物理层&#xff1a;中继器。 Telent…

1694_week1_MIT使用Python编程学习手记1

全部学习汇总&#xff1a; GreyZhang/python_basic: My learning notes about python. (github.com) 首先说明一下&#xff0c;这部分信息的整理只是我个人的理解。由于自己的知识功底以及英语水准&#xff0c;很可能会有大量的疏漏。再此&#xff0c;我只想把自己学习时候的一…

Linux进程通信:信号 信号集 信号集函数

1. 信号的概念 Linux进程间通信的方式之一。信号也称为“软件中断”。 信号特点&#xff1a; 简单&#xff1b;携带信息有限&#xff1b;满足特定条件才发送信号&#xff1b;可进行用户空间和内核空间进程的交互&#xff1b; 信号4要素&#xff1a; &#xff08;1&#xf…

抓马,互联网惊现AI鬼城:上万个AI发帖聊天,互相嗨聊,人类被禁言

近日又有一个社区迷惑走红 上万个AI发帖聊天&#xff0c;人类不得入内&#xff1f; 据红星新闻报道 近日&#xff0c;一个名为Chirper的AI网络社区突然爆火 上万个AI聊天机器人在其中 激烈地聊天、互动、分享 社区主页右上角明确写着&#xff1a; “这是一个人工智能的社交…

《斯坦福数据挖掘教程·第三版》读书笔记(英文版) Chapter 1 Data Mining

来源&#xff1a;《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT Chapter 1 Data Mining Now, statisticians view data mining as the construction of a statistical model, that is, an underlying distribution from which the visible data is drawn. However, ma…

docker上部署程序后无法连接数据库的问题

咱就是说&#xff0c;这个问题差点给我劝退docker。下面说下环境情况。 装了个javaweb程序容器&#xff0c;装了个数据库容器&#xff0c;javaweb容器就是链接不上数据库。 咱也是跟着菜鸟教程的容器互联步骤简历网络链接&#xff1a; 并且启动时增加--networkxxx 都加入到了…

socket通信之select

多线程版本的的socket的server端 #include "socket.hpp" #include <iostream> #include <string> #include <memory>DWORD WINAPI threadProc(LPVOID lp) {SOCKET sClient *(SOCKET*)(lp);while (true) {char buff[1024] { 0 };int result rec…

数据结构初阶 —— 树(堆)

目录 一&#xff0c;堆 堆的概念 向下调整法&#xff08;数组&#xff09; 向上调整法&#xff08;数组&#xff09; 堆的创建&#xff08;建堆&#xff09; 堆的实现 一&#xff0c;堆 堆的概念 如有个关键码的集合K{&#xff0c;&#xff0c;&#xff0c;...&#xf…

Anaconda你不得不知道的若干知识点

Anaconda你不得不知道的若干知识点 1. 查看所有的环境变量2. 加载tensorflow在jupyter中会挂掉怎么办&#xff1f;3. Excel xlsx file&#xff1b; not supported两种解决办法4. (unicode error)5. 统计pandas二维表中的某列的重复值法一&#xff1a;df.loc[:,col_name].value_…

Fabric测试与基础

Fabric官网:Introduction — hyperledger-fabricdocs main documentation 1.测试网络 ./network.sh up #启动./network.sh down #关闭 2.Fabric核心模块 peer:主节点模块&#xff0c;负责存储区块链数据&#xff0c;运行维护链码 orderer:交易打包、排序模块 cryptogen:组织…

【机器学习分支】重要性采样(Importance sampling)学习笔记

重要性采样&#xff08;importance sampling&#xff09;是一种用于估计概率密度函数期望值的常用蒙特卡罗积分方法。其基本思想是利用一个已知的概率密度函数来生成样本&#xff0c;从而近似计算另一个概率密度函数的期望值。 想从复杂概率分布中采样的一个主要原因是能够使用…

uniapp 抖音授权登录、发布、分享 Ba-Aweme

简介&#xff08;下载地址&#xff09; Ba-Aweme 是一个集成抖音的uniapp插件&#xff0c;支持抖音授权登录&#xff0c;发布图片、视频&#xff0c;分享到联系人群组&#xff0c;直接拍摄等。自带选择图片和选择视频方法。 注意&#xff1a; 使用前&#xff0c;先到抖音开放…

LabVIEW CompactRIO 开发指南 3 选择CompactRIO编程模式

第二章 选择CompactRIO编程模式 第一章中介绍的CompactRIO架构为我们提供了通过LabVIEW FPGA定制FPGA硬件或使用NI CompactRIO扫描模式来实现I/O的选项。如果计算机上有LabVIEW Real-Time和LabVIEW FPGA&#xff0c;那么当向LabVIEW项目添加CompactRIO目标时&#xff0c;将提…