android核心架构Framework组件介绍

news2024/11/25 4:55:54

作为一个android开发者,核心架构是必须要了解的。只有了解每个核心层的作用,才能更深入的理解和学习。本篇主要讲解Java Framework层核心代码流程。

文章目录

    • 一,Android系统架构
    • 1.System Apps
    • 2.Java Framework
    • 3.系统运行库层
    • 4.硬件抽象层(Hardware Abstraction Layer)
    • 5.Linux Kernel
    • 二,系统启动架构
    • 1.Loader层
    • 2.Linux内核层
    • 3.硬件抽象层 (HAL)
    • 4. Android Runtime & 系统库
    • 5.Framework层
    • 6.App层
    • 三,Java Framework详解
    • 1,ActivityManager
    • 2,WindowManager
    • 3,PackageManager
    • 4,InputManagerService

一,Android系统架构

这是官方提供的架构图,由于内核是基于Linux,只需要了解底层的一些作用就行。
在这里插入图片描述

1.System Apps

系统应用层,也就是应用层,不只是系统自带的应用(Dialer:拨号器,Email:邮件,Camera:相机,Calendar:日历等),还有广大的android应用层开发者开发的第三方应用:比如支付宝,微信,qq等。

2.Java Framework

android开发核心层,提供丰富的API给开发者。

  • ActivityManagerService: 管理着android的四大组件;统一调度各应用进程。
  • WindowManagerService: 控制窗口的显示、隐藏以及窗口的层序,大多数情况和View有关系的都要和它打交道。
  • Content Providers: 可以让一个应用访问另一个应用的数据,共享他们的数据。
  • 视图系统(View System): 丰富且可拓展,包括:列表(lists),网络(grids),文本框(text boxes),按钮(buttons)等等。
  • Notification Manager: 可以在"状态栏中"显示自定义的提示信息。
  • Package Manger: 对Android系统内的程序管理。
  • Telephony Manager: 主要提供了一系列用于访问与手机通讯相关的状态和信息的方法,查询电信网络状态信息,sim卡的信息等。
  • Resource Manager: 提供非代码资源的访问,如本地字符串,图形,和布局文件。
  • Location Manager: 提供设备的地址位置的获取方式。很显然,GPS导航肯定能用到位置服务。

3.系统运行库层

Native C/C++ Libraries:C/C++程序库,许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。例如,您可以通过 Android 框架的 Java OpenGL API 访问 OpenGL ES,以支持在应用中绘制和操作 2D 和 3D 图形。

如果开发的是需要 C 或 C++ 代码的应用,可以使用 Android NDK 直接从原生代码访问某些原生平台库。也可以利用一些.a静态库和.so动态库,NdK和Jni的开发,C和C++平台的代码移植等都需要动这层代码,编译。

Android Runtime:运行时库 , Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。它可以支持已转换为.dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。(dx 是一套工具,可以将 Java .class 转换成 .dex 格式. 一个dex档通常会有多个.class。由于dex有时必须进行最佳化,会使档案大小增加1-4倍,以ODEX结尾。)然而Dalvik VM 效率并不是最高的。从 Android 4.4 开始,Google 开发者引进了新的 Android 运行环境 ART(意思就是 Android Runtime。Android 官方页面的介绍中,也将其称作新的虚拟机),以替代旧的 Dalvik VM。Android 5.0之后就彻底的代替了。ART 的机制与 Dalvik 不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译(AOT,Ahead-Of-Time)。这样的话,应用的启动(首次)和执行都会变得更加快速。代价就是安装会慢。里面有 预先 (AOT) 和即时 (JIT) 编译,优化的垃圾回收 (GC),更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置监视点以监控特定字段,Android Runtime Excepiton 就出自这里。

4.硬件抽象层(Hardware Abstraction Layer)

硬件抽象层 (HAL) 提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个库模块,其中每个模块都为特定类型的硬件组件实现一个界面,例如:Audio音频模块,BlueTooth:蓝牙模块,Camera:相机模块,Sensors:传感器。系统内置对传感器的支持达13种,他们分别是:加速度传感器(accelerometer)、磁力传感器(magnetic field)、方向传感器(orientation)、陀螺仪(gyroscope)、环境光照传感器(light)、压力传感器(pressure)、温度传感器(temperature)和距离传感器(proximity)等。当框架 API 要求访问设备硬件时,Android 系统将为该硬件组件加载库模块。厂商会在这层定义自己的HAL接口。

