Android SystemUI组件(10)禁用/重启锁屏流程分析
该系列文章总纲链接:专题分纲目录 Android SystemUI组件
本章关键点总结 & 说明:
说明:本章节持续迭代之前章节的思维导图,主要关注左侧上方锁屏分析部分 应用入口处理流程解读 即可。
在 Android 系统中,禁用锁屏(Keyguard)通常需要 DISABLE_KEYGUARD
权限。但是,这个权限属于签名权限,只能由系统应用或者具有系统签名的应用使用,比如Setting、Launcher等。
对于普通应用来说,通常不允许禁用锁屏,因为这会降低设备的安全性。然而,有些情况下,比如在设置应用或者需要解锁功能的其他预装应用中,可能需要这个权限。在 AndroidManifest.xml 文件中声明权限的示例:
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
但是,即使声明了这个权限,普通应用也无法获得这个权限,系统会忽略它们的请求。对于系统应用或者具有系统权限的应用,使用 KeyguardManager
禁用锁屏和重新启用锁屏的代码如下:
//获取系统服务
KeyguardManager keyguardManager = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);//创建一个KeyguardLock对象,这个对象提供了控制锁屏(Keyguard)行为的方法。
//参数"UNIQUE_LOCK_INSTANCE"是一个标识符,用于区分不同的锁屏控制实例
KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("UNIQUE_LOCK_INSTANCE");//常用操作:禁用锁屏
keyguardLock.disableKeyguard();//常用操作:重新启用锁屏
keyguardLock.reenableKeyguard();
接下来从KeyguardManager的2个关键API disableKeyguard和reenableKeyguard来继续分析。
1 disableKeyguard和reenableKeyguard方法入手分析
disableKeyguard和reenableKeyguard的代码实现如下:
public class KeyguardManager {private IWindowManager mWM;private ITrustManager mTrustManager;//...public void disableKeyguard() {try {mWM.disableKeyguard(mToken, mTag);} catch (RemoteException ex) {}}public void reenableKeyguard() {try {mWM.reenableKeyguard(mToken);} catch (RemoteException ex) {}}//...
}
IWindowManager
是一个Binder接口,它定义了一系列管理窗口的方法。在Android系统中,服务通常是通过Binder IPC(进程间通信)机制进行通信的。IWindowManager
接口的实现类是WindowManagerService
,它运行在系统的服务端,并管理所有窗口的状态和行为。
当KeyguardManager
的disableKeyguard()
或reenableKeyguard()
方法被调用时,它们会通过mWM
(即IWindowManager
的实例)向WindowManagerService
发送请求,以禁用或重新启用锁屏。具体代码实现如下:
public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {static final String TAG = "WindowManager";//...@Overridepublic void disableKeyguard(IBinder token, String tag) {//权限检查if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires DISABLE_KEYGUARD permission");}if (token == null) {throw new IllegalArgumentException("token == null");}mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));}@Overridepublic void reenableKeyguard(IBinder token) {//权限检查if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires DISABLE_KEYGUARD permission");}if (token == null) {throw new IllegalArgumentException("token == null");}mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(KeyguardDisableHandler.KEYGUARD_REENABLE, token));}//...
}
针对这KeyguardDisableHandler的sendMessage的消息处理,代码实现如下:
public class KeyguardDisableHandler extends Handler {private static final String TAG = "KeyguardDisableHandler";//...// Message.what constantsstatic final int KEYGUARD_DISABLE = 1;static final int KEYGUARD_REENABLE = 2;static final int KEYGUARD_POLICY_CHANGED = 3;//...@Overridepublic void handleMessage(Message msg) {if (mKeyguardTokenWatcher == null) {mKeyguardTokenWatcher = new KeyguardTokenWatcher(this);}switch (msg.what) {case KEYGUARD_DISABLE:final Pair<IBinder, String> pair = (Pair<IBinder, String>)msg.obj;mKeyguardTokenWatcher.acquire(pair.first, pair.second);break;case KEYGUARD_REENABLE:mKeyguardTokenWatcher.release((IBinder)msg.obj);break;case KEYGUARD_POLICY_CHANGED:mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;if (mKeyguardTokenWatcher.isAcquired()) {// If we are currently disabled we need to know if the keyguard// should be re-enabled, so determine the allow state immediately.mKeyguardTokenWatcher.updateAllowState();if (mAllowDisableKeyguard != ALLOW_DISABLE_YES) {mPolicy.enableKeyguard(true);}} else {// lazily evaluate this next time we're asked to disable keyguardmPolicy.enableKeyguard(true);}break;}}//...
}
接下来着重分析mKeyguardTokenWatcher.acquire和mKeyguardTokenWatcher.release的实现,代码具体实现如下:
class KeyguardTokenWatcher extends TokenWatcher {public KeyguardTokenWatcher(final Handler handler) {super(handler, TAG);}//更新是否允许禁用锁屏的状态。这是通过查询DevicePolicyManager服务来实现的,//它管理设备策略,包括密码质量要求等。public void updateAllowState() {DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);if (dpm != null) {try {//检查当前用户是否有密码质量要求,如果返回PASSWORD_QUALITY_UNSPECIFIED,//则表示没有密码要求,允许禁用锁屏(ALLOW_DISABLE_YES);//否则,不允许禁用锁屏(ALLOW_DISABLE_NO)。mAllowDisableKeyguard = dpm.getPasswordQuality(null,ActivityManagerNative.getDefault().getCurrentUser().id)== DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;} catch (RemoteException re) {// Nothing much we can do}}}//获取到一个令牌时(请求禁用锁屏)@Overridepublic void acquired() {if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {updateAllowState();}if (mAllowDisableKeyguard == ALLOW_DISABLE_YES) {mPolicy.enableKeyguard(false);} else {Log.v(TAG, "Not disabling keyguard since device policy is enforced");}}//释放一个令牌时(请求要启用锁屏)@Overridepublic void released() {mPolicy.enableKeyguard(true);}
}
这里的关键方法为:mPolicy.enableKeyguard,代码具体实现如下:
public class PhoneWindowManager implements WindowManagerPolicy {static final String TAG = "WindowManager";static final boolean DEBUG = false;//.../** {@inheritDoc} */@Overridepublic void enableKeyguard(boolean enabled) {if (mKeyguardDelegate != null) {mKeyguardDelegate.setKeyguardEnabled(enabled);}}//...
}
这里继续分析mKeyguardDelegate.setKeyguardEnabled,代码实现如下:
public class KeyguardServiceDelegate {public static final String KEYGUARD_PACKAGE = "com.android.systemui";public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService";private static final String TAG = "KeyguardServiceDelegate";private static final boolean DEBUG = true;protected KeyguardServiceWrapper mKeyguardService;//...public void setKeyguardEnabled(boolean enabled) {if (mKeyguardService != null) {mKeyguardService.setKeyguardEnabled(enabled);}mKeyguardState.enabled = enabled;}//...
}
注意:这里的mKeyguardState.enabled状态的目的是为了维护一个本地副本,以便快速检查锁屏(Keyguard)是否当前被启用或禁用,而不需要每次都调用KeyguardService来获取这个状态。接下来继续分析mKeyguardService.setKeyguardEnabled,代码实现如下:
public class KeyguardServiceWrapper implements IKeyguardService {private KeyguardStateMonitor mKeyguardStateMonitor;private IKeyguardService mService;private String TAG = "KeyguardServiceWrapper";//...@Override // Binder interfacepublic void setKeyguardEnabled(boolean enabled) {try {mService.setKeyguardEnabled(enabled);} catch (RemoteException e) {Slog.w(TAG , "Remote Exception", e);}}//...
}
继续分析mService.setKeyguardEnabled,代码实现如下:
public class KeyguardService extends Service {static final String TAG = "KeyguardService";static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;//...private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {//...@Override // Binder interfacepublic void setKeyguardEnabled(boolean enabled) {checkPermission();//权限检查mKeyguardViewMediator.setKeyguardEnabled(enabled);}//...}//...
}
KeyguardViewMediator的setKeyguardEnabled,终于到了真正实现功能的部分了。
2 功能实现 KeyguardViewMediator.setKeyguardEnabled方法
接下来继续分析代码,主要关注逻辑功能的实现,代码实现如下:
public class KeyguardViewMediator extends SystemUI {private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;private static final boolean DEBUG = KeyguardConstants.DEBUG;//...public void setKeyguardEnabled(boolean enabled) {synchronized (this) {// 设置锁屏是否被外部启用mExternallyEnabled = enabled;// 如果请求禁用锁屏(enabled为false)且锁屏当前正在显示if (!enabled && mShowing) {// 如果当前有正在进行的解锁操作,则忽略禁用请求if (mExitSecureCallback != null) {return;}// 标记需要在锁屏重新启用时重新显示mNeedToReshowWhenReenabled = true;// 更新输入限制状态updateInputRestrictedLocked();// 隐藏锁屏hideLocked();} else if (enabled && mNeedToReshowWhenReenabled) {// 如果请求启用锁屏且之前有标记需要重新显示mNeedToReshowWhenReenabled = false;// 更新输入限制状态updateInputRestrictedLocked();// 如果当前有解锁操作的回调,则处理解锁结果if (mExitSecureCallback != null) {try {mExitSecureCallback.onKeyguardExitResult(false);} catch (RemoteException e) {Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);}mExitSecureCallback = null;// 重置状态resetStateLocked();} else {// 显示锁屏showLocked(null);// 标记正在等待锁屏变为可见状态mWaitingUntilKeyguardVisible = true;// 延迟发送消息,以便在超时后继续执行mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS);// 等待锁屏变为可见状态while (mWaitingUntilKeyguardVisible) {try {wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}}}}//...
}
这段代码的逻辑确保了锁屏的显示和隐藏能够根据请求和当前状态正确地进行,同时处理了解锁操作的回调和状态同步。整体逻辑可拆解为4个部分:
-
锁屏状态更新:首先,方法同步并更新锁屏的外部启用状态。
-
处理禁用请求:如果请求是禁用锁屏,并且锁屏当前正在显示,会检查是否有正在进行的解锁操作。如果没有,将标记需要在锁屏重新启用时重新显示,并隐藏锁屏。
-
处理启用请求:如果请求是启用锁屏,并且之前有标记需要重新显示,会清除该标记,并根据是否有解锁操作的回调来处理。如果有回调,会处理解锁结果并重置状态。如果没有回调,会显示锁屏,并等待锁屏变为可见状态。
-
等待锁屏可见:在启用锁屏后,通过发送延迟消息和等待机制确保锁屏已经绘制完成,避免在锁屏未完全显示时用户操作导致的问题。
接下来分析两个重要的锁屏功能API:显示锁屏showLocked 和 隐藏锁屏hideLocked。这部分代码向下的分析参考了文章Android SystemUI组件(07)锁屏KeyguardViewMediator分析 的后半部分。代码实现如下:
public class KeyguardViewMediator extends SystemUI {private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;private static final boolean DEBUG = KeyguardConstants.DEBUG;//...handler 发送消息 SHOW/HIDEprivate void showLocked(Bundle options) {if (DEBUG) Log.d(TAG, "showLocked");// ensure we stay awake until we are finished displaying the keyguardmShowKeyguardWakeLock.acquire();Message msg = mHandler.obtainMessage(SHOW, options);mHandler.sendMessage(msg);}private void hideLocked() {if (DEBUG) Log.d(TAG, "hideLocked");Message msg = mHandler.obtainMessage(HIDE);mHandler.sendMessage(msg);}//...handler处理private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case SHOW:handleShow((Bundle) msg.obj);break;case HIDE:handleHide();break;//...}}};//handler关键处理方法handleShowprivate void handleShow(Bundle options) {synchronized (KeyguardViewMediator.this) {// 如果系统还没有准备好,忽略显示锁屏的请求if (!mSystemReady) {return;}// 标记锁屏为显示状态setShowingLocked(true);// 调用状态栏锁屏视图管理器显示锁屏mStatusBarKeyguardViewManager.show(options);// 标记锁屏不是在隐藏状态mHiding = false;// 重置锁屏完成挂起的状态resetKeyguardDonePendingLocked();// 标记没有运行隐藏动画mHideAnimationRun = false;// 更新活动锁屏状态updateActivityLockScreenState();// 调整状态栏adjustStatusBarLocked();// 用户活动事件userActivity();// 在最后执行,以免延迟锁屏显示playSounds(true);// 释放锁屏显示时持有的WakeLockmShowKeyguardWakeLock.release();}// 显示锁屏管理器mKeyguardDisplayManager.show();}private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {@Overridepublic void run() {try {// 通知窗口管理器锁屏正在消失mWM.keyguardGoingAway(mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock(),mStatusBarKeyguardViewManager.isGoingToNotificationShade());} catch (RemoteException e) {Log.e(TAG, "Error while calling WindowManager", e);}}};//handler关键处理方法handleHideprivate void handleHide() {synchronized (KeyguardViewMediator.this) {mHiding = true; // 标记锁屏正在隐藏// 如果锁屏当前正在显示并且没有被遮挡if (mShowing && !mOccluded) {// 如果还没有运行隐藏动画if (!mHideAnimationRun) {// 开始执行预隐藏动画,并在动画结束后执行mKeyguardGoingAwayRunnablemStatusBarKeyguardViewManager.startPreHideAnimation(mKeyguardGoingAwayRunnable);} else {// 如果已经在运行隐藏动画,则直接执行mKeyguardGoingAwayRunnablemKeyguardGoingAwayRunnable.run();}} else {// 如果锁屏没有显示,或者被遮挡,不依赖于WindowManager来启动退出动画// 直接处理开始退出动画handleStartKeyguardExitAnimation(SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),mHideAnimation.getDuration());}}}//...
}
接下来总结下2个关键流程内容:
handleShow
方法,它负责处理显示锁屏的逻辑。具体如下:
- 设置锁屏状态:如果系统已准备好,标记锁屏为显示状态,并调用
mStatusBarKeyguardViewManager.show(options)
来显示锁屏。 - 重置状态:重置锁屏完成挂起的状态,标记没有运行隐藏动画,更新活动锁屏状态,调整状态栏,记录用户活动事件。
- 播放声音:在锁屏显示后播放声音,这通常包括锁屏出现的声音。
- 释放WakeLock:释放在显示锁屏时持有的
mShowKeyguardWakeLock
,以允许设备在锁屏显示后进入休眠状态。 - 显示锁屏管理器:调用
mKeyguardDisplayManager.show()
来显示锁屏管理器。
handleShow
方法的目的是确保在需要时显示锁屏界面,更新系统状态以反映锁屏的显示,并通过播放声音或振动向用户提供反馈,同时保持设备的安全性和良好的用户体验。
handleHide
方法,它负责处理隐藏锁屏的逻辑。具体如下:
- 设置隐藏标志:将
mHiding
标志设置为true
,表示锁屏正在被隐藏。 - 检查锁屏状态:检查锁屏是否正在显示并且没有被遮挡。
- 处理没有显示的锁屏:如果锁屏没有显示或者被遮挡,不依赖于WindowManager来启动退出动画,而是直接调用
handleStartKeyguardExitAnimation
方法来处理开始退出动画。
handleHide
方法的目的是确保在锁屏隐藏时能够正确地执行动画和相关的清理工作。它根据锁屏的当前状态来决定是否启动动画,以及是否直接处理退出动画。这种方法确保了锁屏隐藏过程的平滑和一致性,同时避免了不必要的依赖和潜在的冲突。
接下来我们专注分析show的逻辑实现,这里调用了mStatusBarKeyguardViewManager的show方法,代码具体实现如下:
public class StatusBarKeyguardViewManager {//step1 显示锁屏public void show(Bundle options) {mShowing = true; // 标记锁屏为显示状态mStatusBarWindowManager.setKeyguardShowing(true); // 通知状态栏窗口管理器锁屏正在显示reset(); // 调用reset方法来重置锁屏状态}//step2 重置锁屏状态public void reset() {if (mShowing) {if (mOccluded) {mPhoneStatusBar.hideKeyguard(); // 如果锁屏被遮挡,隐藏锁屏mBouncer.hide(false /* destroyView */); // 隐藏解锁界面(Bouncer)} else {showBouncerOrKeyguard(); // 显示解锁界面或锁屏}updateStates(); // 更新锁屏状态}}//step3 显示解锁界面或锁屏private void showBouncerOrKeyguard() {if (mBouncer.needsFullscreenBouncer()) {mPhoneStatusBar.hideKeyguard(); // 需要全屏解锁界面时,隐藏锁屏mBouncer.show(true); // 显示解锁界面(Bouncer)} else {mPhoneStatusBar.showKeyguard(); // 不需要全屏解锁界面时,显示锁屏mBouncer.hide(false); // 隐藏解锁界面(Bouncer)mBouncer.prepare(); // 准备解锁界面(Bouncer)}}
}
接下来主要解读mBouncer.show和hide的实现及相关流程。主要以show方法(加载视图)为主。接下来继续分析KeyguardBouncer的show方法和hide方法流程,代码具体实现如下:
public class KeyguardBouncer {private Context mContext;//...private final Runnable mShowRunnable = new Runnable() {@Overridepublic void run() {// 设置锁屏视图的可见性为可见mRoot.setVisibility(View.VISIBLE);// 恢复锁屏视图的活动状态mKeyguardView.onResume();// 开始锁屏视图的显示动画mKeyguardView.startAppearAnimation();// 清除锁屏即将显示的标志mShowingSoon = false;}};//...//加载及锁屏界面关键流程//step1 显示锁屏界面public void show() {// 确保锁屏视图已经创建,锁屏View的加载ensureView();// 如果锁屏视图已经是可见的或者即将显示,则不需要再次显示if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {// 更新当前的安全方法,这在锁屏已经显示但当前安全方法发生变化时是必要的mKeyguardView.show();return;}// 尝试dismiss锁屏。如果没有设置安全模式,这将dismiss整个锁屏。// 如果需要认证,则显示解锁界面(Bouncer)。if (!mKeyguardView.dismiss()) {// 设置标志,表示锁屏即将显示mShowingSoon = true;// 在多个帧上分散工作mChoreographer.postCallbackDelayed(Choreographer.CALLBACK_ANIMATION, mShowRunnable,null, 48);}}//step2 确保锁屏视图已经创建private void ensureView() {//检查mRoot(锁屏界面的根视图)是否已经存在。if (mRoot == null) {//加载锁屏界面inflateView();}}//step3 加载锁屏界面private void inflateView() {// 如果之前已经添加过锁屏视图,先将其移除removeView();// 通过LayoutInflater从keyguard_bouncer布局文件中加载锁屏界面布局mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);// 从加载的布局中获取KeyguardViewBase实例mKeyguardView = (KeyguardViewBase) mRoot.findViewById(R.id.keyguard_host_view);// 为锁屏视图设置锁图案工具,用于处理锁屏图案相关逻辑mKeyguardView.setLockPatternUtils(mLockPatternUtils);// 为锁屏视图设置ViewMediatorCallback,用于处理锁屏界面的回调事件mKeyguardView.setViewMediatorCallback(mCallback);// 将锁屏视图添加到容器视图中,确保它在容器的最后面mContainer.addView(mRoot, mContainer.getChildCount());// 初始时将锁屏视图的可见性设置为不可见mRoot.setVisibility(View.INVISIBLE);// 设置系统UI可见性,禁用HOME按钮,这样用户在锁屏界面上不会看到HOME按钮mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);}//...//隐藏锁屏界面关键流程//step1 隐藏锁屏界面public void hide(boolean destroyView) {// 取消任何即将执行的显示锁屏的操作cancelShowRunnable();// 如果锁屏视图不为空,则进行清理if (mKeyguardView != null) {// 移除锁屏视图上的解散动作,即用户不再能通过这个视图解散锁屏mKeyguardView.setOnDismissAction(null);// 清理锁屏视图,这可能包括重置状态、停止动画等mKeyguardView.cleanUp();}// 如果传入的参数destroyView为true,则完全移除锁屏视图if (destroyView) {removeView();} else if (mRoot != null) {// 如果不销毁视图,只是将其设置为不可见mRoot.setVisibility(View.INVISIBLE);}}//step2 锁屏界面不显示,取消线程private void cancelShowRunnable() {// 从Choreographer中移除之前安排的动画帧更新回调mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mShowRunnable, null);// 将mShowingSoon标志设置为false,表示锁屏界面不再即将显示mShowingSoon = false;}
}
其中,StatusBarKeyguardViewManager类中的show方法负责实际显示锁屏界面。它首先将锁屏的显示状态设置为true,然后调用reset方法来重置锁屏状态。reset方法会根据锁屏是否被遮挡来决定是显示解锁界面(Bouncer)还是锁屏界面。
KeyguardBouncer类中的show方法用于显示解锁界面(Bouncer)。如果需要全屏解锁界面,它会隐藏锁屏并显示解锁界面。否则,它会显示锁屏并隐藏解锁界面,并准备解锁界面以供用户输入。
KeyguardBouncer类中的hide方法用于隐藏解锁界面。它会取消任何即将执行的显示操作,并根据传入的参数决定是销毁视图还是仅仅将其设置为不可见。
这些方法共同工作,确保了锁屏界面能够在适当的时机显示或隐藏,同时提供了用户反馈和设备安全性。
相关文章:

Android SystemUI组件(10)禁用/重启锁屏流程分析
该系列文章总纲链接:专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明: 说明:本章节持续迭代之前章节的思维导图,主要关注左侧上方锁屏分析部分 应用入口处理流程解读 即可。 在 Android 系统中,禁用锁屏…...

【Geeksend邮件营销】外贸邮件中的一些常用语
外贸邮件中的相关术语丰富多样,涉及邮件的开头、正文、结尾以及特定的商务用语。以下是一些常用的外贸邮件术语及其解释: 一、邮件开头用语 1、问候语: Dear [收件人姓名], Trust this email finds you well. How are you? …...

配置静态ip
背景:因业务需要需要将一台服务器从机房搬到实验室,机房是光纤,实验室是网线,需要重新配置下静态ip 确认网络配置文件(网上没找到,不清楚一下方法对不对) 先随便一个网口连接网线,执行 ifconfig -a 找到带“RUNNING”的(lo不是哈)----eno1 到/etc/sysconfig/network…...

[LeetCode] LCR170. 交易逆序对的总数
题目描述: 在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录 record,返回其中存在的「交易逆序对」总数。 示例 1: 输入:…...

大开眼界,原来指针还能这么玩?
文章目录 第一阶段:基础理解目标:内容:题目:答案解析: 第二阶段:指针与数组目标:内容:题目:答案解析: 第三阶段:指针与字符串目标:内容…...

