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

Android SystemUI组件(08)睡眠灭屏 锁屏处理流程

该系列文章总纲链接:专题分纲目录 Android SystemUI组件


本章关键点总结 & 说明:

说明:本章节持续迭代之前章节的思维导图,主要关注左侧上方锁屏分析部分 睡眠灭屏 即可。

Power按键的处理逻辑最终是由PhoneWindowManager来完成。想了解更多可参考输入子系统的相关文章。整理如下:

Android Framework 输入子系统(01)核心机制 inotify和epoll

Android Framework 输入子系统(02)核心机制 双向通信(socketpair+binder)

Android Framework 输入子系统(03)输入系统框架

Android Framework 输入子系统(04)InputReader解读

Android Framework 输入子系统(05)InputDispatcher解读

Android Framework 输入子系统(06)Global Key 一键启动 应用程序案例

Android Framework 输入子系统(07)APP建立联系

Android Framework 输入子系统(08)View基础(activity window decor view)

Android Framework 输入子系统(09)InputStage解读

Android Framework 输入子系统(10)Input命令解读

Android Framework 输入子系统(11)sendevent与getevent命令解读

本章我们只关注与Power按键相关的内容,InputManagerService处理的按键事件,最终会传递到PhoneWindowManager的interceptKeyBeforeQueueing方法中处理。我们就从这里入手逐步分析。

1 从PhoneWindowManager到PowerManagerService的处理

public class PhoneWindowManager implements WindowManagerPolicy {static final String TAG = "WindowManager";static final boolean DEBUG = false;//...//关键流程step1public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {//...//表示屏幕是否点亮final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;final boolean canceled = event.isCanceled();//获取按键编码final int keyCode = event.getKeyCode();final boolean keyguardActive = (mKeyguardDelegate == null ? false :(interactive ?isKeyguardShowingAndNotOccluded() :mKeyguardDelegate.isShowing()));boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0|| event.isWakeKey();//...// Handle special keys.switch (keyCode) {//...case KeyEvent.KEYCODE_POWER: {result &= ~ACTION_PASS_TO_USER;isWakeKey = false; // wake-up will be handled separatelyif (down) {//亮屏 step1 按下power按键,亮屏流程interceptPowerKeyDown(event, interactive);} else {//抬起power按键interceptPowerKeyUp(event, interactive, canceled);}break;}case KeyEvent.KEYCODE_SLEEP: {result &= ~ACTION_PASS_TO_USER;if (!mPowerManager.isInteractive()) {useHapticFeedback = false; // suppress feedback if already non-interactive}mPowerManager.goToSleep(event.getEventTime(),PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);isWakeKey = false;break;}case KeyEvent.KEYCODE_WAKEUP: {result &= ~ACTION_PASS_TO_USER;isWakeKey = true;break;}//...}//...if (isWakeKey) {wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);}return result;}//...//关键流程step2private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {final boolean handled = canceled || mPowerKeyHandled;mScreenshotChordPowerKeyTriggered = false;cancelPendingScreenshotChordAction();cancelPendingPowerKeyAction();if (!handled) {// Figure out how to handle the key now that it has been released.mPowerKeyPressCounter += 1;final int maxCount = getMaxMultiPressPowerCount();final long eventTime = event.getDownTime();if (mPowerKeyPressCounter < maxCount) {// This could be a multi-press.  Wait a little bit longer to confirm.// Continue holding the wake lock.Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);msg.setAsynchronous(true);mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());return;}// No other actions.  Handle it immediately.powerPress(eventTime, interactive, mPowerKeyPressCounter);}// Done.  Reset our state.finishPowerKeyPress();}//...//关键流程step3private void powerPress(long eventTime, boolean interactive, int count) {if (mScreenOnEarly && !mScreenOnFully) {return;}if (count == 2) {powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);} else if (count == 3) {powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);} else if (interactive && !mBeganFromNonInteractive) {//关键流程step4 除了无效处理意外,都会调用到PowerManagerService中的goToSleep方法switch (mShortPressOnPowerBehavior) {case SHORT_PRESS_POWER_NOTHING:break;case SHORT_PRESS_POWER_GO_TO_SLEEP:mPowerManager.goToSleep(eventTime,PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);break;case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:mPowerManager.goToSleep(eventTime,PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);break;case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:mPowerManager.goToSleep(eventTime,PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);launchHomeFromHotKey();break;}}}//...
}

2 从PowerManagerService到Notifier的处理

