天天看點

OSX: Mac不睡眠的排查

Mac電腦不睡眠的問題,貌似簡單其實水不淺,尤其是它有點怪異惱人,可謂是Mac典型的最詭異的問題之一了,在Windows視窗世界,這個似乎不是一個問題,到了Mac了幾乎就成了痼疾了。

雖然蘋果有官方文檔講述這個問題的解決方法,還算比較的詳細:如果您的 Mac 不會進入睡眠或者保持睡眠狀态。但這個問題的詭異就在于,其表象看上去一樣,導緻表象的軟體硬體因素卻千差萬别,看看官方文檔,你會覺得:瓦,太複雜了。如果一個人能把文檔中所有的詳細步驟都記下來,在網上是不是也是大拿一個級别的了?

而為了能夠找到問題的根本,系統的内在因素就是我們關心的。為了能夠幫助大家解惑答疑-本文希望做到的,本文試圖從多個方面盡量詳盡地分析可能造成此類問題的原因,并運用OSX提供的系統方法來監測和甄别問題的具體原因,并嘗試盡量給出解決辦法。其實,反過來說也涉及到了如何讓蘋果機不進入睡眠的各種可能,比如使用現成軟體,或者系統内部支援的指令,甚至自己程式設計實作也可以。總之,咱們在研讀原蘋果官方文檔的基礎上,可以進一步,了解和作業系統内部設定,做到對蘋果機控制自如。

因為本文多數内容涉及硬體和系統内部運作機制以及對系統資訊的分析和操作,是以不适合普通使用者,最好在有經驗的技術人員的幫助下進行,并且了解相關說明内容再變更系統設定。

一般因素:

我們還是羅列一下吧,普通軟體可能是最常見的原因,比如可以看看下面進行排查:

  1. 是否iTunes播放音樂,它會禁止Mac電腦進入睡眠,以保持音樂的播放
  2. Dropbox在上傳/下載下傳檔案, 可以禁止LAN sync來解決.
  3. 解除安裝Drobo Dashboard.
  4. 退出Google Drive.
  5. 其他的軟體,如smcFanControl程式。
  6. 還有專門禁止睡眠的軟體,如:InsomniaX,Caffeine,NoSleep和wimoweh等等
  7. 系統資源共享,比如網際網路/檔案共享等

看到第6條了,如果你希望使用現成軟體來不讓機器睡眠,那麼這些軟體可以考慮。

正文開始:

其實,不睡眠的根本原因有兩個方面可能,一個是某個程式禁止系統進行睡眠,它是通過對系統所支援的斷言(assertions)機制來實作的,下面會詳細說;另一種情況是Mac雖然睡眠了後來接收到了喚醒消息,因為使用者可能無意或者忘記或者沒有意識到這些設定産生的影響,造成系統對特殊信号進行系統喚醒響應。是以,下面從兩個方面來說明,如何下手檢查。

在進一步分析之前,最好确認,系統是否設定了睡眠(是否禁止),可以到節能系統配置中檢視,或者使用OSX提供的能源管理的指令pmset。對pmset的了解和使用,能幫助我們對蘋果電腦的電源配置情況進行詳盡了解并提高自由控制度,後面我們也是主要依靠這個指令來展開工作。

最基本的,用下面指令來檢視目前的能源配置情況:

pmset -g
           

或者是

pmset -g custom
           

前者隻顯示目前電源的配置情況,後者可以分别對電池和外接電源的不同配置顯示。

利用上面的指令,看看sleep的配置值,如果是0,那麼就是禁止睡眠,非零就是系統空閑的多少分鐘後進入睡眠。

斷言接口:

斷言是系統底層IO對能源管理機制的對應用程式的一個接口,是在IOPMLib中定義的,官方文檔寫道:" access to common power management facilities, like initiating system sleep, getting current idle timer values, registering for sleep/wake notifications, and preventing system sleep."

為了能夠更詳細地排查到底是那個程式設定了斷言阻止系統睡眠,可以通過檢視目前系統斷言的情況:

/usr/bin/pmset -g assertions
           

現在通過一個執行個體來分析,下面是一個典型的場景的斷言情況:

Assertion status system-wide:
   PreventUserIdleDisplaySleep    1
   CPUBoundAssertion              0
   PreventSystemSleep             1
   PreventUserIdleSystemSleep     1
   InternalPreventDisplaySleep    1
   ExternalMedia                  0
   UserIsActive                   1
   ApplePushServiceTask           0
   BackgroundTask                 1