5.Linux Kernel

Android依赖于Linux2.6内核提高的高核心系统服务,例如安全,内存管理,进程管理,网络斎等等方面内容。内核作为一个抽象层,存在与硬件层和软件层之间。android对Linux下面内容做了增强。有下面这些驱动(Audio,IPC,Display,BlueTooth,Camera,USB)。

最后形成思维导图方便记忆

请添加图片描述

二,系统启动架构

在这里插入图片描述

Android系统启动过程由上图从下往上的一个过程,Boot Loader -> Kernel -> Native -> Framework -> App。

1.Loader层

Boot ROM: 当手机处于关机状态时,长按Power键开机,引导芯片开始从固化在ROM里的预设代码开始执行,然后加载引导程序到RAM;Boot Loader:这是启动Android系统之前的引导程序,主要是检查RAM,初始化硬件参数等功能。

2.Linux内核层

启动Kernel的swapper进程(pid=0):该进程又称为idle进程,系统初始化过程Kernel由无到有开创的第一个进程,,用于初始化进程管理、内存管理,加载Display,Camera Driver,Binder Driver等相关工作;启动kthreadd进程(pid=2):是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等内核守护进程。kthreadd进程是所有内核进程的鼻祖。

3.硬件抽象层 (HAL)

硬件抽象层 (HAL) 提供标准接口,HAL包含多个库模块,其中每个模块都为特定类型的硬件组件实现一组接口,比如WIFI/蓝牙模块,当框架API请求访问设备硬件时,Android系统将为该硬件加载相应的库模块。

4. Android Runtime & 系统库

每个应用都在其自己的进程中运行,都有自己的虚拟机实例。ART通过执行DEX文件可在设备运行多个虚拟机,DEX文件是一种专为Android设计的字节码格式文件,经过优化,使用内存很少。

ART主要功能包括:预先(AOT)和即时(JIT)编译,优化的垃圾回收(GC),以及调试相关的支持。

这里的Native系统库主要包括init孵化来的用户空间的守护进程、HAL层以及开机动画等。启动init进程(pid=1),是Linux系统的用户进程,init进程是所有用户进程的鼻祖。

init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程;init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务;init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程),Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的。

5.Framework层

Zygote进程,是由init进程通过解析init.rc文件后fork生成的,Zygote进程主要包含:加载ZygoteInit类,注册Zygote Socket服务端套接字,加载虚拟机,提前加载类preloadClasses,提前加载资源preloadResouces。

System Server进程,是由Zygote进程fork而来的第一个进程,System Server负责启动和管理整个Java framework,包含ActivityManager,WindowManager,PackageManager,PowerManager等服务。 Media Server进程,是由init进程fork而来,负责启动和管理整个C++ framework,包含AudioFlinger,Camera Service等服务。

6.App层

Zygote进程孵化出的第一个App进程是Launcher,这是用户看到的桌面App;Zygote进程还会创建Browser,Phone,Email等App进程,每个App至少运行在一个进程上。所有的App进程都是由Zygote进程fork生成的。

三,Java Framework详解

不管是做系统开发,还是应用开发Framework都需要有所了解。虽然应用开发不涉及Framework层的定制和修改,但原理也要知道,知其然也要知其所以然。

1,ActivityManager

ActivityManager是对Activity管理、运行时功能管理和运行时数据结构的封装,进程(Process)、应用程序/包、服务(Service)、任务(Task)信息等。

但是这些信息真正维护并不是ActivityManager来负责的,从其中的众多接口getXXX()可以看到其中都是使用:ActivityManagerNative.getDefault()的操作来实现这些信息的获取。

  • ActivityManager.MemoryInfo: 系统可用内存信息。
  • ActivityManager.RecentTaskInfo: 最近的任务信息。
  • ActivityManager.RunningAppProcessInfo: 正在运行的进程信息。
  • ActivityManager.RunningServiceInfo: 正在运行的服务信息。
  • ActivityManager.RunningTaskInfo: 正在运行的任务信息。

