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

Android 镜像模式和扩展模式区别探讨-Android14

Android 镜像模式和扩展模式区别探讨

  • 1、区分镜像模式和扩展模式
    • 1.1 扩展屏是否有显示内容
    • 1.2 镜像模式显示条件
  • 2、镜像模式界面

同屏显示和异屏显示探讨

DisplayManagerService启动及主屏添加-Android13
Android主副屏显示-Android14


1、区分镜像模式和扩展模式

LogicalDisplay.java#mHasContent    当前LogicalDisplay是否有内容显示
DisplayContent.java#mLastHasContent  当前DisplayContent是否有内容显示


Android14上默认扩展屏没有显示内容mHasContent=false,扩展屏显示的是主屏DEFAULT_DISPLAY镜像

1.1 扩展屏是否有显示内容

ActivityOptions副屏启动 有Activity启动到扩展屏上,就表示扩展屏上有显示内容,即 mHasContent=true

  • LogicalDisplay.java#mHasContent是由DisplayContent.java#mLastHasContent设置下去的,就是mTmpApplySurfaceChangesTransactionState.displayHasContent
  • RootWindowContainer.java界面刷新时,在mApplySurfaceChangesTransaction中同步,forAllWindows(mApplySurfaceChangesTransaction, true) 当扩展屏没有界面mChildren就会返回 false
  • RootWindowContainer.java#handleNotObscuredLocked 有界面时,界面对应 DisplayContent 是主屏isDefaultDisplay就为 displayHasContent = true; ,而扩展屏界面对应的 DisplayContent 判断主屏不是屏保和锁屏(!mObscureApplicationContentOnSecondaryDisplays)、或者 扩展屏是解锁状态(displayContent.isKeyguardAlwaysUnlocked(),默认无Display.FLAG_ALWAYS_UNLOCKED标志,是未解锁状态,该条件为false)、或者 界面覆盖且为TYPE_KEYGUARD_DIALOG类型((obscured && type == TYPE_KEYGUARD_DIALOG)),某个条件满足就为 displayHasContent = true;

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java#applySurfaceChangesTransaction

mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
if (!inTransition() && !mDisplayRotation.isRotatingSeamlessly()) {mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,mLastHasContent,mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,mTmpApplySurfaceChangesTransactionState.preferredModeId,mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,mTmpApplySurfaceChangesTransactionState.disableHdrConversion,true /* inTraversal, must call performTraversalInTrans... below */);
}
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;final boolean obscuredChanged = w.mObscured !=mTmpApplySurfaceChangesTransactionState.obscured;final RootWindowContainer root = mWmService.mRoot;// Update effect.w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;if (!mTmpApplySurfaceChangesTransactionState.obscured) {final boolean isDisplayed = w.isDisplayed();if (isDisplayed && w.isObscuringDisplay()) {// This window completely covers everything behind it, so we want to leave all// of them as undimmed (for performance reasons).mObscuringWindow = w;mTmpApplySurfaceChangesTransactionState.obscured = true;}final boolean displayHasContent = root.handleNotObscuredLocked(w,mTmpApplySurfaceChangesTransactionState.obscured,mTmpApplySurfaceChangesTransactionState.syswin);if (!mTmpApplySurfaceChangesTransactionState.displayHasContent&& !getDisplayPolicy().isWindowExcludedFromContent(w)) {mTmpApplySurfaceChangesTransactionState.displayHasContent |= displayHasContent;}if (w.mHasSurface && isDisplayed) {if ((w.mAttrs.flags & FLAG_KEEP_SCREEN_ON) != 0) {mTmpHoldScreenWindow = w;} else if (w == mLastWakeLockHoldingWindow) {ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,"handleNotObscuredLocked: %s was holding screen wakelock but no longer "+ "has FLAG_KEEP_SCREEN_ON!!! called by%s",w, Debug.getCallers(10));}final int type = w.mAttrs.type;if (type == TYPE_SYSTEM_DIALOG|| type == TYPE_SYSTEM_ERROR|| (type == TYPE_NOTIFICATION_SHADE&&  mWmService.mPolicy.isKeyguardShowing())) {mTmpApplySurfaceChangesTransactionState.syswin = true;}if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0&& w.mAttrs.preferredRefreshRate != 0) {mTmpApplySurfaceChangesTransactionState.preferredRefreshRate= w.mAttrs.preferredRefreshRate;}mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing|= w.mAttrs.preferMinimalPostProcessing;mTmpApplySurfaceChangesTransactionState.disableHdrConversion|= !(w.mAttrs.isHdrConversionEnabled());final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy().getPreferredModeId(w);if (w.getWindowingMode() != WINDOWING_MODE_PINNED&& mTmpApplySurfaceChangesTransactionState.preferredModeId == 0&& preferredModeId != 0) {mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;}final float preferredMinRefreshRate = getDisplayPolicy().getRefreshRatePolicy().getPreferredMinRefreshRate(w);if (mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate == 0&& preferredMinRefreshRate != 0) {mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate =preferredMinRefreshRate;}final float preferredMaxRefreshRate = getDisplayPolicy().getRefreshRatePolicy().getPreferredMaxRefreshRate(w);if (mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate == 0&& preferredMaxRefreshRate != 0) {mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate =preferredMaxRefreshRate;}}}if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) {// This is the wallpaper target and its obscured state changed... make sure the// current wallpaper's visibility has been updated accordingly.mWallpaperController.updateWallpaperVisibility();}w.handleWindowMovedIfNeeded();final WindowStateAnimator winAnimator = w.mWinAnimator;//Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");w.resetContentChanged();// Moved from updateWindowsAndWallpaperLocked().if (w.mHasSurface) {// Take care of the window being ready to display.final boolean committed = winAnimator.commitFinishDrawingLocked();if (isDefaultDisplay && committed) {if (w.hasWallpaper()) {ProtoLog.v(WM_DEBUG_WALLPAPER,"First draw done in potential wallpaper target %s", w);mWallpaperMayChange = true;pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;if (DEBUG_LAYOUT_REPEATS) {surfacePlacer.debugLayoutRepeats("wallpaper and commitFinishDrawingLocked true",pendingLayoutChanges);}}}}final ActivityRecord activity = w.mActivityRecord;if (activity != null && activity.isVisibleRequested()) {activity.updateLetterboxSurface(w);final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {mTmpUpdateAllDrawn.add(activity);}}w.updateResizingWindowIfNeeded();
};

frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java#handleNotObscuredLocked

boolean handleNotObscuredLocked(WindowState w, boolean obscured, boolean syswin) {final WindowManager.LayoutParams attrs = w.mAttrs;final int attrFlags = attrs.flags;final boolean onScreen = w.isOnScreen();final boolean canBeSeen = w.isDisplayed();final int privateflags = attrs.privateFlags;boolean displayHasContent = false;ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,"handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"+ ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",w, w.mHasSurface, onScreen, w.isDisplayed(), w.mAttrs.userActivityTimeout);if (w.mHasSurface && onScreen) {if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {mUserActivityTimeout = w.mAttrs.userActivityTimeout;ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "mUserActivityTimeout set to %d",mUserActivityTimeout);}}if (w.mHasSurface && canBeSeen) {if (!syswin && w.mAttrs.screenBrightness >= 0&& Float.isNaN(mScreenBrightnessOverride)) {mScreenBrightnessOverride = w.mAttrs.screenBrightness;}final int type = attrs.type;// This function assumes that the contents of the default display are processed first// before secondary displays.final DisplayContent displayContent = w.getDisplayContent();if (displayContent != null && displayContent.isDefaultDisplay) {// While a dream or keyguard is showing, obscure ordinary application content on// secondary displays (by forcibly enabling mirroring unless there is other content// we want to show) but still allow opaque keyguard dialogs to be shown.if (w.isDreamWindow() || mWmService.mPolicy.isKeyguardShowing()) {mObscureApplicationContentOnSecondaryDisplays = true;}displayHasContent = true;} else if (displayContent != null &&(!mObscureApplicationContentOnSecondaryDisplays|| displayContent.isKeyguardAlwaysUnlocked()|| (obscured && type == TYPE_KEYGUARD_DIALOG))) {// Allow full screen keyguard presentation dialogs to be seen, or simply ignore the// keyguard if this display is always unlocked.displayHasContent = true;}if ((privateflags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {mSustainedPerformanceModeCurrent = true;}}return displayHasContent;
}