揭秘选择知识产权管理系统的常见误区,避免踩坑
在当今知识经济时代,知识产权管理对于企业的发展至关重要。为了提高管理效率和效果,许多企业纷纷选择采用知识产权管理系统。然而,在选择过程中,存在着一些容易陷入的误区。 误区一:只关注功能,忽视用户体验…...

计算机组成原理之存储器的分类
1、按存储介质分类: 半导体存储器:使用半导体器件作为存储元件,如TTL和MOS存储器。这类存储器体积小、功耗低、存取时间短,但断电后数据会丢失。 磁表面存储器:使用磁性材料涂覆在金属或塑料基体表面作为存储介质&…...

Linux(不同版本系统包含Ubuntu)下安装mongodb详细教程
一、下载MongoDB 在MongoDB官网下载对应的MongoDB版本,可以点击以下链接快速跳转到下载页面: mongodb官网下载地址 注意选择和自己操作系统一致的platform,可以先查看自己的操作系统 查看操作系统详情 命令: uname -a 如图:操…...

如何扫描HTTP代理:步骤与注意事项
HTTP代理是一个复杂的过程,通常用于寻找可用的代理服务器,以便在网络中实现匿名或加速访问。虽然这个过程可以帮助用户找到适合的代理,但也需要注意合法性和道德问题。本文将介绍如何扫描HTTP代理,并提供一些建议和注意事项。 什…...