Listed by owning process:
  pid 2922(screensharingd): [0x00000005000002b1] 00:04:37 NoDisplaySleepAssertion named: "Nameless (via IOPMAssertionCreate)" 
  pid 44(mds): [0x0000000c00000133] 00:20:38 BackgroundTask named: "com.apple.metadata.mds" 
  pid 2924(ScreensharingAg): [0x00000005000002bf] 00:00:15 NoDisplaySleepAssertion named: "screen sharing wake display" 
  pid 2924(ScreensharingAg): [0x0000000a000002ba] 00:00:05 UserIsActive named: "screen sharing wake display" 
  pid 2520: [0x0000012c000009d8] PreventUserIdleSystemSleep named: "com.apple.audio.'AppleHDAEngineOutput:1B,0,1,2:0'.noidlesleep" 
           
pid 2423(caffeinate): [0x0000000800000292] 00:09:13 PreventSystemSleep named: "caffeinate command-line tool" 
	Details: caffeinate asserting forever
	Localized=THE CAFFEINATE TOOL IS PREVENTING SLEEP.
  pid 25(powerd): [0x0000000100000185] 00:15:58 PreventUserIdleSystemSleep named: "com.apple.powermanagement.ttyassertion" 
	Details: /dev/ttys000
	Localized=A remote user is connected. That prevents system sleep.
  pid 25(powerd): [0x0000000d000002ae] 00:04:41 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 19 secs Action=TimeoutActionRelease
  pid 25(powerd): [0x0000000d000002af] 00:04:38 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 22 secs Action=TimeoutActionRelease
  pid 25(powerd): [0x0000000d000002b0] 00:04:38 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 22 secs Action=TimeoutActionRelease
  pid 25(powerd): [0x0000000d000002b6] 00:03:52 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 67 secs Action=TimeoutActionRelease
  pid 25(powerd): [0x0000000d000002b7] 00:03:52 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 67 secs Action=TimeoutActionRelease
  pid 25(powerd): [0x0000000d000002bc] 00:01:32 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 208 secs Action=TimeoutActionRelease
  pid 25(powerd): [0x0000000d000002be] 00:00:18 InternalPreventDisplaySleep named: "com.apple.powermanagement.delayDisplayOff" 
	Timeout will fire in 282 secs Action=TimeoutActionRelease

Kernel Assertions: None
           

它主要包括兩個部分:

  • 第一個部分,“Assertion status system-wide”,根據斷言分類顯示狀态,每個狀态如果被一個使用者插入的斷言所激活,會顯示1;未激活的是0. 裡面每一類斷言都是會對系統産生影響的。常見的有PreventUserIdleSystemSleep和PreventUserIdleDisplaySleep。
  • 第二部分,給你列出到底是哪個程序,産生了那一類的斷言。

為了終止一個斷言,一釋放它對系統的影響,就要終止該斷言的程序:

sudo kill <pid>
           
系統設定:      

系統本來預設設定的一些系統行為,可能被改變:

比如關閉筆記本螢幕蓋會讓系統休眠,如果改變會影響這個行為,那麼用這個指令來恢複預設行為:

sudo pmset -a lidwake 1
           

改變電源特性也會喚醒,這個行為用下面指令改變:

sudo pmset acwake 0
           

如果是有活動的ttys程序,比如終端程式甚至遠端連接配接都有可能産生影響,用這個指令禁止:

sudo pmset -a ttyskeepawake 0
           

系統日志:

判斷曾經被喚醒的動作,可以檢查系統消息,運作指令:

/usr/bin/syslog | grep -i "Wake reason"
           

那麼可能的消息有:

  • EC.PowerButton PWRB (User): 使用者按了電源鍵 
  • EHC2: 鍵盤按鍵或者滑鼠移動
  • EHC1: USB連接配接了iDevices
  • ?: 接收到Wake-on-Lan資料包
  • EHC/OHC/USB: USB或者火線裝置
  • LID0: 筆記本螢幕打開
  • RTC: 實時時鐘消息,比如設定的定時能源設定

為了禁止接受Wake-on-Lan資料包,實用下面指令:

sudo pmset -a womp 0
           

藍牙裝置也可能阻止睡眠,看下面的截圖,檢查所有的藍牙裝置,禁止裝置喚醒電腦。

OSX: Mac不睡眠的排查

睡眠延遲:

還有一種情況,就是因為某個程式的運作,延遲了睡眠的動作,這個可以這樣着手:

pmset -g log | grep slowresponse
           

如果它找到程式,那麼就要運作類似下面的指令,并用文本編輯器軟體打開,查找slowresponse來檢視,到底是哪個程式延遲。比如下面的結果:

Domain: applicationresponse.timedout
- Message: Kernel cupsd com.apple.powermanagement.applicationresponse.timedout 30000 ms
- Time: 30/03/10 19:06:55 HAEC 
- Signature: cupsd
- UUID: EDA8296C-E84D-4B86-8AE9-5321B8676227
- Result: Noop
- Response time (ms): 30000
           

這個是列印機程式持續嘗試列印造成睡眠延遲的。

程式設計:

最後補充一下,對于需要程式設計改變睡眠特性的,參見Apple的官方IOPMLib中的Assersions相關說明,比如這裡。