1.2 镜像模式显示条件

Android14上默认扩展屏没有显示内容mHasContent=false,扩展屏显示的是主屏DEFAULT_DISPLAY镜像。其实还有两个条件。

  1. 扩展屏信息 getDisplayDeviceInfoLocked 的flag没有DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY
  2. 扩展屏是否可以显示镜像 displayDevice.isWindowManagerMirroringLocked() ,如果为 false,则SurfaceFlinger不会在此显示器上执行层镜像,该方法目前Android14返回就是false固定值。
  3. mContentRecorder.updateRecording()更新镜像时,如果扩展屏有内容 mDisplayContent.getLastHasContent() 或者扩展屏时关闭状态 mDisplayContent.getDisplayInfo().state == Display.STATE_OFF ,就会停止镜像pauseRecording()

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

void updateRecording() {if (mContentRecorder == null || !mContentRecorder.isContentRecordingSessionSet()) {if (!setDisplayMirroring()) {return;}}mContentRecorder.updateRecording();
}boolean setDisplayMirroring() {int mirrorDisplayId = mWmService.mDisplayManagerInternal.getDisplayIdToMirror(mDisplayId);if (mirrorDisplayId == INVALID_DISPLAY) {return false;}if (mirrorDisplayId == mDisplayId) {if (mDisplayId != DEFAULT_DISPLAY) {ProtoLog.w(WM_DEBUG_CONTENT_RECORDING,"Content Recording: Attempting to mirror self on %d", mirrorDisplayId);}return false;}// This is very unlikely, and probably impossible, but if the current display is// DEFAULT_DISPLAY and the displayId to mirror results in an invalid display, we don't want// to mirror the DEFAULT_DISPLAY so instead we just returnDisplayContent mirrorDc = mRootWindowContainer.getDisplayContentOrCreate(mirrorDisplayId);if (mirrorDc == null && mDisplayId == DEFAULT_DISPLAY) {ProtoLog.w(WM_DEBUG_CONTENT_RECORDING,"Content Recording: Found no matching mirror display for id=%d for "+ "DEFAULT_DISPLAY. Nothing to mirror.",mirrorDisplayId);return false;}if (mirrorDc == null) {mirrorDc = mRootWindowContainer.getDefaultDisplay();ProtoLog.w(WM_DEBUG_CONTENT_RECORDING,"Content Recording: Attempting to mirror %d from %d but no DisplayContent "+ "associated. Changing to mirror default display.",mirrorDisplayId, mDisplayId);}// Create a session for mirroring the display content to this virtual display.ContentRecordingSession session = ContentRecordingSession.createDisplaySession(mirrorDc.getDisplayId()).setVirtualDisplayId(mDisplayId);setContentRecordingSession(session);ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,"Content Recording: Successfully created a ContentRecordingSession for "+ "displayId=%d to mirror content from displayId=%d",mDisplayId, mirrorDisplayId);return true;
}

frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