从PhoneWindowManager的interceptKeyBeforeQueueing方法入口开始分析,最终会到达PowerManagerService的gotoSleep方法(从PowerManager到PowerManagerService的调用就不在分析了,这个属于binder通信的范畴),对应的代码实现如下:

public final class PowerManagerService extends SystemServiceimplements Watchdog.Monitor {private static final String TAG = "PowerManagerService";private static final boolean DEBUG = false;//...//关键流程step1private final class BinderService extends IPowerManager.Stub {@Override // Binder callpublic void goToSleep(long eventTime, int reason, int flags) {if (eventTime > SystemClock.uptimeMillis()) {throw new IllegalArgumentException("event time must not be in the future");}mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);final int uid = Binder.getCallingUid();final long ident = Binder.clearCallingIdentity();try {goToSleepInternal(eventTime, reason, flags, uid);} finally {Binder.restoreCallingIdentity(ident);}}//...}//...//关键流程step2private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {synchronized (mLock) {if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {updatePowerStateLocked();}}}//...//关键流程step3private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {if (eventTime < mLastWakeTime|| mWakefulness == WAKEFULNESS_ASLEEP|| mWakefulness == WAKEFULNESS_DOZING|| !mBootCompleted || !mSystemReady) {return false;}try {//...mLastSleepTime = eventTime;mSandmanSummoned = true;setWakefulnessLocked(WAKEFULNESS_DOZING, reason);// Report the number of wake locks that will be cleared by going to sleep.int numWakeLocksCleared = 0;final int numWakeLocks = mWakeLocks.size();for (int i = 0; i < numWakeLocks; i++) {final WakeLock wakeLock = mWakeLocks.get(i);switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {case PowerManager.FULL_WAKE_LOCK:case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:case PowerManager.SCREEN_DIM_WAKE_LOCK:numWakeLocksCleared += 1;break;}}// Skip dozing if requested.if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {reallyGoToSleepNoUpdateLocked(eventTime, uid);}} return true;}//...//关键流程step4private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP|| !mBootCompleted || !mSystemReady) {return false;}try {mDirty |= DIRTY_WAKEFULNESS;mWakefulness = WAKEFULNESS_ASLEEP;setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);}return true;}//关键流程step5private void setInteractiveStateLocked(boolean interactive, int reason) {if (mInteractive != interactive) {finishInteractiveStateChangeLocked();mInteractive = interactive;mInteractiveChanging = true;mNotifier.onInteractiveStateChangeStarted(interactive, reason);}}//...//关键流程step6private void finishInteractiveStateChangeLocked() {if (mInteractiveChanging) {mNotifier.onInteractiveStateChangeFinished(mInteractive);mInteractiveChanging = false;}}//...
}

3 Notifier的处理

Notifier的处理包含2个层面,一个是发送SCREEN_OFF的广播,通知其他子系统亮屏的消息。一个是通过PhoneWindowManager的处理来逐层执行对应回调onScreenTurnedOff方法。

3.1 从Notifier最终发送SCREEN_OFF广播

针对发送广播的逻辑处理流程,代码逻辑流程如下:

//Notifier
final class Notifier {private static final String TAG = "PowerManagerNotifier";private static final boolean DEBUG = false;//...//关键流程step1public void onInteractiveStateChangeFinished(boolean interactive) {synchronized (mLock) {if (!interactive) {if (mActualPowerState != POWER_STATE_ASLEEP) {mActualPowerState = POWER_STATE_ASLEEP;mPendingGoToSleepBroadcast = true;if (mUserActivityPending) {mUserActivityPending = false;mHandler.removeMessages(MSG_USER_ACTIVITY);}mHandler.post(new Runnable() {@Overridepublic void run() {int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;switch (mLastGoToSleepReason) {case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;break;case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;break;}EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);mPolicy.goingToSleep(why);mActivityManagerInternal.goingToSleep();}});updatePendingBroadcastLocked();}}}}//...//关键流程step2private void updatePendingBroadcastLocked() {if (!mBroadcastInProgress&& mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast|| mActualInteractiveState != mBroadcastedInteractiveState)) {mBroadcastInProgress = true;mSuspendBlocker.acquire();Message msg = mHandler.obtainMessage(MSG_BROADCAST);msg.setAsynchronous(true);mHandler.sendMessage(msg);}}//...//关键流程step3private final class NotifierHandler extends Handler {public NotifierHandler(Looper looper) {super(looper, null, true /*async*/);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_BROADCAST:sendNextBroadcast();break;//...}}}//消息处理:当设备从睡眠状态唤醒时,会发送 ACTION_SCREEN_ON 广播;当设备准备进入睡眠状态时,会发送 ACTION_SCREEN_OFF 广播。private void sendNextBroadcast() {final int powerState;synchronized (mLock) {//mBroadcastedInteractiveState相关处理//...mBroadcastStartTime = SystemClock.uptimeMillis();powerState = mBroadcastedInteractiveState;}EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);// 根据电源状态发送相应的广播if (powerState == INTERACTIVE_STATE_AWAKE) {sendWakeUpBroadcast(); //发送唤醒广播} else {sendGoToSleepBroadcast(); //发送睡眠广播}}//...//消息处理:发送有序广播private void sendGoToSleepBroadcast() {if (ActivityManagerNative.isSystemReady()) {// 发送广播关键API,参数解读如下:// mScreenOnIntent 是一个 Intent,包含了唤醒屏幕的信息// UserHandle.ALL 表示这个广播会发送给所有用户// mWakeUpBroadcastDone 是一个 BroadcastReceiver,用于在广播完成后接收回调// mHandler 是一个 Handler,用于处理广播完成后的回调// 0 是一个 flags,表示广播的权限// 最后的 null, null 是额外的参数,这里没有使用mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,mGoToSleepBroadcastDone, mHandler, 0, null, null);} else {EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);sendNextBroadcast();}}//...
}

