1

I want to use Macbook air in clamshell mode without AC adapter connected. However, Mac OS will force system going to sleep when I close lid.

I found this part of XNU kernel from apple open source may relate to this behavior:

iokit/Kernel/IOPMrootDomain.cpp

...

6362     /*
6363      * Evaluate clamshell and SLEEP if appropiate
6364      */
6365     if (eval_clamshell && clamshellClosed)
6366     {
6367         if (shouldSleepOnClamshellClosed())
6368             privateSleepSystem (kIOPMSleepReasonClamshell);
6369         else
6370             evaluatePolicy( kStimulusDarkWakeEvaluate );
6371     }

...

3061 //******************************************************************************
3062 // sleepOnClamshellClosed
3063 //
3064 // contains the logic to determine if the system should sleep when the clamshell
3065 // is closed.
3066 //******************************************************************************
3067 
3068 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3069 {
3070     if (!clamshellExists)
3071         return false;
3072 
3073     DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3074         clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
3075 
3076     return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
3077 }

Of course, I can compile kernel but I doubt if it is latest Mavericks kernel. So I want to know if I can override kernel space function as we do it for user space function by inserting dynamic library.

Ricky Zhang
  • 140
  • 1
  • 9

1 Answers1

0

Recompiling the xnu kernel is easier than you seem to think:

http://shantonu.blogspot.ca/2013/10/building-xnu-for-os-x-109-mavericks.html

Apple have been pretty slow to release source code for maintenance releases of OSX however, so you would have to delay updates 10.9.x until source becomes available.

Aside from that, you have a 2 obvious options:

  • Patch the mach_kernel executable directly on disk.
  • Patch the IOPMrootDomain::shouldSleepOnClamshellClosed function at runtime using a purpose-built kext.

In both cases, locate the IOPMrootDomain::shouldSleepOnClamshellClosed function in the mach_kernel disassembly. Figure out where it reads acAdaptorConnected and replace those instructions with ones that make the code behave as if acAdaptorConnected were always true.

You'll need to take care when patching at runtime. The method is private, so you can't directly get its address using the kext linker, so you'd need to get the address from elsewhere.

FWIW, I'm not 100% convinced this code is to blame for the behaviour you're seeing. clamshellDisabled should normally be true if an external display is attached. If you're specifically trying to use your Macbook with no screen attached, you can try generating a fake kIOPMDisableClamshell power event, which should flip that flag.

As an aside, it's somewhat disappointing that Apple has hardcoded such behaviour in the kernel - seems like the thing a simple userspace script should be deciding. :-(

pmdj
  • 22,018
  • 3
  • 52
  • 103
  • Reading through that, you are correct that clamshellDisabled is true if external display appears. I will try to enable debug flag this weekend and see if I can find anything. I guess that kernel may be signed. Option 1 may not work. I'm not sure how exactly to implement option2. So I may end up compiling kernel. In any case, thanks for your guidance. I'm quite surprised at the quick response. I believe this feature is quite popular among Apple laptop customer. – Ricky Zhang Dec 13 '13 at 20:16
  • The `mach_kernel` isn't signed at all: `codesign -v /mach_kernel` says `/mach_kernel: code object is not signed at all`. So modifying/replacing it is no problem. – pmdj Dec 15 '13 at 20:51