【分布式微服务云原生】gRPC与Dubbo:分布式服务通信框架的双雄对决
目录 引言gRPC:Google的高性能RPC框架gRPC通信流程图 Dubbo:阿里巴巴的微服务治理框架Dubbo服务治理流程图 表格:gRPC与Dubbo的比较结论呼吁行动Excel表格:gRPC与Dubbo特性总结 摘要 在构建分布式系统时,选择合适的服务…...

Python | Leetcode Python题解之第450题删除二叉搜索树中的节点
题目: 题解: class Solution:def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:cur, curParent root, Nonewhile cur and cur.val ! key:curParent curcur cur.left if cur.val > key else cur.rightif cur i…...

[Linux]从零开始的网站搭建教程
一、谁适合本次教程 学习Linux已经有一阵子了,相信大家对LInux都有一定的认识。本次教程会教大家如何在Linux中搭建一个自己的网站并且实现内网访问。这里我们会演示在Windows中和在Linux中如何搭建自己的网站。当然,如果你没有Linux的基础,这…...

牛客——xay loves or与 __builtin_popcount的使用
xay loves or 题目描述 登录—专业IT笔试面试备考平台_牛客网 运行思路 题目要求我们计算有多少个正整数 yy 满足条件 x \text{ OR } y sx OR ys。这里的“OR”是指按位或运算。为了理解这个问题,我们需要考虑按位或运算的性质。 对于任意两个位 a_iai 和 b_…...