这条逻辑的处理主要是发送睡眠广播为主。接下来分析从mPolicy.goingToSleep(why);出发的灭屏回调处理流程。

3.2 PhoneWindowManager的goingToSleep方法处理灭屏回调方法

这里主要是从到PhoneWindowManager的wakingUp(policy.goingToSleep)方法,再到各层的onScreenTurnedOff方法的处理逻辑流程,从onInteractiveStateChangeFinished处开始,代码实现如下:

//Notifier
final class Notifier {private static final String TAG = "PowerManagerNotifier";private static final boolean DEBUG = false;//...public void onInteractiveStateChangeFinished(boolean interactive) {synchronized (mLock) {if (!interactive) {if (mActualPowerState != POWER_STATE_ASLEEP) {mActualPowerState = POWER_STATE_ASLEEP;mPendingGoToSleepBroadcast = true;if (mUserActivityPending) {mUserActivityPending = false;mHandler.removeMessages(MSG_USER_ACTIVITY);}mHandler.post(new Runnable() {@Overridepublic void run() {int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;switch (mLastGoToSleepReason) {case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;break;case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;break;}EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);mPolicy.goingToSleep(why);mActivityManagerInternal.goingToSleep();}});updatePendingBroadcastLocked();}}}}//...
}

这里会调用到PhoneWindowManager的goingToSleep方法。代码实现如下:

//phonewindowmanager@Overridepublic void goingToSleep(int why) {EventLog.writeEvent(70000, 0);synchronized (mLock) {mAwake = false;mKeyguardDrawComplete = false;updateWakeGestureListenerLp();updateOrientationListenerLp();updateLockScreenTimeout();}if (mKeyguardDelegate != null) {mKeyguardDelegate.onScreenTurnedOff(why);}}

这里会调用到KeyguardDelegate的onScreenTurnedOff方法。代码实现如下:
 

//KeyguardDelegatepublic void onScreenTurnedOff(int why) {if (mKeyguardService != null) {mKeyguardService.onScreenTurnedOff(why);}mKeyguardState.offReason = why;mKeyguardState.screenIsOn = false;}

这里会调用到KeyguardServiceWrapper的onScreenTurnedOff方法。代码实现如下:

//wrapper@Override // Binder interfacepublic void onScreenTurnedOff(int reason) {try {mService.onScreenTurnedOff(reason);} catch (RemoteException e) {Slog.w(TAG , "Remote Exception", e);}}

这里会调用到KeyguardService的onScreenTurnedOff方法。代码实现如下:

//KeyguardService//binder@Override // Binder interfacepublic void onScreenTurnedOff(int reason) {checkPermission();mKeyguardViewMediator.onScreenTurnedOff(reason);}

这里会调用到KeyguardViewMediator的onScreenTurnedOff方法。这里才是真正的逻辑实现,代码实现如下:

