概述

P-Sensor亮屏和按Power键亮屏流程还是有些不同之处,如开始调用位置、PowerManagerService中的流程等,由于在平常遇到过许多PSensor亮屏相关Bug,因此这里独立地进行下分析。

流程

在DisplayPowerController中,实例化了一个SensorEventListener对PSensor事件进行监听:

private final SensorEventListener mProximitySensorListener = new SensorEventListener() {@Overridepublic void onSensorChanged(SensorEvent event) {if (mProximitySensorEnabled) {//获取当前系统时间final long time = SystemClock.uptimeMillis();//获取distance值,表示距离final float distance = event.values[0];//如果distance>=0.0fboolean positive = distance >= 0.0f && distance < mProximityThreshold;//处理PSensor上报事件handleProximitySensorEvent(time, positive);}}

SensorEventListener是一个用于接收Sensor新数据的接口,只有两个方法:

  • onSensorChanged(SensorEvent event):当有新Sensor事件时进行回调;
  • onAccuracyChanged(Sensor, int accuracy):Sensor注册的精度值发生改变时调用;

在DisplayPowerController中,重写了onSensorChanged()方法,因此,在接收到PSensor新事件时,会回调该方法。在这个方法中可以看到,只有mProximitySensorEnabled这个全局变量为true时,才会进入该方法体,这个值表示PSensor是否可用,由屏幕状态和PMS中的请求参数useProximitySensor共同决定,只有满足useProximitySensor=true && state!=Display.STATE_OFF时,该值才会为true,而useProximitySensor=true的条件是当前系统持有PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK类型的锁。

现在进入方法体中,它记录了当前系统时间,并根据SensorEvent判断是否是靠近还是远离后,将time和distance作为参数传给了handleProximitySensorEvent()方法,该方法如下:

private void handleProximitySensorEvent(long time, boolean positive) {//PSensor是否可用,由setProximitySensorEnabled()方法根据PMS中请求的参数
//useProximitySensor和STATE_OFF决定if (mProximitySensorEnabled) {//mPendingProximity表示"将要进行的PSensor状态",初始值为// PROXIMITY_UNKNOWN,PROXIMITY_NEGATIVE&&positive=false都表示远离,// 所以没有值变化,直接返回,下同if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {return; // no change}if (mPendingProximity == PROXIMITY_POSITIVE && positive) {return; // no change}//取消延迟处理Psensor事件的HandlermHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);//如果是靠近if (positive) {//设置mPendingProximity 值,PROXIMITY_POSITIVE表示靠近设备mPendingProximity = PROXIMITY_POSITIVE;//设置PSensor去抖动时间(或转换延迟时间),会申请一个Display锁// 靠近时立即灭屏setPendingProximityDebounceTime(time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); } else {mPendingProximity = PROXIMITY_NEGATIVE;//设置去抖动时间,远离时会稍等会再亮屏setPendingProximityDebounceTime(time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); }// Debounce the new sensor reading.//读取新Psensor数据debounceProximitySensor();}
}

在这个方法中,如果PSensor数据没有改变,则直接返回。如果上报值发生了改变,则首先设置mPendingProximity,表示“将要、打算进行的PSensor事件”,如果是靠近则设置该变量值为PROXIMITY_POSITIVE,远离则设置该变量值为PROXIMITY_NEGATIVE,同时调用setPendingProximityDebounceTime()方法,该方法用来设置PSensor的转换延迟时间,并会通过DisplayPowerCallback向PMS中申请一个Display锁,如果是靠近,延迟时间为0,也即不会进行延迟;如果是远离,默认延迟时间为250。该方法如下:

private void setPendingProximityDebounceTime(long debounceTime) {if (mPendingProximityDebounceTime < 0) {//申请一个PowerManagerService.Display的SuspendBlocker锁mCallbacks.acquireSuspendBlocker(); // acquire wake lock}//PSensor转换延迟时间mPendingProximityDebounceTime = debounceTime;
}

当设置完毕mPendingProximity和mPendingProximityDebounceTime后,会调用debounceProximitySensor()方法,读取新的PSensor数据,该方法如下:

private void debounceProximitySensor() {if (mProximitySensorEnabled&& mPendingProximity != PROXIMITY_UNKNOWN&& mPendingProximityDebounceTime >= 0) {//获取当前系统时间final long now = SystemClock.uptimeMillis();//如果mPendingProximityDebounceTime <= now,说明是靠近事件或者延迟事件到达,//直接进行下一步处理if (mPendingProximityDebounceTime <= now) {// Sensor reading accepted.  Apply the change then release the wake lock.//mProximity表示反应给系统的PSensor事件值,这里进行赋值表示接受Sensor读取值mProximity = mPendingProximity;//更新状态的核心方法updatePowerState();//更新完成后,清除延迟时间、释放Display锁clearPendingProximityDebounceTime(); // release wake lock (must be last)} else {// Need to wait a little longer.// Debounce again later.  We continue holding a wake lock while waiting.//如果mPendingProximityDebounceTime > now,说明有延迟,是远离事件,//通过Handler延迟处理事件,到达延迟时间后会重新调用该方法Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);}}
}

在这个方法中,首先会通过系统当前时间和mPendingProximityDebounceTime进行比较,这个值在setPendingProximityDebounceTime()中设置,前面已经说过。如果当前时间大于等于后者,说明没有延迟,则直接调用下一步逻辑;反之则说明有延迟,通过Handler异步处理延迟,并在到达延迟后会重新调用该方法,进行下一步逻辑的调用,先看看延迟转换的处理:

@Override
public void handleMessage(Message msg) {switch (msg.what) {.......case MSG_PROXIMITY_SENSOR_DEBOUNCED:debounceProximitySensor();break;

因此,PSensor事件不管是延迟转换还是不进行延迟,都会进入该方法的if语句中执行相同的逻辑。
在进入if语句后,首先是将mPendingProximity值设置给mProximity,mProximity表示最终系统的PSensor事件状态值,所以可以理解为接受PSensor新的事件状态值。然后调用updatePowerState()方法开始更新屏幕状态,最后当upatePowerState()方法执行完毕后,调用clearPendingProximityDebounceTime()方法,该方法会重置PSensor转换延迟时间、释放Display锁,如下:

private void clearPendingProximityDebounceTime() {if (mPendingProximityDebounceTime >= 0) {//重置PSensor转换时间mPendingProximityDebounceTime = -1;//释放Display锁mCallbacks.releaseSuspendBlocker(); // release wake lock}
}

现在我们开机进入updatePowerState()方法中进行分析,这个方法在第一篇中已经分析了,更详细的分析请见第一篇内容.这里主要来看PSensor相关的部分:

private void updatePowerState() {//....................................// Apply the proximity sensor.if (mProximitySensor != null) {//如果mPowerRequest.useProximitySensor=true&&Display状态不等于灭屏状态if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {//设置Psensor可用setProximitySensorEnabled(true);if (!mScreenOffBecauseOfProximity&& mProximity == PROXIMITY_POSITIVE) {//该值表示是否由PSensor灭屏mScreenOffBecauseOfProximity = true;//通过DisplayPowerCallback回调PMSsendOnProximityPositiveWithWakelock();}//如果释放PSensor锁时带有PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记,则该值为true} else if (mWaitingForNegativeProximity&& mScreenOffBecauseOfProximity&& mProximity == PROXIMITY_POSITIVE&& state != Display.STATE_OFF) {setProximitySensorEnabled(true);} else {//设置PSensor不可用setProximitySensorEnabled(false);mWaitingForNegativeProximity = false;}//如果满足说明此时PSensor处理远离事件,重置mScreenOffBecauseOfProximity为falseif (mScreenOffBecauseOfProximity&& mProximity != PROXIMITY_POSITIVE) {mScreenOffBecauseOfProximity = false;sendOnProximityNegativeWithWakelock();}} else {mWaitingForNegativeProximity = false;}
//由PSensor灭屏为true,则将state置位DISPLAY.STATE_OFFif (mScreenOffBecauseOfProximity) {state = Display.STATE_OFF;}/*-------------PSensor设置 end--------------*///获取屏幕状态,此时还未设置新的屏幕状态,因此是”旧”的final int oldState = mPowerState.getScreenState();//在这个方法中会进行屏幕状态、亮度的设置和处理亮灭屏动画animateScreenStateChange(state, performScreenOffTransition);//获取屏幕状态,此时已经设置新的屏幕状态state = mPowerState.getScreenState();// ........................
}

现在来分析一下updatePowerState()方法的以上逻辑。对于以上逻辑,我们分别对PSensor灭屏和PSensor亮屏逻辑分开进行分析。

1.PSensor灭屏

先看看下PSensor灭屏的逻辑,如果PMS请求时携带的useProximitySensor 值为true,表示此时系统持有PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK锁,同时如果当前屏幕状态不为灭屏状态(Display.STATE_OFF),则:

  • 1.通过setProximitySensorEnabled()方法将PSensor设置为enable状态,即可用状态;
  • 2.将mScreenOffBecauseOfProximity值设置为true,表示由PSensor灭屏,并将请求屏幕状态值设置为Display.STATE_OFF;
  • 3.通过sendOnProximityPositiveWithWakelock()方法回调PMS中,通知PMS在DIC中进行了PSensor灭屏。

setProximitySensorEnabled()方法如下:

private void setProximitySensorEnabled(boolean enable) {if (enable) {if (!mProximitySensorEnabled) {// Register the listener.// Proximity sensor state already cleared initially.mProximitySensorEnabled = true;//将PSensor设置为可用状态//注册PSensor事件接收器mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,SensorManager.SENSOR_DELAY_FASTEST, mHandler);}} else {//设置PSensor不可用状态if (mProximitySensorEnabled) {// Unregister the listener.// Clear the proximity sensor state for next time.mProximitySensorEnabled = false;//将PSensor设置为不可用状态mProximity = PROXIMITY_UNKNOWN;//重置mProximity值为初始值mPendingProximity = PROXIMITY_UNKNOWN;//重置mPendingProximity值为初始值mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);//解除PSensor事件接收器mSensorManager.unregisterListener(mProximitySensorListener);clearPendingProximityDebounceTime(); // 清除去抖动时间,释放Display锁}}
}

setProximitySensorEnabled()中,根据传入参数决定PSensor是否可用,同时注册或解除PSensor事件接收器,这个接收器就是刚开始分析时监听PSensor上报值的Listener,实际上,这部分逻辑应该在接受PSensor上报值之前,因为只有注册了接受器,才能接收上报值,但便于流程分析,就放在这里分析了。
sendOnProximityPositiveWithWakelock()方法如下:

private void sendOnProximityPositiveWithWakelock() {//回调到PMS中,申请Display锁mCallbacks.acquireSuspendBlocker();mHandler.post(mOnProximityPositiveRunnable);
}
private final Runnable mOnProximityPositiveRunnable = new Runnable() {@Overridepublic void run() {//将PMS中mProximityPositive值置为truemCallbacks.onProximityPositive();//释放Display锁mCallbacks.releaseSuspendBlocker();}
};

在以上方法中,mCallbacks对象就是PMS中mDisplayPowerCallbacks对象,因此这里会回调到PMS中去,在PMS中回调的三个方法如下:

@Override
public void acquireSuspendBlocker() {mDisplaySuspendBlocker.acquire();
}
@Override
public void releaseSuspendBlocker() {mDisplaySuspendBlocker.release();
}
@Override
public void onProximityPositive() {synchronized (mLock) {mProximityPositive = true;mDirty |= DIRTY_PROXIMITY_POSITIVE;updatePowerStateLocked();}
}

前两个方法用来申请、释放Display锁,onProximityPositive()方法中内容稍后分析。
回到DPC中,当执行完以上流程后,调用animateScreenStateChange()设置屏幕状态、背光值,除一点外:
当执行进入到setScreenState()后:

    private boolean setScreenState(int state, boolean reportOnly) {//......final boolean isOff = (state == Display.STATE_OFF);if (isOff && !mScreenOffBecauseOfProximity) {setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF);}//......}

也就是说,PSensor灭屏,不会设置mReportedScreenStateToPolicy值,所以PSensor灭屏后,这个值依旧为亮屏时的REPORTED_TO_POLICY_SCREEN_ON(2),所以不会有blockScreenOff()unblockScreenOff()的调用。

之后的流程就和Power键灭屏流程相同了,这里就不再分析,请参考DisplayPowerController第一篇分析。

PSensor灭屏时PMS中做了什么?

在上面我们分析到了PMS中的回调,现在继续看看回调onProximityPositive()时,更细节的内容。
onProximityPositive()方法中,首先会将mProximityPositive置为true,然后置位mDirty,最后调用PMS核心updatePowerStateLocked()方法。需要注意的是,在调用updatePowerStateLocked()方法时,由于mDirty值不满足条件,这里不会执行其中的几个updatexxx()方法,只会执行最后一个updateSuspendBlockerLocked()方法,我们只看以下部分:

private boolean needDisplaySuspendBlockerLocked() {//请求Policy为亮屏if (mDisplayPowerRequest.isBrightOrDim()) {//以下条件任意一个为false,则表示需要Display锁,因此不会进入Suspend状态if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive|| !mSuspendWhenScreenOffDueToProximityConfig) {return true;}}return false;
}

以上方法逻辑很简单,其中三个条件任意一个为false,则该方法将返回true,不会释放Display锁。
mSuspendWhenScreenOffDueToProximityConfig表示当由PSensor灭屏后,是否可以进入Suspend状态,该值从配置文件中获取:

mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);

因此如果该值配置为true,则表示当PSensor灭屏后可以进入Suspend状态,实现原因就是这部分逻辑。
再来看看mProximityPositive这个值的用处,除了上面判断是否需要Display锁之外,还有一个地方:

private boolean isBeingKeptAwakeLocked() {return mStayOn|| mProximityPositive|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT| USER_ACTIVITY_SCREEN_DIM)) != 0|| mScreenBrightnessBoostInProgress;
}

这个方法在分析PMS时分析了,判断是否需要保持唤醒状态,只要任意一个条件为true,则系统就不能进入休眠中状态。
因此,当PSensor灭屏后,不会存在超时进入GoToSleep的逻辑。

2.PSensor亮屏

现在继续回到DPC中,来看看PSensor亮屏时的updatePowerState()方法。在调用到updatePowerState()方法之前,PSensor事件接收器接收到远离事件上报值,将mProximity值置为PROXIMITY_NEGATIVE,然后调用到updatePowerState()后,根据条件判断,则:

  • 1.将mScreenOffBecauseOfProximity值置为false;
  • 2.通过sendOnProximityNegativeWithWakelock()方法回调PMS中,通知PMS在DIC中进行了PSensor亮屏。

此时PMS中请求的屏幕状态依旧为Display.STATE_ON,接下来的步骤和原来的步骤相同,除一点外:
当执行进入到setScreenState()后:

isOff = (state == Display.STATE_OFF) = false;
mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_ON;

所以不满足任何一个条件,因此,不会有blockScreenOn()blockScreenOn(),也就是说,PSensor的亮屏不需要WindowManger中的相关回调。

剩下的流程和Power键等亮屏流程完全一样。

这里再来看下sendOnProximityNegativeWithWakelock()方法:

private void sendOnProximityNegativeWithWakelock() {mCallbacks.acquireSuspendBlocker();mHandler.post(mOnProximityNegativeRunnable);
}
private final Runnable mOnProximityNegativeRunnable = new Runnable() {@Overridepublic void run() {mCallbacks.onProximityNegative();mCallbacks.releaseSuspendBlocker();}
};

这个方法中还是回调到PMS中的逻辑,其中释放锁和申请锁的已经分析过,再来看看onProximityNegative()方法:

@Override
public void onProximityNegative() {synchronized (mLock) {//将mProximityPositive 置为falsemProximityPositive = false;mDirty |= DIRTY_PROXIMITY_POSITIVE;//更新用户活动时间userActivityNoUpdateLocked(SystemClock.uptimeMillis(),PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);updatePowerStateLocked();}
}

在这个方法中,将mProximityPositive置为false,同时更新用户活动时间,然后执行updatePowerStateLocked()方法。

总结

分析到这里,整个PSensor亮灭屏的流程就总结完毕,并且从整个分析来看,PSensor亮灭屏,仅仅是修改屏幕状态的背光值,不会像Power键灭屏一样,使系统进入休眠状态。

然而,正是这个原因,在PSensor灭屏后,如果按Power键,是不会亮屏的,这有时候会带来一些用户体验问题,现在市面上好多手机,都会这块有修改,即在PSensor灭屏后,可以通过Power键亮屏,即PSensor灭屏也走休眠流程,这样做的好处显而易见;但是这样一来,好像违反了PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK锁的设计初衷了(该锁表示如果由PSensor导致的灭屏,那么是不会进入休眠状态的, 被视为是持续的用户活动。)

常见问题

Q:PSensor亮灭屏和其他亮灭屏区别?
  • 1.PSensor亮灭屏不存在Wakeup和goToSleep流程;
  • 2.PSensor亮灭屏不需要WindowManager中的回调(unblockScreenOn).
Q:PSensor灭屏后,到达设置休眠时间后会不会进入休眠?

不会,原因如下:

private boolean isBeingKeptAwakeLocked() {return mStayOn|| mProximityPositive //为true,该方法返回true|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT| USER_ACTIVITY_SCREEN_DIM)) != 0|| mScreenBrightnessBoostInProgress;
}
Q:PSensor灭屏后按Power键,为何不会亮屏?

通过对整个DisplayPowerController的流程分析,在通话过程中,对于PSensor灭屏,只会修改其屏幕状态和背光,因此,如果在PSensor灭屏后,第一次按Power键,此时PMS中向Display请求状态时,mWakefulness值为sleep,即要进行睡眠,系统执行goToSleep流程。由于屏幕状态已经为STATE_OFF,背光值为0,因此只会做setScreenState()之前的工作,如调用WindowManager.setScreenTurnedOff,setScreenTruningOff()等,完成真正意义上的灭屏。
而当goToSleep时,PMS中会忽略掉PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK类型的WakeLock锁:

if (mWakefulness == WAKEFULNESS_ASLEEP) {mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;}

因此,当进入DisplayPowerController后,mPowerRequest.useProximitySensor将为false,结合updatePowerState()中的判断条件,此时PSensor将会被解除注册,之后将收不到PSensor消息。

接着,我们第二次按Power键,此时系统将执行wakeUp流程,当进入DisplayPowerController后,mPowerRequest.useProximitySensor将为true,结合updatePowerState()中的判断条件,此时PSensor将会被重新注册,由于用户操作未远离设备,故将立即上报PSensor靠近时间,从而由将屏幕设置为灭屏状态,之后如果抬起PSensor,将才会亮屏。

此外,如果由PSensor灭屏后,当释放PSensor的WakeLock时,携带flag值PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY,此时按Power键也不会立即唤醒,这种情况下DisplayPowerController中的参数mWaitingForNegativeProximity为true,之后的执行逻辑和上面分析的差不多。

Q:如何修改使得在PSensor灭屏后,可以被Power键亮屏,在Power键灭屏后,可以被PSensor亮屏?

暂无

Android 8.1 DisplayPowerController(二) Proximity Sensor的亮灭屏相关推荐

  1. Android 系统(41)---Android7.0 PowerManagerService亮灭屏分析(二)

    Android7.0 PowerManagerService亮灭屏分析(二) 3029 在PowerManagerService中对各种状态进行判断后,将其数值封装进DisplayPowerReque ...

  2. Android 系统(40)--Android7.0 PowerManagerService亮灭屏分析(一)

    Android7.0 PowerManagerService亮灭屏分析(一) 可以导致手机亮灭屏的因素有多种,而在本文中主要讲解按power键亮灭屏过程以及来电亮屏.在亮灭屏过程power中主要的实现 ...

  3. Android 系统(42)---Android7.0 PowerManagerService亮灭屏分析(三)

    Android7.0 PowerManagerService亮灭屏分析(三) 在前面两部分已经对绘制windows与设置设备状态进行了详细讲解. 之后接着就该对亮度值进行设置, 实现亮屏动作了. 在D ...

  4. 结合源码探讨Android距离传感器亮灭屏机制

    结合源码探讨Android距离传感器亮灭屏机制 本文的分析是基于Android 5.0.0 Google原生代码的. Android中的距离传感器,也就是P-sensors(Proximity Sen ...

  5. Android7.0 PowerManagerService亮灭屏分析(二)

    在PowerManagerService中对各种状态进行判断后,将其数值封装进DisplayPowerRequest中传入DisplayPowerController中进一步处理.在亮屏过程中Disp ...

  6. Android 知识点 109 —— Android7.0 PowerManagerService 之亮灭屏

    原文地址: https://www.cnblogs.com/dyufei/p/8017604.html 写的太好了,粘过来! 本篇从按下power按键后,按键事件从InputManagerServic ...

  7. Android7.0 PowerManagerService 之亮灭屏(二) PMS 电源状态管理updatePowerStateLocked()...

    本篇注意接着上篇[Android7.0 PowerManagerService 之亮灭屏(一)]继续分析量灭屏的流程,这篇主要分析PMS的状态计算和更新流程,也是PMS中最为重要和复杂的一部分电源状态 ...

  8. Android 8.0 手机亮灭屏

    本文主要跟踪分析通过按松power键来唤醒,熄灭屏幕的逻辑.下面是一些相关类的介绍 PowerManagerService.java:简称PMS,负责Andorid系统中电源管理方面的工作.作为系统核 ...

  9. android 亮灭屏流程

    1. frameworks\base\core\java\android\hardware\display\DisplayManagerInternal.java 内部服务 frameworks\ba ...

最新文章

  1. 模型数据的保存和读取
  2. JavaScript改变 HTML 内容
  3. mac terminal常用命令接触
  4. socket编程 及select poll epoll示例
  5. linux 酷炫的命令行
  6. 204. Count Primes
  7. 高扫后督解决方案 力助银行内部核查
  8. Package vim is not available, but is referred to by another package.
  9. Zookeeper 安装部署
  10. ***PHP各种编码的汉字字符串截取
  11. The Windows Phone Emulator wasn't able to create the external network switches 解决方法
  12. 让你的Hybrid App听懂你的话(Android篇)
  13. 区块链 single共识
  14. HTML 打开新页面 关闭,javascript打开新窗口同时关闭旧窗口
  15. 为什么浏览器要阻止跨域
  16. 用asp.net写的一个购物网站
  17. [转载]项目风险管理七种武器-长生剑
  18. 页式存储中的逻辑地址与物理地址之间的解析过程
  19. 《仿大众点评仿美团做一个评价网站——Java SSM》项目研发阶段性总结
  20. 泰克示波器CVI开发|泰克示波器波形抓取数据控制软件NS-Scope

热门文章

  1. (原创)六度拓扑(www.6dtop.com)---超乎想像的人际关系网络
  2. linux如何更改密钥环密码,Linux系统教程:Ubuntu桌面上禁用默认的密钥环解锁提示...
  3. 关于销售订单高级定价的一点疑惑
  4. oracle安装后,电脑变得很卡,解决办法(安装的是oracle11g)
  5. 结合《穹顶之下》看中、美宽带提速
  6. SSR门户项目爬坑之路(一)
  7. (附源码)springBoot高校宿舍交电费系统 毕业设计 031552
  8. IDEA生成springboot项目的两种方式
  9. 西安恒智小寨java_长安反编译工具 java
  10. 电脑误删的文件怎么恢复?分享90%的人都会的这2招