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

Android Framework底层原理之WMS的启动流程

一 概述

今天,我们介绍 WindowManagerService(后续简称 WMS)的启动流程,WMS 是 Android 系统中,负责窗口显示的的服务。在 Android 中它也起着承上启下的作用。

如下图,就是《深入理解 Android》书籍中的一张图。

图中展示了,WMS 在 Android 系统的地位,它作为中间层,连接了上层的 View 框架和下层的 SurfaceFingler。了解了 WMS 的工作机制,我们就彻底打通了上层 VIew 到底层 Surface,甚至到显示器如何显示的逻辑。

接下来,我们依旧从 WMS 的启动开始,来看 WMS 是如何启动的。

二 从 SystemServer 开始

2.1 startOtherServices

[frameworks/base/services/java/com/android/server/SystemServer.java]
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {WindowManagerService wm = null;// 这里传入的 PhoneWindowManager 就是 WMS 中的 WindowManagerPolicywm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);// 将 WMS 设置到 AMS 中mActivityManagerService.setWindowManager(wm);wm.onInitReady();...try {wm.displayReady();} catch (Throwable e) {reportWtf("making display ready", e);}...try {wm.systemReady();} catch (Throwable e) {reportWtf("making Window Manager Service ready", e);}...// 更新上下文中,关于显示窗口相关的属性final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);DisplayMetrics metrics = new DisplayMetrics();context.getDisplay().getMetrics(metrics);context.getResources().updateConfiguration(config, metrics);}

和 AMS 不同的是,WMS 的启动是在 SystemServer 的 startOtherServices 中,启动过程依旧是我们之前提过的构造、注册,只是少了 onStart 这个步骤。

并且,在 WMS 启动之后,还会陆续调用一些其他的函数

  • onInitReady
  • displayReady
  • systemReady
  • updateConfiguration

接下来,我们会根据 WMS 启动过程中调用的函数,以此查看它们具体的实现原理。

从 AMS 和 WMS 的启动,我们可以看出来,它们都是隶属于 SystemServer 进程的,根据之前我们对应用和 AMS 的了解,也经常看到它们交互的流程中,有 WMS 的身影,所以虽然说是应用和 AMS,WMS 的通信,实际上就是应用和 SystemServer 进程的通信。

2.2 main

[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm) {return main(context, im, showBootMsgs, onlyCore, policy, atm,new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,SurfaceControl.Builder::new);
}public static WindowManagerService main(final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, DisplayWindowSettingsProviderdisplayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {DisplayThread.getHandler().runWithScissors(() ->sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,surfaceControlFactory), 0);return sInstance;
}

在 WMS 的 main 函数中主要做了两件事

  1. 创建了一个 WMS 对象
  2. 将这个 WMS 对象传递给了 DisplayThread

我们首先看这个 WMS 对象的构造函数

三 WindowManagerService

3.1 WMS 的构造函数

private WindowManagerService(Context context, InputManagerService inputManager,boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,ActivityTaskManagerService atm, DisplayWindowSettingsProviderdisplayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory,Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {installLock(this, INDEX_WINDOW);// ActivityTaskManagerServicemGlobalLock = atm.getGlobalLock();mAtmService = atm;mContext = context;mIsPc = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);mAllowBootMessages = showBootMsgs;...// 输入法管理mInputManager = inputManager; // Must be before createDisplayContentLocked.// 显示管理mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);// Surface 图像相关mSurfaceControlFactory = surfaceControlFactory;mTransactionFactory = transactionFactory;mSurfaceFactory = surfaceFactory;mTransaction = mTransactionFactory.get();mPolicy = policy;// 窗口动画mAnimator = new WindowAnimator(this);// 根窗口容器mRoot = new RootWindowContainer(this);final ContentResolver resolver = context.getContentResolver();mUseBLAST = Settings.Global.getInt(resolver,Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR, 1) == 1;mSyncEngine = new BLASTSyncEngine(this);mWindowPlacerLocked = new WindowSurfacePlacer(this);mTaskSnapshotController = new TaskSnapshotController(this);mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,Choreographer.getInstance());LocalServices.addService(WindowManagerPolicy.class, mPolicy);mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);mKeyguardDisableHandler = KeyguardDisableHandler.create(mContext, mPolicy, mH);mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);if (mPowerManagerInternal != null) {mPowerManagerInternal.registerLowPowerModeObserver(new PowerManagerInternal.LowPowerModeListener() {@Overridepublic int getServiceType() {return ServiceType.ANIMATION;}@Overridepublic void onLowPowerModeChanged(PowerSaveState result) {synchronized (mGlobalLock) {final boolean enabled = result.batterySaverEnabled;if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {mAnimationsDisabled = enabled;dispatchNewAnimatorScaleLocked(null);}}}});mAnimationsDisabled = mPowerManagerInternal.getLowPowerState(ServiceType.ANIMATION).batterySaverEnabled;}mScreenFrozenLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");mScreenFrozenLock.setReferenceCounted(false);mDisplayNotificationController = new DisplayWindowListenerController(this);// AMS 相关mActivityManager = ActivityManager.getService();mActivityTaskManager = ActivityTaskManager.getService();mAmInternal = LocalServices.getService(ActivityManagerInternal.class);mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);... 
}

WMS 的构造函数的代码非常长,其中有包含各种服务,我们这里只关注和我们应用 Activity 相关的,还有和显示相关的窗口容器 RootWindowContainer,还有和刷新相关的 Surface

3.2 runWithScissors

另外,在 main 函数中,还调用了一个 runWithScissors,这个函数是 Handler 中定义的函数,这里我们简单看一下。

public final boolean runWithScissors(@NonNull Runnable r, long timeout) {if (r == null) {throw new IllegalArgumentException("runnable must not be null");}if (timeout < 0) {throw new IllegalArgumentException("timeout must be non-negative");}if (Looper.myLooper() == mLooper) {r.run();return true;}BlockingRunnable br = new BlockingRunnable(r);return br.postAndWait(this, timeout);
}

runWithScissors 是 Handler 中的函数,用一句话概括就是,如果发送消息的线程与 Handler 处理的线程相同,就直接调用。如果不同,就阻塞调用

3.3 onInitReady

public void onInitReady() {initPolicy();// Add ourself to the Watchdog monitors.Watchdog.getInstance().addMonitor(this);createWatermark();showEmulatorDisplayOverlayIfNeeded();
}

3.4 initPolicy

private void initPolicy() {UiThread.getHandler().runWithScissors(new Runnable() {@Overridepublic void run() {WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());// mPolicy 其实就是 PhoneWindowManager【5.1】mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);}}, 0);
}

mPolicy 其实是 PhoneWindowManager,runWithScissors 前面介绍过了,如果是当前线程,就直接运行,如果不是当前线程,就阻塞运行。

所以这里是在 android.ui 线程中,运行 mPolicy 的初始化逻辑

3.5 createWatermark

void createWatermark() {if (mWatermark != null) {return;}File file = new File("/system/etc/setup.conf");FileInputStream in = null;DataInputStream ind = null;try {in = new FileInputStream(file);ind = new DataInputStream(in);String line = ind.readLine();if (line != null) {String[] toks = line.split("%");if (toks != null && toks.length > 0) {// TODO(multi-display): Show watermarks on secondary displays.final DisplayContent displayContent = getDefaultDisplayContentLocked();mWatermark = new Watermark(displayContent, displayContent.mRealDisplayMetrics,toks, mTransaction);mTransaction.apply();}}} ...
}

createWatermark 创建系统水印(只能显示文字)。

3.6 displayReady

[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public void displayReady() {synchronized (mGlobalLock) {if (mMaxUiWidth > 0) {mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));}applyForcedPropertiesForDefaultDisplay();mAnimator.ready();mDisplayReady = true;// createWatermark重新配置所有显示器大小mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);// 是否触屏mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);}try {// ATMSmActivityTaskManager.updateConfiguration(null);} catch (RemoteException e) {}
}

displayReady 就是初始化显示器大小。

3.7 systemReady

[frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java]
public void systemReady() {mSystemReady = true;// 调用 PhoneWindowManager 的 systemReadymPolicy.systemReady();// 调用 DisplayPolicy 的 systemReadymRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);// 调用 TaskSnapshotController 的 systemReadymTaskSnapshotController.systemReady();mHasWideColorGamutSupport = queryWideColorGamutSupport();mHasHdrSupport = queryHdrSupport();// 加载系统设置UiThread.getHandler().post(mSettingsObserver::loadSettings);// VRIVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(Context.VR_SERVICE));if (vrManager != null) {try {final boolean vrModeEnabled = vrManager.getVrModeState();synchronized (mGlobalLock) {vrManager.registerListener(mVrStateCallbacks);if (vrModeEnabled) {mVrModeEnabled = vrModeEnabled;mVrStateCallbacks.onVrStateChanged(vrModeEnabled);}}} catch (RemoteException e) {// Ignore, we cannot do anything if we failed to register VR mode listener}}
}

3.8 computeNewConfiguration

public Configuration computeNewConfiguration(int displayId) {synchronized (mGlobalLock) {return computeNewConfigurationLocked(displayId);}
}

3.9 computeNewConfigurationLocked

private Configuration computeNewConfigurationLocked(int displayId) {if (!mDisplayReady) {return null;}final Configuration config = new Configuration();final DisplayContent displayContent = mRoot.getDisplayContent(displayId);displayContent.computeScreenConfiguration(config);return config;
}

displayId 表示的是显示设备的 id,这两段代码,就是通过 mRoot(RootWindowContainer)获取显示指定设备的 DisplayContent。说人话就是,通过显示器的 id,获取显示器对应的实例类 DisplayContent

四 DisplayThread

[frameworks/base/services/core/java/com/android/server/DisplayThread.java]
public final class DisplayThread extends ServiceThread {private static DisplayThread sInstance;private static Handler sHandler;private DisplayThread() {// DisplayThread 运行重要的东西,但 AnimationThread 更重要。因此,优先级设置为 THREAD_PRIORITY_DISPLAY + 1// THREAD_PRIORITY_DISPLAY 的值为 -4,super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);}

DisplayThread 就是 Android 中的 android.display 线程,它的优先级为 THREAD_PRIORITY_DISPLAY + 1,THREAD_PRIORITY_DISPLAY 值为 -4,所以 android.display 线程的优先级是 -3。

再回到 【2.2】中,WMS 的 main 函数是通过 android.display 线程完成的,并且在 android.display 线程中,对 android.ui 线程进行了初始化。

五 UIThread

public final class UiThread extends ServiceThread {private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;private static UiThread sInstance;private static Handler sHandler;private UiThread() {super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);}@Overridepublic void run() {// Make sure UiThread is in the fg stune boost groupProcess.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);super.run();}

UiThread 和 DisplayThread 一样,也是继承自 ServiceThread,它的线程名是 android.ui,优先级是 THREAD_PRIORITY_FOREGROUND,值为-2,所以 android.ui 线程的优先级是 -2。

六 PhoneWindowManager

PhoneWindowManager 是 WindowManagerPolicy 的实现类,它定义了手机窗口、处理输入事件以及与系统 UI 交互的策略和行为。

PhoneWindowManager 中的函数有很多,这里我们列举一个,其中的按键分发的函数 interceptKeyBeforeQueueing。

6.1 interceptKeyBeforeQueueing

[frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java]
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {final int keyCode = event.getKeyCode();final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0|| event.isWakeKey();if (!mSystemBooted) {// 系统启动前,只监听电源按键if (down && (keyCode == KeyEvent.KEYCODE_POWER|| keyCode == KeyEvent.KEYCODE_TV_POWER)) {wakeUpFromPowerKey(event.getDownTime());} else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)&& isWakeKeyWhenScreenOff(keyCode)) {wakeUpFromWakeKey(event);}// 拦截掉电源键return 0;}// interceptKeyBeforeQueueing 主要就是对手机按键的事件拦截,这里我们简单列举几个// 返回键,音量键等等。switch (keyCode) {case KeyEvent.KEYCODE_BACK: {if (down) {mBackKeyHandled = false;} else {if (!hasLongPressOnBackBehavior()) {mBackKeyHandled |= backKeyPress();}// Don't pass back press to app if we've already handled it via long pressif (mBackKeyHandled) {result &= ~ACTION_PASS_TO_USER;}}break;}case KeyEvent.KEYCODE_VOLUME_DOWN:case KeyEvent.KEYCODE_VOLUME_UP:

返回值是一个整型,如果是 0 就表示被拦截,一开始的电源按键我们就看到了,在系统没有启动前,电源按键只能用于系统启动,但是系统启动后,电源按键就可以用于其他的作用了,例如语音助手。

PhoneWindowManager 这个类主要的作用有:

  1. 按键的分发
  2. 窗口的管理

这里我们就不扩展了,后面遇到实际的场景再来说明。

七 总结

WMS 的启动流程比较简单,主要就是启动了两个线程 "android.display""android.ui"

如果你还没有掌握Framework,现在想要在最短的时间里吃透它,可以参考一下《Android Framework核心知识点》,里面内容包含了:Init、Zygote、SystemServer、Binder、Handler、AMS、PMS、Launcher……等知识点记录。

《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的删除过程

《Android Framework学习手册》:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战

相关文章:

Android Framework底层原理之WMS的启动流程

一 概述 今天&#xff0c;我们介绍 WindowManagerService&#xff08;后续简称 WMS&#xff09;的启动流程&#xff0c;WMS 是 Android 系统中&#xff0c;负责窗口显示的的服务。在 Android 中它也起着承上启下的作用。 如下图&#xff0c;就是《深入理解 Android》书籍中的…...

Leaflet入门,Leaflet加载xyz地图,以vue-leaflet插件加载高德地图为例

前言 本章介绍Leaflet使用vue2-leaflet或者vue-leaflet插件方式便捷加载xyz高德地图。 # 效果演示 vue如何使用Leaflet vue2如何使用:《Leaflet入门,如何使用vue2-leaflet实现vue2双向绑定式的使用Leaflet地图,以及初始化后拿到leaflet对象,方便调用leaflet的api》 vue3…...

【ARM Cache 系列文章 8 -- ARM DynamIQ 技术介绍

文章目录 DynamIQ 技术背景DynamIQ技术详解DynamIQ 与 big.LITTLEDynamIQ cluster 分类硬件支持 DynamIQ为什么适合人工智能&#xff1f; DynamIQ 技术背景 2017年3月21日下午&#xff0c;ARM在北京金隅喜来登酒店召开发布会&#xff0c;正式发布了全新的有针对人工智能及机器…...

24届近5年南京大学自动化考研院校分析

今天给大家带来的是南京大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、南京大学 学校简介 南京大学是一所历史悠久、声誉卓著的高等学府。其前身是创建于1902年的三江师范学堂&#xff0c;此后历经两江师范学堂、南京高等师范学校、国立东南大学、国立第四中…...

微信小程序(原生)和uniapp预览电子文件doc/pdf/ppt/excel等

微信小程序原生预览文件 function previewFile(value) {const fileExtName ${value.ext};const randFile new Date().getTime() fileExtName;uni.showLoading({title: 加载中...})wx.downloadFile({url: value.url, // 文件的本身urlfilePath: wx.env.USER_DATA_PATH / r…...

【前端 | CSS】align-items与align-content的区别

align-items 描述 CSS align-items 属性将所有直接子节点上的 align-self 值设置为一个组。align-self 属性设置项目在其包含块中在交叉轴方向上的对齐方式 align-items是针对每一个子项起作用&#xff0c;它的基本单位是每一个子项&#xff0c;在所有情况下都有效果&…...

Go语言入门

Go语言入门 简介 Go是一门由Google开发的开源编程语言&#xff0c;旨在提供高效、可靠和简洁的软件开发工具。Go具有静态类型、垃圾回收、并发性和高效编译的特点&#xff0c;适用于构建可扩展的网络服务和系统工具。本文将介绍Go语言的基础知识和常用功能&#xff0c;并通过…...

Python学习笔记第五十五天(Pandas CSV文件)

Python学习笔记第五十五天 Pandas CSV 文件read_csv()to_string()to_csv() 数据处理head()tail()fillna() info() 后记 Pandas CSV 文件 CSV&#xff08;Comma-Separated Values&#xff0c;逗号分隔值&#xff0c;有时也称为字符分隔值&#xff0c;因为分隔字符也可以不是逗号…...

自然语言处理: 第七章GPT的搭建

自然语言处理: 第七章GPT的搭建 理论基础 在以transformer架构为框架的大模型遍地开花后&#xff0c;大模型的方向基本分成了三类分别是: decoder-only架构 , 其中以GPT系列为代表encoder-only架构&#xff0c;其中以BERT系列为代表encoder-decoder架构&#xff0c;标准的tr…...

【奶奶看了都会】2分钟学会制作最近特火的ikun幻术图

1.效果展示 最近ikun幻术图特别火啊&#xff0c;在网上能找到各种各样的ikun姿势图片&#xff0c;这些图片都是AI绘制的&#xff0c;能和风景完美融合在一起&#xff0c;今天小卷就来教大家怎么做这种图片 先看看图片效果 视频链接&#xff1a; 仿佛见到一位故人&#xff0c;…...

【深度学习】【风格迁移】Zero-shot Image-to-Image Translation

论文&#xff1a;https://arxiv.org/abs/2302.03027 代码&#xff1a;https://github.com/pix2pixzero/pix2pix-zero/tree/main 文章目录 Abstract1. Introduction相关工作3. Method Abstract 大规模文本到图像生成模型展示了它们合成多样且高质量图像的显著能力。然而&#x…...

Day 30 C++ STL 常用算法(上)

文章目录 算法概述常用遍历算法for_each——实现遍历容器函数原型示例 transform——搬运容器到另一个容器中函数原型注意示例 常用查找算法find——查找指定元素函数原型示例 find_if—— 查找符合条件的元素函数原型示例 adjacent_find——查找相邻重复元素函数原型示例 bina…...

MES系统在机器人行业生产管理种的运用

机器人的智能水平也伴随技术的迭代不断攀升。 2021年的春晚舞台上&#xff0c;来自全球领先工业机器人企业abb的全球首款双臂协作机器人yumi&#xff0c;轻松自如地表演了一出写“福”字&#xff0c;赢得了全国观众的赞叹。 在汽车装配领域&#xff0c;一台机器人可以自主完成一…...

Spark(39):Streaming DataFrame 和 Streaming DataSet 输出

目录 0. 相关文章链接 1. 输出的选项 2. 输出模式(output mode) 2.1. Append 模式(默认) 2.2. Complete 模式 2.3. Update 模式 2.4. 输出模式总结 3. 输出接收器(output sink) 3.1. file sink 3.2. kafka sink 3.2.1. 以 Streaming 方式输出数据 3.2.2. 以 batch …...

【云原生】Docker 详解(一):从虚拟机到容器

Docker 详解&#xff08;一&#xff09;&#xff1a;从虚拟机到容器 1.虚拟化 要解释清楚 Docker&#xff0c;首先要解释清楚 容器&#xff08;Container&#xff09;的概念。要解释容器的话&#xff0c;就需要从操作系统说起。操作系统太底层&#xff0c;细说的话一两本书都说…...

代码随想录第48天 | 198. 打家劫舍、213. 打家劫舍II、337. 打家劫舍III

198. 打家劫舍 当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。 递归五部曲&#xff1a; dp[i]&#xff1a;考虑下标i&#xff08;包括i&#xff09;以内的房屋&#xff0c;最多可以偷窃的金额为dp[i]。决定dp[i]的因素就是第i房间偷还是不偷。 如果偷第i房间&…...

【LeetCode】按摩师

按摩师 题目描述算法分析编程代码 链接: 按摩师 题目描述 算法分析 编程代码 class Solution { public:int massage(vector<int>& nums) {int n nums.size();if(n 0) return 0;vector<int> f(n);auto g f;f[0] nums[0];for(int i 1;i<n;i){f[i] g[i…...

国际腾讯云账号云核算概述!!

云核算概述 维基百科界说&#xff1a;云核算是一种依据互联网的新型核算方法&#xff0c;经过互联网上异构、自治的服务为个人和企业供给按需即取的核算。 云核算描绘的一起特征&#xff1a;云是一种按需运用的服务&#xff0c;运用者只重视服务本身。 云核算作为IT服务形式&am…...

.NET 6.0 重启 IIS 进程池

在 .NET 6.0 中&#xff0c;你可以使用 Microsoft.Web.Administration 命名空间提供的 API 来管理 IIS 进程池并实现重启操作。以下是一个示例代码&#xff0c;展示如何使用 .NET 6.0 中的 Microsoft.Web.Administration 来重启 IIS 进程池&#xff1a; using Microsoft.Web.A…...

一位心理学教师对ChatGPT的看法,提到了正确地使用它的几个要点

在没有自主学习能力和有自主学习能力的两类学生中&#xff0c;ChatGPT的出现&#xff0c;会加大他们在知识学习及思维发展上的鸿沟。爱学习的人会因为AI变得更好…… 从2022年年底起&#xff0c;ChatGPT的技术突破使人类终于进入了一个AI被广泛应用在工作、学习、生活的时代。…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...