//KeyguardViewMediatorpublic void onScreenTurnedOff(int why) {synchronized (this) {// 将屏幕状态设置为关闭mScreenOn = false;// 重置关键的锁屏完成等待状态resetKeyguardDonePendingLocked();// 标记未运行隐藏动画mHideAnimationRun = false;// 判断是否需要立即锁屏// 如果设置为按下电源键立即锁屏,或者设备没有设置安全措施,则立即锁屏final boolean lockImmediately =mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();// 通知屏幕已关闭notifyScreenOffLocked();// 如果存在退出安全模式的回调,执行回调并设置为nullif (mExitSecureCallback != null) {// 执行回调以通知锁屏退出的结果try {mExitSecureCallback.onKeyguardExitResult(false);} catch (RemoteException e) {// 如果远程调用失败,记录错误Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);}mExitSecureCallback = null;// 如果锁屏没有被外部启用,隐藏锁屏if (!mExternallyEnabled) {hideLocked();}} else if (mShowing) {// 如果锁屏当前正在显示,重置锁屏状态resetStateLocked();} else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT ||(why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)){// 如果屏幕是因为超时关闭,或者用户主动关闭但不需要立即锁屏,// 则计划延迟显示锁屏doKeyguardLaterLocked();} else {// 否则,立即显示锁屏doKeyguardLocked(null);}}// 通知更新监控器屏幕已关闭,并传递关闭的原因KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why);}

这里总结下,onScreenTurnedOff 关键逻辑解读如下:

  1. 当屏幕关闭时,这个方法会被调用。
  2. 如果设备设置为按下电源键立即锁定,或者设备没有设置安全措施(如PIN、密码、图案),则变量 lockImmediately 会被设置为 true。
  3. 根据 why 参数的值(表示屏幕关闭的原因),决定是否立即调用 doKeyguardLocked 或者延迟调用 doKeyguardLaterLocked(也会调用doKeyguardLocked )。

接下来关于doKeyguardLocked的处理,可以参考如下文章:

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

参考其第二部分2.2 即可。

相关文章:

Android SystemUI组件(08)睡眠灭屏 锁屏处理流程

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分 睡眠灭屏 即可。 Power按键的处理逻辑最终是由PhoneWindowManager来完…...

C# 表达式与运算符

本课要点&#xff1a; 1、表达式的基本概念 2、常用的几种运算符 3、运算符的优先级 4、常见问题 一 表达式 表达式是由运算符和操作数组成的。、-、*和/等都是运算符&#xff0c;操作数包括文本、常量、变量和表达式等。 二 算术运算符 2.1 算术运算符的使用 三 常见错误 …...

SpringBoot--最大连接数和最大并发数

原文网址&#xff1a;SpringBoot--最大连接数和最大并发数-CSDN博客 简介 本文介绍SpringBoot的最大连接数和最大并发数。 配置 SpringBoot默认使用tomcat处理请求。tomcat可以指定连接数、线程数等配置。 server:tomcat:# 请求处理线程都在使用中时&#xff0c;新连接请求…...

CF687D Dividing Kingdom II 题解

Description 给定一个 n n n 个点、 m m m 条边的图&#xff0c;有 q q q 次询问&#xff0c;每次询问一个 [ l , r ] [l,r] [l,r] 的区间&#xff0c;求将 n n n 个点分为两个部分后&#xff0c;编号在 [ l , r ] [l,r] [l,r] 内的边中&#xff0c;两端点属于同一部分的…...

高空抛物AI检测算法:精准防控,技术革新守护城市安全

近年来&#xff0c;随着城市化进程的加速&#xff0c;高楼大厦如雨后春笋般涌现&#xff0c;但随之而来的高空抛物问题却成为城市管理的一大难题。高空抛物不仅严重威胁行人的安全&#xff0c;还可能引发法律纠纷和社会问题。为了有效预防和减少高空抛物事件的发生&#xff0c;…...

html+css+js实现Collapse 折叠面板

实现效果&#xff1a; HTML部分 <div class"collapse"><ul><li><div class"header"><h4>一致性 Consistency</h4><span class"iconfont icon-jiantou"></span></div><div class"…...

RM服务器研究(一)

客户端默认端口是10100&#xff1a; MultiPort.dll BOOL sub_10001070() { UINT v0; // esi BOOL result; // eax CHAR KeyName; // [espCh] [ebp-10Ch] DWORD flOldProtect; // [esp10h] [ebp-108h] CHAR Buffer; // [esp14h] [ebp-104h] char v5; // [esp15h] [e…...

云岚到家xxl job 配置

调度中心&#xff1a; 负责管理调度信息&#xff0c;按照调度配置发出调度请求&#xff0c;自身不承担业务代码&#xff1b; 主要职责为执行器管理、任务管理、监控运维、日志管理等 任务执行器&#xff1a; 负责接收调度请求并执行任务逻辑&#xff1b; 主要职责是执行任…...