类图如下:

在这里插入图片描述
IActivityManager作为ActivityManagerProxy和ActivityManagerNative的公共接口,所以两个类具有部分相同的接口,可以实现合理的代理模式;ActivityManagerProxy代理类是ActivityManagerNative的内部类;ActivityManagerNative是个抽象类,真正发挥作用的是它的子类ActivityManagerService。

ActivityManager在应用进程中,所有的Manager都在应用进程,而ActivityManagerService运行在系统进程中(system_server)。

ActivityManager通过代理ActivityManagerProxy实现与ActivityManagerService通信,流程如下:

    @Deprecated
    public List<RunningServiceInfo> getRunningServices(int maxNum)
            throws SecurityException {
        try {
            return getService()
                    .getServices(maxNum, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @UnsupportedAppUsage
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

从上边源码中可以看出,ServiceManager.getService(“activity”),获取系统的“activity”的Service,所有的Service都是注册到ServiceManager进行统一管理。这样就创建了一个对ActivityManagerService实例的本地代理对象ActivityManagerProxy实例。

ActivityManagerService

AMS负责管理着android的四大组件;统一调度各应用进程。

AMS在SystemServer中启动

private void run(){
    ......
    try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        } catch (Throwable ex) {
            throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    ......
}

private void startBootstrapServices() {
        Installer installer = mSystemServiceManager.startService(Installer.class);
       
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
    
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
       
        mActivityManagerService.setInstaller(installer);
      
        mActivityManagerService.setSystemProcess();
    }

mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class)这个方法主要是创建ActivityManagerService.Lifecycle对象并调用Lifecycle.onStart方法

public static final class Lifecycle extends SystemService {
        private final ActivityManagerService mService;

        public Lifecycle(Context context) {
            super(context);
            //真正创建AMS
            mService = new ActivityManagerService(context);
        }

        @Override
        public void onStart() {
            mService.start();
        }

        public ActivityManagerService getService() {
            return mService;
        }
    }

AMS创建了三个线程

public ActivityManagerService(Context systemContext) {
        mContext = systemContext;
        mFactoryTest = FactoryTest.getMode();
        mSystemThread = ActivityThread.currentActivityThread();
        //创建一个前台线程并获取mHandler
        mHandlerThread = new ServiceThread(TAG,
                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
        mHandlerThread.start();
        mHandler = new MainHandler(mHandlerThread.getLooper());
        //创建一个UI线程,这个线程主要处理跟ams内部发出的需要进行ui处理的事件
        mUiHandler = new UiHandler();
        ......

}

当调用startActivityForResult

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
        
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
        } else {
            ......
        }
    }


    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    ActivityResult result = null;
                    if (am.ignoreMatchingSpecificIntents()) {
                        if (options == null) {
                            options = ActivityOptions.makeBasic().toBundle();
                        }
                        result = am.onStartActivity(who, intent, options);
                    }
                    if (result != null) {
                        am.mHits++;
                        return result;
                    } else if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData(who);
            intent.prepareToLeaveProcess(who);
            //通过Binder通信最终在AMS中执行
            int result = ActivityTaskManager.getService().startActivity(whoThread,
                    who.getOpPackageName(), who.getAttributionTag(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                    target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);   
            //检查activity是否启动
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

在AMS中的调用


    /**
     * @deprecated use {@link #startActivityWithFeature} instead
     */
    @Deprecated
    @Override
    public int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return mActivityTaskManager.startActivity(caller, callingPackage, null, intent,
                resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions);
    }

在ActivityTaskManager调用

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
            Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

2,WindowManager

android的窗口分为三种:

  • 应用程序窗口 (Application Window): 包括所有应用程序自己创建的窗口,以及在应用起来之前系统负责显示的窗口。
  • 子窗口(Sub Window):比如应用自定义的对话框,或者输入法窗口,子窗口必须依附于某个应用窗口(设置相同的token)。
  • 系统窗口(System Window): 系统设计的,不依附于任何应用的窗口,比如说,状态栏(Status Bar),
    导航栏(Navigation Bar), 壁纸(Wallpaper), 来电显示窗口(Phone),锁屏窗口(KeyGuard),
    信息提示窗口(Toast), 音量调整窗口,鼠标光标等等。

核心实现类是WindowManagerImpl

    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

mGlobal是WindowManagerGlobal:

public final class WindowManagerImpl implements WindowManager {
    @UnsupportedAppUsage
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ...
}

WindowManager操作Window,不过具体的实现细节还是WindowManagerGlobal这个类来做的,这个类是一个单例模式。

继续看下WindowManagerGlobal.java的addView函数:

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ……

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            // 界面布局的限制
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
             ……
            // 构建界面控制
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            try {
                //将View显示到手机窗口
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

其中创建了ViewRootImpl

ViewRootImpl 是一个视图层次结构的顶部,ViewRootImpl 实现了 View 与 WindowManager 之间所需要的协议,作为 WindowManagerGlobal 中大部分的内部实现。

在 WindowManagerGlobal 中实现方法中,都可以见到 ViewRootImpl,也就说 WindowManagerGlobal 方法最后还是调用到了 ViewRootImpl。

比如addView,removeView,update 的调用顺序:WindowManagerImpl -> WindowManagerGlobal -> ViewRootImpl。

而且WindowManager.java 是继承的ViewManager。

在这里插入图片描述

WindowManagerService

3,PackageManager

4,InputManagerService

InputManagerService是事件输入的关键组件,在system_process进程中。通过socket通信与客户端进行交互。

在这里插入图片描述Linux内核: 接受输入设备的中断,并将原始事件的数据写入设备节点中设备接电,作为内核与 IMS 的桥梁,将原始事 件的数据暴露给用户空间,以便 IMS 可以从中读取事件;

InputManagerService: 一个 Android 系统服务,分为 Java 层和 Native 层两部分,Java 层负责与 WMS 通信,而 Native 层则是 InputReader 和 InputDispatcher 两个输入系统关键组件的运行容器;

EventHub: 直接访问所有的设备节点,通过一个名为 getEvents() 的函数将所有输入系统相关的待处理的底层事件返回给使用者,包括原始输入事件,设备节点的增删等;

InputReader: IMS 中的关键组件之一,它运行在一个独立的线程中,负责管理输入设备的列表和配置,以及进行输入事件的加工处理,它通过其线程循环不断地通过 getEvents() 函数从 EventHub 中将事件取出并进行处理,对于设备节点的增删事件,它会更新输入设备列表与配置;对于原始输入事件,InputReader对其进行翻译,组装,封装为包含更多信息,更多可读性的输入事件,然后交给InputDispatcher进行派发;

InputReaderPolicy: 为 InputReader 的事件加工处理提供一些策略配置

InputDispatcher: 是 IMS 中的另一个关键组件,运行于一个独立的线程中,InputDispatcher 中保管来自 WMS 的所有窗口的信息,收到 InputReader 的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口;

InputDispatcherPolicy: 为 InputDispatcher 的派发过程提供策略控制,例如 HOME 键被 InputDispatcherPolicy 截取到 PhoneWindowManager 中处理,并阻止窗口收到 HOME 键按下的事件;

WindowManagerService: 它并不是输入系统的一员,新建窗口时,WMS 为新窗口和 IMS 创建了事件传递所用的通道,会将窗口的可点击区域,焦点窗口等信息实时更新到 IMS 的 InputDispatcher 中,使得 InputDispatcher 可以正确将事件派发到指定窗口;

ViewRootImpl: 对某些窗口,如壁纸窗口,SurfaceView 的窗口来说,窗口就是输入事件派发的终点,而对其他的如Activity,对话框等使用了 Android 控件系统的窗口来说,输入事件的终点是控件。

点击屏幕执行过程

InputManagerService的Read线程捕获事件,预处理后发送给Dispatcher线程

Dispatcher找到目标窗口

通过Socket将事件发送到目标窗口

APP端被唤醒

找到目标窗口处理事件

在这里插入图片描述

为什么InputManagerService和APP通信使用Socket而不是Binder

  • Binder本身是CS结构的,经常用于SystemServer 中不同的Service间通信,或则是由App作为Client调用Service
    (如AMS)的情况,整体的方式很像是Http,即一个请求对应一个响应。而Input子系统的事件传递机制和CS架构的调用逻辑完全不一样,它是由底层出发,由Service发起像Client进行通知的,而且会有连续的多个事件以及要分发到多个App,整体和“请求-响应”结构完全不一致,用Binder实现逻辑较为复杂。
  • Input系统的事件分发需要双向通信,Server -> App分发,App-> Server通知分发结果,而Binder做双向通信也不太方便。
  • 尽管Binder性能较为优秀,不过它的性能优势主要在于数据传递少一次Copy,而在Input系统中所传递的都是一些事件,事件本身的数据量都是比较小的,所以这个内存Copy的性能优势本身也不太明显。

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

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

相关文章

Matplotlib库的简单用法

Matplotlib库的简单用法 Matplotlib是python科学计算中最基础、最重要的绘图库&#xff0c;是Python中最流行的数据可视化库之一&#xff0c;它提供了大量的绘图函数和工具&#xff0c;可以让用户创建各种类型的图表和图形&#xff0c;一般使用matpltlib完全可以满足我们绘图需…

“成功学大师”杨涛鸣被抓

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 4月15日&#xff0c;号称帮助一百多位草根开上劳斯莱斯&#xff0c;“成功学大师”杨涛鸣机其团队30多人已被刑事拘留&#xff0c;培训课程涉嫌精神传销&#xff0c;警方以诈骗案进行立案调查。 …

基于4412的dm9000驱动移植

1 概述 以太网高速稳定的特性比Wifi无线传输有一定的优势&#xff0c;当无线传输无法满足一些智能设备&#xff0c;需要开发设计以太网模块。Linux支持以太网系统&#xff0c;结合4412开发板&#xff0c;重点学习dm9000驱动的设计与实现。 2 硬件资源分析 2.1 4412开发板以太网…

【Python】Python中的列表,元组,字典

文章目录列表创建列表获取元素修改元素添加元素查找元素删除元素列表拼接遍历列表切片操作元组创建元组元组中的操作字典创建字典添加/修改元素删除元素查找字典的遍历合法的key类型列表 列表是一种批量保存数据的方式&#xff0c;列表使用[]表示 创建列表 创建两个空列表 …

nginx优化及配置

nginx隐藏版本号 查看方法 浏览器F12 看network头部看server curl -i 192.168.232.7 获取头部&#xff08;查版本号&#xff09; 配置文件改 添加server_tokens off 改源码 cd /src/core vim nginx.h 修改 修改的IIS为window常用的软件服务 重新编译安装 cd nginx_1.2…

【C++】while 循环应用案例 - 猜数字游戏

目录 1、缘起 2、案例描述 3、代码 4、相关知识点 4.1、rand() 函数 4.2、srand() 函数 5、总结 1、缘起 猜数字游戏是一种简单而又有趣的游戏&#xff0c;在这个游戏中&#xff0c;计算机会生成一个随机数字&#xff0c;玩家需要通过不断猜测来猜出这个数字。在本篇博…

使用docker搭建lnmp环境+redis服务

lnmp搭建过程&#xff0c;前文已经写了传送门&#xff0c;本文主要写一下运行redis容器和php-fpm容器内安装redis扩展 redis 1.创建宿主机配置和数据文件夹 [rootlocalhost ~] mkdir -p /lnmp/redis/{data,conf}2.放置/lnmp/redis/conf/redis.conf文件 点我下载 3.启动容器 …

k8s+kubeedge+sedna安装全套流程+避坑指南+解决办法

最近在学习边缘计算要用到kubeedge&#xff0c;安装了好多次总会遇到各种各样的问题&#xff0c;因此在这里一一列出&#xff0c;以方便下次安装。则里面可能出错的地方太多&#xff0c;如果有问题&#xff0c;请私信联系。 一、环境准备 节点IP环境软件云端节点172.23.70.23…

Python|矿产卫片Excel经纬度坐标数据转换为shp点数据——OGR库实现

1.实验需求 基于Excel表格里面的经纬度坐标数据,自动生成点shp矢量文件,并添加属性信息。 2.编程思路详解 ①使用Pandas库读取原始矿产图斑列表表格; xlsx_path = uC:\\Users\\YaoJun\\Desktop\\矿产图斑列表.xlsx #sheet_name默认为0,即读取第一个sheet的数据 df = pd.…

TPM管理工作应该如何开展?

在制造行业&#xff0c;Total Productive Maintenance&#xff08;TPM&#xff09;管理被广泛认为是提高生产效率和设备可靠性的有效方式。然而&#xff0c;实施TPM管理需要深入的专业知识和经验。本文将探讨如何开展TPM管理工作&#xff0c;以确保制造企业的生产效率和设备可靠…

2023-Python实现烯牛数据采集

文章目录&#x1f449;1、目标网址&#x1f449;2、接口分析&#x1f449;3、代码实现【JS 逆向百例】 1/100 学习记录&#xff1a;哈喽~ 前面我们接触了一些JS逆向的数据获取&#xff0c;如果前面的百度&#xff0c;有道翻译和正方教务系统的登录加密你已掌握&#xff0c;说明…

计组2.4——加法器的设计

计组&#xff1a;2.4算术逻辑单元异或门实现奇偶校验的原理串行加法器&&并行加法器并行加法器的优化算术逻辑单元 控制信号&#xff1a; 当M0时表示算术运算 当M1时表示逻辑运算 S0~ S3表示做什么运算&#xff0c;因此ALU可以表示16种算数运算和16种逻辑运算 Ai,Bi代表…

PL-VINS线特征处理部分源码阅读

PL-VINS线特征处理部分源码阅读1 linefeature_tracker2 三角化单目三角化双目三角化3 后端优化线特征状态量重投影误差本文主要阅读PL-VINS中引入线特征的代码实现&#xff0c;包括线特征表示方法&#xff08;Plcker参数化方法、正交表示法&#xff09;、前端线特征提取与匹配、…

遥感、GIS及GPS在土壤空间数据分析、适应性评价、制图及土壤普查中的应用

摸清我国当前土壤质量与完善土壤类型&#xff0c;可以为守住耕地红线、保护生态环境、优化农业生产布局、推进农业高质量发展奠定坚实基础&#xff0c;为此&#xff0c;2022年初国务院印发了《关于开展第三次全国土壤普查的通知》&#xff0c;决定自2022年起开展第三次全国土壤…

微信支付,JSAPI支付,APP支付,H5支付,Native支付,小程序支付功能详情以及回调处理

一.支付相关文档地址支付wiki&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml支付api: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/index.shtml开发工具包(SDK)下载&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay6_0.shtm…

靶机精讲之CTF4

主机发现 靶机193 端口扫描 服务扫描 80&#xff0c;25&#xff08;明确版本&#xff09;攻击面更大 web渗透 blog是交互式的程序 发现index可进行手动爆破&#xff08;地址包含&#xff09; http://192.168.10.193/index.html?page../../../../../../../../etc/passwd 无发…

雨水情测报系统+智慧水库大坝安全监测系统

解决方案 雨水情测报系统智慧水库大坝安全监测系统&#xff0c;系统主要由降雨量监测站、水库水位监测站、大坝安全监测中的渗流量、渗流压力和变形监测站及视频和图像监测站等站点组成&#xff0c;同时建立规范、统一的监测平台&#xff0c;集数据传输、信息共享、数据储存于…

Git简单使用~下载、安装、命令行使用、IDEA使用

文章目录一、Git下载二、Git安装三、命令行操作四、IDEA使用gitee4. 查看Gitee仓库一、Git下载 官网下载地址&#xff1a;Git (git-scm.com) 点击"Download for Windows"&#xff0c;跳转至详细下载页面。 以Windows64位安装版为例&#xff0c;点击"64-bit…

代码随想录算法训练营第42天| 416. 分割等和子集

代码随想录算法训练营第42天| 416. 分割等和子集416. 分割等和子集416. 分割等和子集 题目链接&#xff1a;416. 分割等和子集&#xff0c;难度&#xff1a;中等 【实现代码】 class Solution { public:bool canPartition(vector<int>& nums) {int sum 0;for (int…

抢鲜发布:Flutter 3.7更新详解

本文首发自「慕课网」(imooc.com)&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;CrazyCodeBoy|慕课网讲师 新年伊始&#xff0c;由 Flutter 3.7 正式版来「打头阵」&#xff01;我们与整个…