Docker学习和部署ry项目
文章目录 停止Docker重启设置开机自启执行docker ps命令,如果不报错,说明安装启动成功2.然后查看数据卷结果3.查看数据卷详情结果4.查看/var/lib/docker/volumes/html/_data目录可以看到与nginx的html目录内容一样,结果如下:5.进入…...

Linux中设置cd命令后直接显示当前目录下的所有文件
Linux中cd命令后默认是不显示该目录下的文件的,略微不方便。换个环境经常遇到需要重新设置的情况,网上已有很多发帖了,这里主要汇总下比较简单且常见的bash与csh下的设置方法。 实现的本质就是将"cd" 与 "ls"组合起来&am…...

【RTCP】报文学习笔记
在学习中,发现每一篇都只能窥探其中一部分内容。因此学习了多个大神的文章,记录如下: 参考希望_睿智 大神的文章:从零开始精通RTSP之深入理解RTCP协议, 大神对于细节表述非常到位。 read_book/RTP_RTCP /RTP_RTCP协议内容–精选自译.md 大神提供了更多更为详细的信息。 ZL…...

Solidity优质例子(二)物流的增删改查智能合约(附truffle测试)
本合约非常适合新手学习,其包含了基本的增删改查功能以及各个方式的不同之处的总结,本套合约我也编写了truffle测试,学习truffle测试的小伙伴也有福了~ 该合约的主要作用是通过区块链技术实现物流追踪系统的透明化、自动化与防篡改特性&#…...

