Insomnia.kextはどのようにMacBookを不眠症にしているのか?

MacBook不眠症にするInsomnia.kext。その実体は、カーネル機能拡張である。「カーネル」という響きが含まれると、非常に高度、かつ複雑、そして神秘的な感じがする。OSの深層部なんてどうせ自分には理解できない、という諦めもあって、今まで遠ざけていた。だから自分にとって、その中身は完全なブラックボックス

ところが、Insomnia.kextはカーネルに組み込まれるが、カーネル本体ではなく、カーネル機能拡張なのである。そして、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: 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をカーネルにロードしてみる
  • ロードしたカーネル機能拡張に何らかの不具合があると、間違いなくカーネルパニックが発生する。
  • カーネルパニックが発生したら、一旦電源を落として、再起動するしか手はない。
  • カーネル機能拡張はカーネルの一部分としてカーネルと同じ特権モードで実行されるので、通常のアプリケーションと違って個別に強制終了できないのである。
  • つまり、以下の手順を試す前に、再起動しても問題ない状態にしておかなければならない。
    • 編集中の書類は保存して、念のためTime Machineでバックアップしておいた。
  • とは言ったものの、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で、アンロードして終了。

メソッド呼び出しのタイミング

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
	
		com.apple.kpi.iokit
		10.8
		com.apple.kpi.libkern
		10.8
	

$ 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.
  • コンソールで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)を呼び出すだけの実装は不要なのだと思う。
  • また、messageメソッドの定義もディスプレイの開閉を検出する目的である。
    • messageメソッドは、デバイスが状態変化した時に発する通知を取得して、処理する役割。
    • Insomniaの実装では、ディスプレイの開閉状態の変化に反応して、NSLog()でその状態を出力している。
    • スリープの制御に直接関係ないので、コメントアウトしてある。
  • 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); の->演算子が気になったので調べてみた。
カーネルソースコードまで辿る
  • では、kIOPMDisableClamshellなどの実体は何か?


などなど、OSXカーネル部分はオープンソースなので、どこまでも辿ることが可能なのだ!

最新の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の仕組みが理解できた!