Insomnia.kextはどのようにMacBookを不眠症にしているのか?
MacBookを不眠症にするInsomnia.kext。その実体は、カーネル機能拡張である。「カーネル」という響きが含まれると、非常に高度、かつ複雑、そして神秘的な感じがする。OSの深層部なんてどうせ自分には理解できない、という諦めもあって、今まで遠ざけていた。だから自分にとって、その中身は完全なブラックボックス。
ところが、Insomnia.kextはカーネルに組み込まれるが、カーネル本体ではなく、カーネル機能拡張なのである。そして、Insomnia.kextのソースコードも公開されている。ちょっと見た限り、コードは短く、そしてシンプル。これなら自分にも理解できるかもしれない、そんな思いから、Insomnia.kextの追跡が始まったのである。
ソースコードの在処
ソースコードは、複数箇所で様々なバージョンが見つかった。
- Insomnia.kext、InsomniaX.appのソースコード情報
- InsomniaX Source // semaja2
- http://insomniax.semaja2.net/InsomniaX.Source.zip(今回追跡したのは InsomniaX.Source/Insomnia に含まれるコード)
- 関連するソースコードページ(InsomniaX.Source2.zipは、古いバージョンのようだ)
- InsomniaX Source // semaja2
- Insomnia.kextのソースコードをブラウザで表示
- Insomnia.kextのソースコードをチェックアウト
svn checkout http://insomnia-kext.googlecode.com/svn/trunk/
svn checkout https://insomnia-kext.svn.sourceforge.net/svnroot/insomnia-kext/trunk/ #Revision 2(古いバージョンのようだ)
カーネル機能拡張の知識ページ
自分にはカーネル機能拡張の知識は全くない。よって、以下のページを精読することで、その仕組みを理解することから始める。
- Kernel Extension Programming Topicsの意訳 - LandEscape Graphics(日本語)素晴らしい翻訳に感謝です!
- キーボードリマッパーから見る Mac OS X のカーネル拡張の作り方素晴らしい解説に感謝です!
カーネル機能拡張の作り方
- 上記はカーネル機能拡張を解説する素晴らしいドキュメントなのだが、読んでいるだけでは間違いなく眠くなる。(保証する、自分がそうだった)
- ちゃんと理解するためには、どうするべきか?自分が思う最短の方法は、ちゃんと動くカーネル機能拡張を作ってみること。(これに勝る学習方法はないと思う)
...ということで、作ってみた。(ドキュメントを忠実に真似る)
新規プロジェクトの作成
Kernel Extension Programming Topics: Create a New Project(どうやらInsomnia.kextは、IOKitを利用したデバイスドライバのようだ)
- Xcodeを起動して、ファイル >> 新規プロジェクト...を開いた。
- System Plug-inのIOKit Driverを選択した。
- プロジェクト名は「MyDriver」
- プロジェクトウィンドウの「グループとファイル」の「MyDriver」を選択して、control-クリックして「情報を見る」
- ビルド タブを選択して、「アクティブアーキテクチャのみをビルド」のチェックを外す(完全に無しの状態)
Info.plist
Kernel Extension Programming Topics: Edit the Information Property List
- Info.plistをダブルクリックして、表示されたプロパティ リスト エディタの表をcontrol-クリックして、「Show Raw Keys/Values」を選択する。
- CFBundleIdentifier = com.MyCompany.driver.${PRODUCT_NAME:rfc1034identifier} に修正する。
- IOKitPersonalities を選択して、MyDriver を追加する。control-クリックして、Value Type >> Dictionary に変更する。
- MyDriver を選択して、CFBundleIdentifier = com.MyCompany.driver.MyDriver を追加する。
- MyDriver を選択して、IOClass = com_MyCompany_driver_MyDriver を追加する。
- MyDriver を選択して、IOKitDebug = 65535 を追加する。control-クリックして、Value Type >> Number に変更する。
- MyDriver を選択して、IOProviderClass = IOResources を追加する。
- MyDriver を選択して、IOMatchCategory = com_MyCompany_driver_MyDriver を追加する。
- 出来上りの状態は以下のようになる。
- Info.plistをcontrol-クリックして、形式を指定して開く >> ソースコードファイルにすると、以下のコードとなった。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${EXECUTABLE_NAME}</string> <key>CFBundleIconFile</key> <string></string> <key>CFBundleIdentifier</key> <string>com.MyCompany.driver.${PRODUCT_NAME:rfc1034identifier}</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>${PRODUCT_NAME}</string> <key>CFBundlePackageType</key> <string>KEXT</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>1</string> <key>IOKitPersonalities</key> <dict> <key>MyDriver</key> <dict> <key>CFBundleIdentifier</key> <string>com.MyCompany.driver.MyDriver</string> <key>IOClass</key> <string>com_MyCompany_driver_MyDriver</string> <key>IOKitDebug</key> <integer>65535</integer> <key>IOProviderClass</key> <string>IOResources</string> <key>IOMatchCategory</key> <string>com_MyCompany_driver_MyDriver</string> </dict> </dict> <key>OSBundleLibraries</key> <dict/> </dict> </plist>
MyDriver.h(ヘッダーファイル)
Kernel Extension Programming Topics: Fill in the Header File
#include <IOKit/IOService.h> class com_MyCompany_driver_MyDriver : public IOService { OSDeclareDefaultStructors(com_MyCompany_driver_MyDriver) public: virtual bool init(OSDictionary *dictionary = 0); virtual void free(void); virtual IOService *probe(IOService *provider, SInt32 *score); virtual bool start(IOService *provider); virtual void stop(IOService *provider); };
MyDriver.cpp(実装コード)
Kernel Extension Programming Topics: Implement the Driver’s Entry Points
#include <IOKit/IOLib.h> #include "MyDriver.h" // This required macro defines the class's constructors, destructors, // and several other methods I/O Kit requires. OSDefineMetaClassAndStructors(com_MyCompany_driver_MyDriver, IOService) // Define the driver's superclass. #define super IOService bool com_MyCompany_driver_MyDriver::init(OSDictionary *dict) { bool result = super::init(dict); IOLog("Initializing\n"); return result; } void com_MyCompany_driver_MyDriver::free(void) { IOLog("Freeing\n"); super::free(); } IOService *com_MyCompany_driver_MyDriver::probe(IOService *provider, SInt32 *score) { IOService *result = super::probe(provider, score); IOLog("Probing\n"); return result; } bool com_MyCompany_driver_MyDriver::start(IOService *provider) { bool result = super::start(provider); IOLog("Starting\n"); return result; } void com_MyCompany_driver_MyDriver::stop(IOService *provider) { IOLog("Stopping\n"); super::stop(provider); }
Info.plistにライブラリ宣言を追加する
Kernel Extension Programming Topics: Add Library Declarations
- Xcodeでビルドする。
- ターミナルで以下のコマンドを実行する。
$ cd MyDriver/build/Debug #MyDriverプロジェクトの /build/Debug へ移動する。 $ kextlibs -xml MyDriver.kext #MyDriver.kextに必要なライブラリ設定をxmlで出力する。 <key>OSBundleLibraries</key> <dict> <key>com.apple.kpi.iokit</key> <string>10.8</string> <key>com.apple.kpi.libkern</key> <string>10.8</string> </dict> $ echo $? #終了ステータス0で、kextlibsが正常終了したことを確認する。 0
- echo $? が 0 であることまで確認できたら、出力されたxml部分を Info.plist の OSBundleLibraries へコピーする。
<key>OSBundleLibraries</key> <dict/>
- 上記の部分が、以下のようなxmlになった。
<key>OSBundleLibraries</key> <dict> <key>com.apple.kpi.iokit</key> <string>10.8</string> <key>com.apple.kpi.libkern</key> <string>10.8</string> </dict>
- 保存して、再度Xcodeでビルドする。
MyDriver.kextをロードする準備
Kernel Extension Programming Topics: Prepare the Driver for Loading
- ビルドされたMyDriver.kextを /tmp へコピーする。(カーネルにロードするには、オーナー=root、グループ=wheel、の必要があるので)
- kextutil -n -t ...によって、MyDriver.kextが正常にカーネルにロードできるかチェックする。
- 以下のように表示されれば、この時点で正常にロード可能なカーネル機能拡張と予想される。
$ sudo cp -R MyDriver.kext /tmp $ sudo chown -R root:wheel /tmp/MyDriver.kext $ kextutil -n -t /tmp/MyDriver.kext No kernel file specified; using running kernel for linking. Notice: /tmp/MyDriver.kext has debug properties set. /tmp/MyDriver.kext appears to be loadable (including linkage for on-disk libraries).
- 何らかの問題が発生して再ビルドした場合は、一旦 /tmp/MyDriver.kext を削除してから、上記の「ロードする準備」を最初から繰り返す。
$ sudo rm -R /tmp/MyDriver.kext
実際にMyDriver.kextをカーネルにロードしてみる
- ロードしたカーネル機能拡張に何らかの不具合があると、間違いなくカーネルパニックが発生する。
- カーネルパニックが発生したら、一旦電源を落として、再起動するしか手はない。
- カーネル機能拡張はカーネルの一部分としてカーネルと同じ特権モードで実行されるので、通常のアプリケーションと違って個別に強制終了できないのである。
- アクティビティモニタで確認できるプロセスID=0のkernel_taskの中で実行されるのだ。
- つまり、以下の手順を試す前に、再起動しても問題ない状態にしておかなければならない。
- 編集中の書類は保存して、念のためTime Machineでバックアップしておいた。
- カーネルパニックの度に再起動していては、開発効率が著しく悪くなる。
- そのため、ドキュメントではマシンを2台使ったデバッグ方法が解説されている。
- あるいは、仮想マシン環境を作って開発すれば、より効率良く開発できるかもしれない。
- とは言ったものの、MyDriver.kextはアップルのドキュメントからそのままコピー&ペーストした雛形的なカーネル機能拡張である。
- 実装内容もIOLog()で処理状況を出力するのみ。おそらく、カーネルパニックは発生しないだろう。(たぶん)
...ということで早速、カーネルにロードしてみた。
$ sudo kextutil -v /tmp/MyDriver.kext #デバッグモードでカーネルにロードする Notice: /tmp/MyDriver.kext has debug properties set. /tmp/MyDriver.kext appears to be loadable (not including linkage for on-disk libraries). Loading /tmp/MyDriver.kext. /tmp/MyDriver.kext successfully loaded (or already loaded). $ kextstat | grep -v com.apple #ロードされた状況を確認 Index Refs Address Size Wired Name (Version)113 0 0x5c86f000 0xe000 0xd000 com.iospirit.driver.rbiokithelper (1.5.4) <62 35 29 5 4 3 1> 115 0 0x5bfc4000 0x3000 0x2000 com.eltima.ElmediaPlayer.kext (1.0) <4 1> 116 0 0x55347000 0x5000 0x4000 com.google.driver.Gild (1.0.0) <5 4 3 1> 117 0 0x5c49e000 0x18000 0x17000 org.pqrs.driver.KeyRemap4MacBook (7.3.0) <29 5 4 3 1> 127 0 0x5c1f2000 0x2000 0x1000 com.bresink.driver.BRESINKx86Monitoring (2.0) <12 11 10> 128 3 0x5c8d1000 0x25000 0x24000 org.virtualbox.kext.VBoxDrv (3.2.8) <7 5 4 3 1> 129 0 0x5c397000 0x7000 0x6000 org.virtualbox.kext.VBoxUSB (3.2.8) <128 41 35 7 5 4 3 1> 130 0 0x5c48c000 0x4000 0x3000 org.virtualbox.kext.VBoxNetFlt (3.2.8) <128 7 5 4 3 1> 131 0 0x5c1f8000 0x3000 0x2000 org.virtualbox.kext.VBoxNetAdp (3.2.8) <128 5 4 1> 204 0 0x5b44f000 0x3000 0x2000 com.protech.nosleep (1.2.1) <4 3> 373 0 0x557e0000 0x2000 0x1000 com.MyCompany.driver.MyDriver (1) <4 3> $ sudo kextunload -v /tmp/MyDriver.kext #アンロードして終了 com.MyCompany.driver.MyDriver unloaded and personalities removed.
- 通常、kextloadでロードするが、kextutilならデバッグモードでロードできるようだ。
- vオプションは、処理状況を詳細に出力してくれる。
- kextstatで、ロードされたのが確認できた。
- kextunloadで、アンロードして終了。
メソッド呼び出しのタイミング
- “ドライバオブジェクトのライフサイクル”によると、
- あるいは、Kernel Extension Programming Topics: Implement the Driver’s Entry Pointsによると、
- あるいは、Kernel Extension Programming Topicsの意訳5 » LandEscape Graphicsによると、
MyDriver.kextが実装しているメソッドは、以下のタイミングで呼び出されるようだ。
- kextloadで、init、prove、startが呼び出される。
- initは、com_MyCompany_driver_MyDriverクラスのインスタンスが生成される時に一度だけ呼び出される。
- proveは、適合するドライバかどうか確認するために呼び出される。
- その後startで、ドライバのサービスを開始する。ドライバの機能はここでセットアップするべき。
- kextunloadで、stop、freeが呼び出される。
- stopは、startで開始されたサービスを中止して、元の状態に戻す。(start・stopは対になるペア)
- freeは、initやインスタンス化で割り当てられてリソースを廃棄する。(init・freeは対になるペア)
IOLog()
- IOLog()は、引数の値をkernel.logに出力してくれる関数だ。
- Insomnia.kextをロード・アンロード時のkernel.logには、init・start等に実装されているであろうIOLog()の出力が克明に記録されている。
- よって、MyDriver.kextのロード・アンロード時にも、同じようにKernel.logにIOLog()の出力が記録されるはず。
- そう思って確認したが、Kernel.logにはMyDriver.kextのIOLog()らしき出力は全く見当たらない...。
- kextstatコマンドで確認すると、ちゃんとMyDriver.kextがロードされていることは確認できる。
なぜ?
- init以下が何も実行されていないということは、ロードはされたが、インスタンス化されていない、ということだろうか?
- MyDriver.hとMyDriver.cppについては、何度見ても問題ないように見える。
- 残る原因は、Info.plistの設定内容かもしれない。
- Insomnia.kextのInfo.plistとの違いを見ながら、修正・追加してみた。
- IOProviderClass = IOService
- IONameMatch = IOPMrootDomain
- ターミナルで以下の操作をして、試してみた。
# 古い/tmp/MyDriver.kextを削除して、再ビルドしたMyDriver.kextをコピー、オーナー=root グループ=wheel に設定 $ sudo rm -R /tmp/MyDriver.kext; sudo cp -R MyDriver.kext /tmp; sudo chown -R root:wheel /tmp/MyDriver.kext Password: $ kextlibs -xml MyDriver.kext #必要なライブラリ設定をチェック(変更なしだった)OSBundleLibraries $ kextutil -n -t /tmp/MyDriver.kext #ロード前のチェック No kernel file specified; using running kernel for linking. Notice: /tmp/MyDriver.kext has debug properties set. /tmp/MyDriver.kext appears to be loadable (including linkage for on-disk libraries). $ sudo kextutil -v /tmp/MyDriver.kext #ロード Notice: /tmp/MyDriver.kext has debug properties set. /tmp/MyDriver.kext appears to be loadable (not including linkage for on-disk libraries). Loading /tmp/MyDriver.kext. /tmp/MyDriver.kext successfully loaded (or already loaded). $ sudo kextunload -v /tmp/MyDriver.kext #アンロード com.MyCompany.driver.MyDriver unloaded and personalities removed. com.apple.kpi.iokit 10.8 com.apple.kpi.libkern 10.8
- コンソールでkernel.logを確認してみると...
...(中略)... Jul 22 02:24:18 zari-MacBook kernel[0]: Initializing Jul 22 02:24:18 zari-MacBook kernel[0]: Probing Jul 22 02:24:18 zari-MacBook kernel[0]: Starting Jul 22 02:25:40 zari-MacBook kernel[0]: Stopping Jul 22 02:25:40 zari-MacBook kernel[0]: Freeing
できた!MyDriver.kextがちゃんと反応している!
- どうやら、IOProviderClassがIOResourcesだとNGだったようだ。
- IOResourcesは、具体的なデバイスではなく、各デバイスのスーパークラス的な扱いになるらしい。
- ドキュメントのサンプルコードなので、仮想的なデバイスの意味でIOResourcesを指定したようだ。
- まだまだ詳細は理解しきれていない...。
ここまで、カーネル機能拡張の雛形となるMyDriver.kextが完成した!
不眠を発症するカーネル機能拡張に改造する
- ところで当初の目的は、insomniaがどのようにMacBookを不眠症にしているのか、解き明かすことだった。
- そこでInsomniaのソースコードでスリープを制御すると思われる部分を見ながら、MyDriverを改造してみる。
MyDriver.h
#include <IOKit/IOService.h> #include <IOKit/IOWorkLoop.h> #include <IOKit/IOTimerEventSource.h> class com_MyCompany_driver_MyDriver : public IOService { OSDeclareDefaultStructors(com_MyCompany_driver_MyDriver) public: virtual bool init(OSDictionary *dictionary = 0); virtual void free(void); virtual IOService *probe(IOService *provider, SInt32 *score); virtual bool start(IOService *provider); virtual void stop(IOService *provider); //virtual IOReturn message(UInt32 type, IOService *provider, void *argument = 0); private: static bool send_event(UInt32 msg); //bool lastLidState; };
MyDriver.cpp
可能な限りコードを削っていくと...
- IOLog()で状態を出力して、親クラス(IOService)を呼び出すだけの実装は不要なのだと思う。
- だから、init・free・probeメソッドの定義、はコメントアウトした。
- また、messageメソッドの定義もディスプレイの開閉を検出する目的である。
- MyDriverに実装されていないメソッドは、勝手にその親クラス(IOService)が反応してくれるのだ。
- init・free・probe・messageメソッドは、すべて親クラス(IOService)で定義されている。
- そのようにして淘汰され、残ったコードは以下のようになった。(コメントアウトも含んでいる)
#include <IOKit/IOLib.h> #include "MyDriver.h" #include <IOKit/pwr_mgt/RootDomain.h> // This required macro defines the class's constructors, destructors, // and several other methods I/O Kit requires. OSDefineMetaClassAndStructors(com_MyCompany_driver_MyDriver, IOService) // Define the driver's superclass. #define super IOService /* bool com_MyCompany_driver_MyDriver::init(OSDictionary *dict) { IOLog("MyDriver: Initializing\n"); return super::init(dict); } void com_MyCompany_driver_MyDriver::free(void) { IOLog("MyDriver: Freeing\n"); super::free(); } IOService *com_MyCompany_driver_MyDriver::probe(IOService *provider, SInt32 *score) { IOLog("MyDriver: Probing\n"); return super::probe(provider, score); } */ bool com_MyCompany_driver_MyDriver::start(IOService *provider) { IOLog("MyDriver: Starting\n"); com_MyCompany_driver_MyDriver::send_event(kIOPMDisableClamshell | kIOPMPreventSleep); return super::start(provider); } void com_MyCompany_driver_MyDriver::stop(IOService *provider) { IOLog("MyDriver: Stopping\n"); com_MyCompany_driver_MyDriver::send_event(kIOPMEnableClamshell | kIOPMAllowSleep); super::stop(provider); } bool com_MyCompany_driver_MyDriver::send_event(UInt32 msg) { IOPMrootDomain *root = NULL; IOReturn ret=kIOReturnSuccess; IOLog("MyDriver: Sending event\n"); root = getPMRootDomain(); if (!root) { IOLog("MyDriver: Fatal error could not get RootDomain.\n"); return false; } ret = root->receivePowerNotification(msg); IOLog("MyDriver: root returns %d\n", ret); if(ret!=kIOReturnSuccess) IOLog("MyDriver: Error sending event\n"); else IOLog("MyDriver: Message sent to root\n"); return true; } /* kIOPMMessageClamshallStateChange Notification */ /* IOReturn com_MyCompany_driver_MyDriver::message(UInt32 type, IOService * provider, void * argument) { if (type == kIOPMMessageClamshellStateChange) { IOLog("========================\n"); IOLog("MyDriver: Clamshell State Changed\n"); // If lid was opened if ((argument && kClamshellStateBit) & (!lastLidState)) { IOLog("MyDriver: kClamshellStateBit set - lid was opened\n"); lastLidState = true; com_MyCompany_driver_MyDriver::send_event(kIOPMClamshellOpened); // If lastLidState is true - lid closed } else if (lastLidState) { IOLog("MyDriver: kClamshellStateBit not set - lid was closed \n"); lastLidState = false; // - send kIOPMDisableClamshell | kIOPMPreventSleep here? com_MyCompany_driver_MyDriver::send_event(kIOPMDisableClamshell | kIOPMPreventSleep); } } return super::message(type, provider, argument); } */
動作確認
- 以上の変更を保存してから、再ビルドした。
- 早速、カーネルにロードして試してみた。
$ sudo rm -R /tmp/MyDriver.kext; sudo cp -R MyDriver.kext /tmp; sudo chown -R root:wheel /tmp/MyDriver.kext Password: $ kextutil -n -t /tmp/MyDriver.kext No kernel file specified; using running kernel for linking. Notice: /tmp/MyDriver.kext has debug properties set. /tmp/MyDriver.kext appears to be loadable (including linkage for on-disk libraries). $ sudo kextutil -v /tmp/MyDriver.kext Notice: /tmp/MyDriver.kext has debug properties set. /tmp/MyDriver.kext appears to be loadable (not including linkage for on-disk libraries). Loading /tmp/MyDriver.kext. /tmp/MyDriver.kext successfully loaded (or already loaded). $ pmset sleepnow Unable to sleep system: error 0xe00002bc $ sudo kextunload -v /tmp/MyDriver.kext com.MyCompany.driver.MyDriver unloaded and personalities removed.
- コンソールのkernel.logの様子。
...(中略)... Jul 22 08:46:59 bebe-MacBook kernel[0]: MyDriver: Starting Jul 22 08:46:59 bebe-MacBook kernel[0]: MyDriver: Sending event Jul 22 08:46:59 bebe-MacBook kernel[0]: MyDriver: root returns 0 Jul 22 08:46:59 bebe-MacBook kernel[0]: MyDriver: Message sent to root Jul 22 08:47:13 bebe-MacBook kernel[0]: Sleep prevented by SB 0, SS 0, AS 0 Jul 22 08:47:43 bebe-MacBook kernel[0]: MyDriver: Stopping Jul 22 08:47:43 bebe-MacBook kernel[0]: MyDriver: Sending event Jul 22 08:47:43 bebe-MacBook kernel[0]: MyDriver: root returns 0 Jul 22 08:47:43 bebe-MacBook kernel[0]: MyDriver: Message sent to root
- コマンド・メニュー・キー操作による、あらゆるスリープは完全に無効になった。もちらん、ディスプレイを閉じてもスリープしない。
スリープが無効になる仕組み
- startメソッドで、スリープを無効にするメッセージをsend_eventしている。
- send_eventの中身は、PMRootDomainオブジェクト宛に、receivePowerNotificationを呼び出している。
root = getPMRootDomain(); ...(中略)... ret = root->receivePowerNotification(msg);
- msgには、以下の値が設定されて呼び出される。
- kIOPMDisableClamshell | kIOPMPreventSleep(スリープを無効にする場合)
- kIOPMEnableClamshell | kIOPMAllowSleep(スリープを元どおり有効にする場合)
- ちなみに、些細なことだけど root->receivePowerNotification(msg); の->演算子が気になったので調べてみた。
- 第十三回-03 ドット演算子とアロー演算子
- つまり、他の言語でよく見かける root.receivePowerNotification(msg); と同等なのだけど、C・C++においてはポインタに対するメソッド呼び出しは->を使うのが流儀なのだ。
最新のInsomnia.kextについて
- usage.rtfには、その使い方が書いてあった。
Insomnia.kext with control by sysctl Michael Rossberg, Alexey Manannikov Andrew James, Dominik Wickenhauser Kext usage: Enable loaded Insomnia.kext: /usr/sbin/sysctl -w kern.lidsleep=1 Disable loaded Insomnia.kext: /usr/sbin/sysctl -w kern.lidsleep=0 Get Insomnia.kext state: /usr/sbin/sysctl kern.lidsleep Returned value 0 - not active, 1 - active, -1 - not loaded Enable debug output to console: /usr/sbin/sysctl -w kern.lidsleep=3 Disable debug output to console: /usr/sbin/sysctl -w kern.lidsleep=2
なんと!
- 今までロードしたら、完全にスリープが無効になるだけだったのだが、
- sysctlコマンドで、スリープの有効・無効、kernel.log出力の有効・無効がコントロールできるようになるようだ。
- 最新のInsomniaX.appを起動して、sysctl kern.lidsleepを試してみた。
$ sysctl kern.lidsleep
kern.lidsleep: 1 1
- おおっ!すでにkern.lidsleepが設定されていた!
$ sudo sysctl -w kern.lidsleep=0
Password:
kern.lidsleep: 1 1 -> 0 0
- 0を設定したら、Insomnia.kextがロードされた状態でもスリープ可能になった。
- しかし、現状サポートされているのは、sudo sysctl -w kern.lidsleep=0 or 1 のみ。
- sudo sysctl -w kern.lidsleep=2 or 3 についてはエラーが出て、値が設定できない。
$ sudo /usr/sbin/sysctl -w kern.lidsleep=0 kern.lidsleep: 1 1 -> 0 0 $ sudo /usr/sbin/sysctl -w kern.lidsleep=1 kern.lidsleep: 0 0 -> 1 1 $ sudo /usr/sbin/sysctl -w kern.lidsleep=2 kern.lidsleep: 1 1 sysctl: kern.lidsleep: Operation not permitted $ sudo /usr/sbin/sysctl -w kern.lidsleep=3 sysctl: kern.lidsleep: Operation not permitted
今後のバージョンに期待!
カーネル システム パラメタの設定方法
以上で、Insomnia.kextの仕組みが理解できた!