对android binder的一些疑问及解答
1上层做了那么多封装是否是过度了,难度增加就在于上层的一层层的封装。 最底层直接ioctl和binder驱动交互(单纯c语言实现binder交互) 第一层:IPCThreadState.transatct封装了对驱动的请求和接受 第二层封装用IBinder.h里面…...

主流麦克风阵列有哪些?
麦克风阵列在HiFi音频方案中是非常重要的一种方案。它的重要性主要体现在音质提升、环境适应性、噪声处理和空间感创造等方面。以下是它的核心作用: 1. 高精度的声音捕捉 在HiFi音频解决方案中,清晰而高保真的声音捕捉是至关重要的。麦克风阵列可以通过…...

几个快速压缩图片大小的方法!
几个快速压缩图片大小的方法!在当今这个视觉主导的时代,图片已成为我们日常生活中不可或缺的一部分,它们承载着从壮丽风景到办公文档的各类信息,每个人的电子设备中,往往都保存着海量的图片文件,然而&#…...

怎么避免在pod产生-派生炸弹(Fork Bomb)? k8s(kubernetes)
通过修改kubelet的配置,限制每个pod能用的pid数量即可解决此问题。 kubelet 可以通过设置PodPidsLimit参数来限制每个容器内的进程数量。 1.【kubelet节点】 /var/lib/kubelet/config.yaml文件中添加如下的内容 # 500仅仅是举例 podPidsLimit: 5002.【kubelet节点…...