国内动态短效sk5

HTTP爬虫代理,软件测试&#xff0c; 动态转发IP方案&#xff0c;全高匿名&#xff0c;私密IP&#xff0c;固定网关将您每次请求的HTTP重定向到不同的后端IP&#xff0c;支持API;指路小熊IP https://www.xiaoxiongip.com?fromqkJWgD可测...

【路径规划】路径平滑算法,A星算法拐点的圆弧化处理

摘要 A算法广泛应用于路径规划中&#xff0c;但其生成的路径通常在拐点处呈现不平滑的折线。为了提升路径的平滑性&#xff0c;本文提出了一种基于圆弧的平滑处理方法&#xff0c;用于对A算法产生的路径拐点进行优化。通过在MATLAB中进行仿真验证&#xff0c;该方法能够有效减…...

【寻找one piece的算法之路】——双指针算法!他与她是否会相遇呢?

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;寻找one piece的刷题之路 什么是双指针算法 双指针算法是一种常用的编程技巧&#xff0c;尤其在处理数组和字符串问题时非常有效。这种方法的核心思想是使用两个指针来遍历数据结构&#xff0c;这两…...

UFS 3.1架构简介

整个UFS协议栈可以分为三层:应用层(UFS Application Layer(UAP)),传输层(UFS Transport Layer(UTP)),链路层(UIC InterConnect Layer(UIC))。应用层发出SCSI命令(UFS没有自己的命令使用的是简化的SCSI命令),在传输层将SCSI分装为UPIU,再经过链路层将命令发送给Devices。下…...

注册安全分析报告:科研诚信查询平台无验证方式导致安全隐患

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

04.useTitle

在 React 应用中,动态更新页面标题是提升用户体验的一个重要方面。它可以让用户更清楚地知道当前页面的内容或状态,特别是在单页应用(SPA)中。useTitle 钩子提供了一种简单而有效的方式来管理文档标题。以下是如何实现和使用这个自定义钩子: const useTitle = title =>…...

ROS2中的srv、action、发布订阅三种方式

ROS2中的srv、action、发布订阅三种方式 以下是ROS2中srv、action、发布订阅三种方式的差异和使用场景的表格形式呈现&#xff1a; 特性/方式srv&#xff08;服务&#xff09;action&#xff08;动作&#xff09;发布订阅&#xff08;Publish-Subscribe&#xff09;通信模式请…...

HarmonyOS/OpenHarmony 自定义弹窗页面级层级控制解决方案

关键词&#xff1a;CuntomDialog自定义弹窗、SubWindow子窗口、页面级、弹窗层级控制、鸿蒙、弹窗展示层级异常 问题存在API版本&#xff1a;API10 - API12&#xff08;该问题已反馈&#xff0c;期望后续官方能增加页面级控制能力&#xff09; 在正常的鸿蒙app开发过程中&…...

C/C++进阶(一)--内存管理

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 本文所在专栏&#xff1a; 学习专栏C语言_Stark、的博客-CSDN博客 其它专栏&#xff1a; 数据结构与算法_Stark、的博客-CSDN博客 ​​​​​​项目实战C系列_Stark、的博客-CSDN博客 座右铭&a…...

docker-compose 快速部署clickhouse集群

在本教程中&#xff0c;我们将学习如何使用 Docker Compose 部署一个带有三节点的 ClickHouse 集群&#xff0c;并使用 ZooKeeper 作为分布式协调服务。 前提条件 注意事项&#xff1a; 镜像版本号注意保持一致 [zookeeper:3.7, clickhouse/clickhouse-server:22.5.4]config…...

闯关训练三:Git 基础知识

任务1: 破冰活动&#xff1a;自我介绍 点击Fork目标项目&#xff0c;创建一个新的Fork 获取仓库链接 在连接好开发机的vscode终端中逐行执行以下代码&#xff1a; git clone https://github.com/KelvinIII/Tutorial.git # 修改为自己frok的仓库 cd Tutorial/ git branch -a g…...

Java--IO基本流

IO流 概述 生活中&#xff0c;你肯定经历过这样的场景。当你编辑一个文本文件&#xff0c;忘记了ctrls &#xff0c;可能文件就白白编辑了。当你电脑上插入一个U盘&#xff0c;可以把一个视频&#xff0c;拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢&#xff1f;键盘…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...