public int getDisplayIdToMirror(int displayId) {synchronized (mSyncRoot) {final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);if (display == null) {return Display.INVALID_DISPLAY;}final DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();final boolean ownContent = (displayDevice.getDisplayDeviceInfoLocked().flags& DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;// If the display has enabled mirroring, but specified that it will be managed by// WindowManager, return an invalid display id. This is to ensure we don't// accidentally select the display id to mirror based on DM logic and instead allow// the caller to specify what area to mirror.if (ownContent || displayDevice.isWindowManagerMirroringLocked()) {return Display.INVALID_DISPLAY;}int displayIdToMirror = displayDevice.getDisplayIdToMirrorLocked();LogicalDisplay displayToMirror = mLogicalDisplayMapper.getDisplayLocked(displayIdToMirror);// If the displayId for the requested mirror doesn't exist, fallback to mirroring// default display.if (displayToMirror == null) {displayIdToMirror = Display.DEFAULT_DISPLAY;}return displayIdToMirror;}
}

frameworks/base/services/core/java/com/android/server/wm/ContentRecorder.java

/*** Start recording if this DisplayContent no longer has content. Pause recording if it now* has content or the display is not on.*/
@VisibleForTesting void updateRecording() {if (isCurrentlyRecording() && (mDisplayContent.getLastHasContent()|| mDisplayContent.getDisplayInfo().state == Display.STATE_OFF)) {pauseRecording();} else {// Display no longer has content, or now has a surface to write to, so try to start// recording.startRecordingIfNeeded();}
}

2、镜像模式界面

  • 创建镜像SurfaceControlmRecordedSurface = SurfaceControl.mirrorSurface(mRecordedWindowContainer.getSurfaceControl())
  • 创建镜像SurfaceControl对应的TransactionSurfaceControl.Transaction transaction = mDisplayContent.mWmService.mTransactionFactory.get().reparent(mRecordedSurface, mDisplayContent.getSurfaceControl()).reparent(mDisplayContent.getWindowingLayer(), null).reparent(mDisplayContent.getOverlayLayer(), null);
  • 根据主屏和扩展屏大小处理:mRecordedWindowContainer.getBounds(), surfaceSize, updateMirroredSurface

frameworks/base/services/core/java/com/android/server/wm/ContentRecorder.java

/*** Start recording to this DisplayContent if it does not have its own content. Captures the* content of a WindowContainer indicated by a WindowToken. If unable to start recording, falls* back to original MediaProjection approach.*/
private void startRecordingIfNeeded() {// Only record if this display does not have its own content, is not recording already,// and if this display is on (it has a surface to write output to).if (mDisplayContent.getLastHasContent() || isCurrentlyRecording()|| mDisplayContent.getDisplayInfo().state == Display.STATE_OFF|| mContentRecordingSession == null) {return;}if (mContentRecordingSession.isWaitingForConsent()) {ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: waiting to record, so do "+ "nothing");return;}mRecordedWindowContainer = retrieveRecordedWindowContainer();if (mRecordedWindowContainer == null) {// Either the token is missing, or the window associated with the token is missing.// Error has already been handled, so just leave.return;}final Point surfaceSize = fetchSurfaceSizeIfPresent();if (surfaceSize == null) {ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,"Content Recording: Unable to start recording for display %d since the "+ "surface is not available.",mDisplayContent.getDisplayId());return;}ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,"Content Recording: Display %d has no content and is on, so start recording for "+ "state %d",mDisplayContent.getDisplayId(), mDisplayContent.getDisplayInfo().state);// TODO(b/274790702): Do not start recording if waiting for consent - for now,//  go ahead.// Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.mRecordedSurface = SurfaceControl.mirrorSurface(mRecordedWindowContainer.getSurfaceControl());SurfaceControl.Transaction transaction =mDisplayContent.mWmService.mTransactionFactory.get()// Set the mMirroredSurface's parent to the root SurfaceControl for this// DisplayContent. This brings the new mirrored hierarchy under this// DisplayContent,// so SurfaceControl will write the layers of this hierarchy to the// output surface// provided by the app..reparent(mRecordedSurface, mDisplayContent.getSurfaceControl())// Reparent the SurfaceControl of this DisplayContent to null, to prevent// content// being added to it. This ensures that no app launched explicitly on the// VirtualDisplay will show up as part of the mirrored content..reparent(mDisplayContent.getWindowingLayer(), null).reparent(mDisplayContent.getOverlayLayer(), null);// Retrieve the size of the DisplayArea to mirror.updateMirroredSurface(transaction, mRecordedWindowContainer.getBounds(), surfaceSize);// Notify the client about the visibility of the mirrored region, now that we have begun// capture.if (mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK) {mMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(mRecordedWindowContainer.asTask().isVisibleRequested());} else {int currentDisplayState =mRecordedWindowContainer.asDisplayContent().getDisplayInfo().state;mMediaProjectionManager.notifyActiveProjectionCapturedContentVisibilityChanged(currentDisplayState != DISPLAY_STATE_OFF);}// No need to clean up. In SurfaceFlinger, parents hold references to their children. The// mirrored SurfaceControl is alive since the parent DisplayContent SurfaceControl is// holding a reference to it. Therefore, the mirrored SurfaceControl will be cleaned up// when the VirtualDisplay is destroyed - which will clean up this DisplayContent.
}
/*** Apply transformations to the mirrored surface to ensure the captured contents are scaled to* fit and centred in the output surface.** @param transaction           the transaction to include transformations of mMirroredSurface*                              to. Transaction is not applied before returning.* @param recordedContentBounds bounds of the content to record to the surface provided by*                              the app.* @param surfaceSize           the default size of the surface to write the display area*                              content to*/@VisibleForTesting void updateMirroredSurface(SurfaceControl.Transaction transaction,Rect recordedContentBounds, Point surfaceSize) {// Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the// output surface.float scaleX = surfaceSize.x / (float) recordedContentBounds.width();float scaleY = surfaceSize.y / (float) recordedContentBounds.height();float scale = Math.min(scaleX, scaleY);int scaledWidth = Math.round(scale * (float) recordedContentBounds.width());int scaledHeight = Math.round(scale * (float) recordedContentBounds.height());// Calculate the shift to apply to the root mirror SurfaceControl to centre the mirrored// contents in the output surface.int shiftedX = 0;if (scaledWidth != surfaceSize.x) {shiftedX = (surfaceSize.x - scaledWidth) / 2;}int shiftedY = 0;if (scaledHeight != surfaceSize.y) {shiftedY = (surfaceSize.y - scaledHeight) / 2;}transaction// Crop the area to capture to exclude the 'extra' wallpaper that is used// for parallax (b/189930234)..setWindowCrop(mRecordedSurface, recordedContentBounds.width(),recordedContentBounds.height())// Scale the root mirror SurfaceControl, based upon the size difference between the// source (DisplayArea to capture) and output (surface the app reads images from)..setMatrix(mRecordedSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)// Position needs to be updated when the mirrored DisplayArea has changed, since// the content will no longer be centered in the output surface..setPosition(mRecordedSurface, shiftedX /* x */, shiftedY /* y */).apply();mLastRecordedBounds = new Rect(recordedContentBounds);// Request to notify the client about the resize.mMediaProjectionManager.notifyActiveProjectionCapturedContentResized(mLastRecordedBounds.width(), mLastRecordedBounds.height());}

相关文章:

Android 镜像模式和扩展模式区别探讨-Android14

Android 镜像模式和扩展模式区别探讨 1、区分镜像模式和扩展模式1.1 扩展屏是否有显示内容1.2 镜像模式显示条件 2、镜像模式界面 同屏显示和异屏显示探讨DisplayManagerService启动及主屏添加-Android13 Android主副屏显示-Android14 1、区分镜像模式和扩展模式 LogicalDispla…...

深度学习笔记之BERT(五)TinyBERT

深度学习笔记之TinyBERT 引言回顾&#xff1a;DistilBERT模型TinyBERT模型结构TinyBERT模型策略Transformer层蒸馏嵌入层蒸馏预测层蒸馏 TinyBERT模型的训练效果展示 引言 上一节介绍了 DistilBERT \text{DistilBERT} DistilBERT模型&#xff0c;本节将继续介绍优化性更强的知…...

【时间序列预测】基于PyTorch实现CNN_BiLSTM算法

文章目录 1. CNN与BiLSTM2. 完整代码实现3. 代码结构解读3.1 CNN Layer3.2 BiLSTM Layer3.3 Output Layer3.4 forward Layer 4. 应用场景5. 总结 本文将详细介绍如何使用Pytorch实现一个结合卷积神经网络&#xff08;CNN&#xff09;和双向长短期记忆网络&#xff08;BiLSTM&am…...

联想Y7000 2024版本笔记本 RTX4060安装ubuntu22.04双系统及深度学习环境配置

目录 1..制作启动盘 2.Windows 磁盘分区,删除原来ubuntu的启动项 3.四个设置 4.安装ubuntu 5.ubuntu系统配置 1..制作启动盘 先下载镜像文件,注意版本对应。Rufus - 轻松创建 USB 启动盘 用rufus制作时,需要注意选择正确的分区类型和系统类型。不然安装的系统会有问题…...

VuePress学习

1.介绍 VuePress 由两部分组成&#xff1a;第一部分是一个极简静态网站生成器 (opens new window)&#xff0c;它包含由 Vue 驱动的主题系统和插件 API&#xff0c;另一个部分是为书写技术文档而优化的默认主题&#xff0c;它的诞生初衷是为了支持 Vue 及其子项目的文档需求。…...

一次“okhttp访问间隔60秒,提示unexpected end of stream“的问题排查过程

一、现象 okhttp调用某个服务&#xff0c;如果第二次访问间隔上一次访问时间超过60s&#xff0c;返回错误&#xff1a;"unexpected end of stream"。 二、最终定位原因&#xff1a; 空闲连接如果超过60秒&#xff0c;服务端会主动关闭连接。此时客户端恰巧访问了这…...

SQL最佳实践:避免使用COUNT=0

如果你遇到类似下面的 SQL 查询&#xff1a; SELECT * FROM customer c WHERE 0 (SELECT COUNT(*)FROM orders oWHERE o.customer_id c.customer_id);意味着有人没有遵循 SQL 最佳实践。该语句的作用是查找没有下过订单的客户&#xff0c;其中子查询使用了 COUNT 函数统计客…...

PG与ORACLE的差距

首先必须是XID 64&#xff0c;一个在极端环境下会FREEZE的数据库无论如何都无法承担关键业务系统的重任的&#xff0c;我们可以通过各种配置&#xff0c;提升硬件的性能&#xff0c;通过各种IT管控措施来尽可能避免在核心系统上面临FREEZE的风险&#xff0c;不过并不是每个企业…...

树莓派3B+驱动开发(2)- LED驱动(传统模式)

github主页&#xff1a;https://github.com/snqx-lqh 本项目github地址&#xff1a;https://github.com/snqx-lqh/RaspberryPiDriver 本项目硬件地址&#xff1a;https://oshwhub.com/from_zero/shu-mei-pai-kuo-zhan-ban 欢迎交流 笔记说明 如我在驱动开发总览中说的那样&…...

超详细搭建PhpStorm+PhpStudy开发环境

刚开始接触PHP开发&#xff0c;搭建开发环境是第一步&#xff0c;网上下载PhpStorm和PhpStudy软件&#xff0c;怎样安装和激活就不详细说了&#xff0c;我们重点来看一看怎样搭配这两个开发环境。 前提&#xff1a;现在假设你已经安装完PhpStorm和PhpStudy软件。 我的PhpStor…...

分析比对vuex和store模式

在 Vue 中&#xff0c;Vuex 和 store 模式 是两个不同的概念&#xff0c;它们紧密相关&#xff0c;主要用于管理应用的状态。下面我会详细介绍这两个概念&#xff0c;并通过例子帮助你更好地理解。 1. Vuex 是什么&#xff1f; Vuex 是 Vue.js 的一个状态管理库&#xff0c;用…...

C# 网络编程--基础核心内容

在现今软件开发中&#xff0c;网络编程是非常重要的一部分&#xff0c;本文简要介绍下网络编程的概念和实践。 C#网络编程的主要内容包括以下几个方面‌&#xff1a; : 上图引用大佬的图&#xff0c;大家也关注一下&#xff0c;有技术有品质&#xff0c;有国有家&#xff0c;情…...

【C++游戏程序】easyX图形库还原游戏《贪吃蛇大作战》(三)

承接上一篇文章&#xff1a;【C游戏程序】easyX图形库还原游戏《贪吃蛇大作战》&#xff08;二&#xff09;&#xff0c;我们这次来补充一些游戏细节&#xff0c;以及增加吃食物加长角色长度等设定玩法&#xff0c;也是本游戏的最后一篇文章。 一.玩家边界检测 首先是用来检测…...

uni-app H5端使用注意事项 【跨端开发系列】

&#x1f517; uniapp 跨端开发系列文章&#xff1a;&#x1f380;&#x1f380;&#x1f380; uni-app 组成和跨端原理 【跨端开发系列】 uni-app 各端差异注意事项 【跨端开发系列】uni-app 离线本地存储方案 【跨端开发系列】uni-app UI库、框架、组件选型指南 【跨端开…...

SpringBoot中的@Configuration注解

在Spring Boot中&#xff0c;Configuration注解扮演着非常重要的角色&#xff0c;它是Spring框架中用于定义配置类的一个核心注解。以下是Configuration注解的主要作用&#xff1a; 定义配置类&#xff1a; 使用Configuration注解的类表示这是一个配置类&#xff0c;Spring容器…...

十二、路由、生命周期函数

router路由 页面路由指的是在应用程序中实现不同页面之间的跳转,以及数据传递。通过 Router 模块就可以实现这个功能 2.1创建页面 之前是创建的文件,使用路由的时候需要创建页面,步骤略有不同 方法 1:直接右键新建Page(常用)方法 2:单独添加页面并配置2.1.1直接右键新建…...

【蓝桥杯每日一题】X 进制减法

X 进制减法 2024-12-6 蓝桥杯每日一题 X 进制减法 贪心 进制转换 题目大意 进制规定了数字在数位上逢几进一。 XX 进制是一种很神奇的进制, 因为其每一数位的进制并不固定&#xff01;例如说某 种 XX 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 XX 进制…...

《蓝桥杯比赛规划》

大家好啊&#xff01;我是NiJiMingCheng 我的博客&#xff1a;NiJiMingCheng 这节课我们来分享蓝桥杯比赛规划&#xff0c;好的规划会给我们的学习带来良好的收益&#xff0c;废话少说接下来就让我们进入学习规划吧&#xff0c;加油哦&#xff01;&#xff01;&#xff01; 一、…...

C++算法练习day70——53.最大子序和

题目来源&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目思路分析 题目&#xff1a;寻找最大子数组和&#xff08;也称为最大子序和&#xff09;。 给定一个整数数组 nums&#xff0c;找到一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#x…...

import是如何“占领满屏“

import是如何“占领满屏“的&#xff1f; 《拒绝使用模块重导&#xff08;Re-export&#xff09;》 模块重导是一种通用的技术。在腾讯、字节、阿里等各大厂的组件库中都有大量使用。 如&#xff1a;字节的arco-design组件库中的组件&#xff1a;github.com/arco-design… …...

ceph /etc/ceph-csi-config/config.json: no such file or directory

环境 rook-ceph 部署的 ceph。 问题 kubectl describe pod dragonfly-redis-master-0Warning FailedMount 7m59s (x20 over 46m) kubelet MountVolume.MountDevice failed for volume "pvc-c63e159a-c940-4001-bf0d-e6141634cc55" : rpc error: cod…...

C语言——验证“哥德巴赫猜想”

问题描述&#xff1a; 验证"哥德巴赫猜想" 任何一个大于2的偶数都可以表示为两个质数之和。例如&#xff0c;4可以表示为22&#xff0c;6可以表示为33&#xff0c;8可以表示为35等 //验证"哥德巴赫猜想" //任何一个大于2的偶数都可以表示为两个质数之和…...

Flourish笔记:柱状图(Column chart (grouped))

文章目录 样式设定Chart Type&#xff1a;图表类型Controls & Filters&#xff1a;展示方式Colors&#xff1a;颜色bars&#xff1a;柱子的调整labels&#xff1a;柱子数字标注X axis&#xff1a;横坐标标签Y axis&#xff1a;纵坐标标签Plot BackgroundNumber FormatingLe…...

深度学习案例:DenseNet + SE-Net

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 回顾DenseNet算法 DenseNet&#xff08;Densely Connected Convolutional Networks&#xff09;是一种深度卷积神经网络架构&#xff0c;提出的核心思想是通过在每一层与前面所有层进行直接连接…...

excel文件合并,每个excel名称插入excel列

import pandas as pd import os # 设置文件夹路径 folder_path rC:\test # 替换为您的下载文件夹路径 output_file os.path.join(folder_path, BOM材料.xlsx) # 创建一个空的 DataFrame 用于存储合并的数据 combined_data pd.DataFrame() # 遍历文件夹中的所有文件 for …...

Linux 如何设置特殊权限?

简介 通过使用 setuid、setgid 、sticky&#xff0c;它们是 Linux 中的特殊权限&#xff0c;可以对文件和目录的访问和执行方式提供额外的控制。 命令八进制数字功能setuid4当执行文件时&#xff0c;它以文件所有者的权限运行&#xff0c;而不是执行它的用户的权限运行。setg…...

零基础如何使用ChatGPT快速学习Python

引言 AI编程时代来临&#xff0c;没有编程基础可以快速上车享受时代的红利吗&#xff1f;答案是肯定的。本文旨在介绍零基础如何利用ChatGPT快速学习Python编程语言&#xff0c;开启AI编程之路。解决的问题包括&#xff1a;传统学习方式效率低、缺乏互动性以及学习资源质量参差…...

【开源】一款基于SpringBoot 的全开源充电桩平台

一、下载项目文件 下载源码项目文件口令&#xff1a;动作璆璜量子屏多好/~d1b8356ox2~:/复制口令后&#xff0c;进入夸克网盘app即可保存&#xff08;如果复制到夸克app没有跳转资源&#xff0c;可以复制粘贴口令到夸克app的搜索框也可以打开&#xff08;不用点搜索按钮&#…...

AI - RAG中的状态化管理聊天记录

AI - RAG中的状态化管理聊天记录 大家好&#xff0c;今天我们来聊聊LangChain和LLM中一个重要的话题——状态化管理聊天记录。在使用大语言模型(LLM)的时候&#xff0c;聊天记录&#xff08;History&#xff09;和状态&#xff08;State&#xff09;管理是非常关键的。那我们先…...

JAVA安全—SpringBoot框架MyBatis注入Thymeleaf模板注入

前言 之前我们讲了JAVA的一些组件安全&#xff0c;比如Log4j&#xff0c;fastjson。今天讲一下框架安全&#xff0c;就是这个也是比较常见的SpringBoot框架。 SpringBoot框架 Spring Boot是由Pivotal团队提供的一套开源框架&#xff0c;可以简化spring应用的创建及部署。它提…...

wordpress 主题 36kr/网站的优化seo

配置防盗链 防止服务器的图片和其他资源被非本机的站点引用&#xff0c;被其他网站引用后会导致流量图片的用户的数量暴增&#xff0c;而带宽流量增加、增加站点的成本&#xff1b; 编辑虚拟配置文件 vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf 增加代码 <Dire…...

网站建设制作设计/合肥全网优化

作为一个运维&#xff0c;做监控的时候一定要了解我们需要监控的对象&#xff0c;我们监控的范围&#xff0c;以及我们根据业务判定监控要达到的精准度。 监控对象&#xff1a;     1. 监控对象的理解&#xff1a;CPU是怎么工作的&#xff0c;原理     2. 监控对象的指…...

网站开发教程PDF微盘下载/淘数据官网

Visual Basic .NET 教程 模块五 菜单栏、工具栏、状态栏 能力目标&#xff1a;能够设计、创建和使用菜单、工具栏和状态栏 知识目标&#xff1a;掌握菜单控件、工具栏控件和状态栏控件常用的属性、方法和事件 一个典型的Windows应用程序必然包含菜单、工具栏和状态栏&#x…...

赌球网站推广怎么做/搜索关键词的软件

信息系统项目管理师考试&#xff0c;由综合知识&#xff0c;案例分析和论文组成&#xff0c;考试方式如下&#xff1a; &#xff08;1&#xff09;信息系统项目管理综合知识&#xff0c;考试时间为150分钟&#xff0c;笔试&#xff0c;选择题&#xff1b;45分及格。 &#xf…...

怎么申请公司注册/深圳seo网络推广

题意 给一颗边带权的树&#xff0c;边权为1~5&#xff0c;多次询问树上某条路径组成的边权序列的LIS 思路 假设已知边权序列&#xff0c;设\(f_{i,j}\)表示处理了前\(i\)个数&#xff0c;当前\(LIS\)中的最后一个数为\(j\)时的\(LIS\)长度&#xff0c;显然有\(f_{i,j}max(f_{i-…...

保定网站制作公司/网络推广方案范例

一、先来个简单的1.安装docker2.安装eureka——运行docker命令安装3.安装eureka——运行dokcer镜像安装(1)构建eureka的镜像&#xff0c;网易云的docker镜像比较全一些&#xff0c;也可以去https://hub.docker.com/拷贝下(2)运行镜像启动&#xff0c;等响应。可以把本地镜像传到…...