MySQL中的嵌套查询
1. 嵌套查询的定义 嵌套查询指在一个查询语句的某个部分嵌入一个子查询。 嵌套查询的执行过程遵循“先子查询、后外层查询”的逻辑。首先,子查询执行并返回一个结果集,可能是一个值、一行或多行数据。接着,外层查询使用子查询的结果继续对数…...

win10 提示pl2303hxa已停产,请联系供货商解决方案
1. 下载驱动 需要下载老版的驱动,下载地址:https://www.pcsoft.com.cn/soft/211569.html 选择普通下载 或者从CSDN下载: 2. 安装驱动 下载完成后安装下载好的驱动文件,安装后更新pl2303的驱动,如下:…...

浙大数据结构:07-图5 Saving James Bond - Hard Version
这道题也是很有难度,我最开始尝试用Dijkstra来做,发现不是很好处理,用bfs还不错。 机翻: 1、条件准备 n为鳄鱼数量,jump为跳跃距离,headjump为第一次跳跃距离,包括了岛的半径。 isalive标识…...

【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL69
脉冲同步器(快到慢) 描述 sig_a 是 clka(300M)时钟域的一个单时钟脉冲信号(高电平持续一个时钟clka周期),请设计脉冲同步电路,将sig_a信号同步到时钟域 clkb(100M&…...

电商商品数据采集||高并发||多语言请求实例演示|京东|淘宝商品详情数据SKU价格
以京东商品数据采集为例 京东商品详情接口数据采集是指通过调用京东提供的商品详情API接口,获取商品的详细信息。以下是一个简单的步骤来实现这个功能: 1. 注册京东开发者账号 首先,你需要注册一个京东开发者账号,并创建一个应…...

云手机哪款好用?2024年云手机推荐对比指南
随着云手机市场的快速扩展,消费者在选择云手机时面临着众多选择。为了帮助大家找到最适合自己的云手机,小编特意整理了一份当前市场上几款备受关注的云手机品牌对比,大家一起往下看吧。 1. Ogphone云手机 Ogphone云手机是近年来海外业务版块迅…...

无人机航测内业常用建模软件手册下载(上)
航测项目外业离不开无人机,内业离不开制图软件。 无人机航测外业作业包括控点布设、航线规划、仿地飞行、航拍等流程,而内业数据处理则常涉及到CC、Pix4D、PhotoScan、大疆智图、重建大师、M3D、瞰景Smart3D、天工等软件。 我们整理了这些常用建模软件…...

Python Django ORM 的工作原理
在 Web 开发中,处理数据库是非常常见的需求,尤其是在构建动态应用程序时。Django 作为一个流行的 Python Web 框架,提供了一套强大的工具帮助开发者轻松管理数据库。Django 的 ORM(对象关系映射,Object-Relational Map…...

GoLang编程常用规范/工具
代码格式化工具 代码风格: go install github.com/fsgo/go_fmt/cmd/gorgeouslatest gorgeous # 仅格式化git有改动的文件。如需格式化所有文件,可以执行 gorgeous ./...标签格式:https://github.com/4meepo/tagalign go install github.c…...