2

OS X Lion still goes to sleep, even if programmatic mouse "wiggles" are being periodically issued from a Java Robot (this is a standard approach to keeping machines from going to sleep and is documented elsewhere in stackoverflow, and it worked for me prior to OS X Lion).

Can anyone suggest an alternative approach, which does not require permission escalation, of keeping the machine awake from a Java application?

((The fallback solution is obviously to change the Energy Saving preferences so that the machine never sleeps, but we'd like to be smarter than that because requiring the machine to stay awake is the exception rather than the rule)).

Kara
  • 6,115
  • 16
  • 50
  • 57
fommil
  • 5,757
  • 8
  • 41
  • 81

3 Answers3

3

It turns out that it is no longer possible to do this with pure-Java hacks, and one must resort to implementing a JNI I/O listener, the code of which would contain something like

http://developer.apple.com/library/mac/#qa/qa1340/_index.html

An alternative, if you can tolerate calling a command line tool, is to call pmset noidle in a daemon thread.

fommil
  • 5,757
  • 8
  • 41
  • 81
2

Do you need to prevent display sleep or system sleep? If the latter, you can prevent system sleep with disk activity - e.g. read from or write to a file.

Hard disk activity does not prevent display sleep, but it does prevent system sleep. It is not uncommon for the display to sleep before the system goes to sleep if both types of sleep are set to occur after the same length of inactivity. http://support.apple.com/kb/ht1776

This answer points to Objective-C code that can be used to prevent sleep, using the UpdateSystemActivity call. Could you create a simple JNI wrapper on this which you could invoke as a native method from your Java code?

It also seems possible to disable and re-enable sleep using applescript. Could you invoke such a script using Runtime.exec() from your Java code?

Community
  • 1
  • 1
ewan.chalmers
  • 16,145
  • 43
  • 60
  • Display sleep is irrelevant for me, I'm only interested in stopping the machine from going to system sleep. From experience, I can tell you that reading and writing to a file *definitely* does not keep an iMac from going to sleep! – fommil Nov 15 '11 at 17:29
0

Following JNI solution works for macOS 10.5 / GCC

I. Definition Java Native Interface

// File KalleInterface.java
public class KalleInterface
{
    static
    {
        // java.library.path set to libKalleInterface.dylib
        System.loadLibrary("KalleInterface");
    }   

    public static native boolean preventSleep();
    public static native boolean allowSleep();
}

II. Generate Equivalent C++ Interface

Assume compliled java class file is ./bin/KalleInterface.class

javah -jni -d "${PWD}" -classpath "${PWD}/bin" KalleInterface

generates a C++ header KalleInterface.h as

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class KalleInterface */

#ifndef _Included_KalleInterface
#define _Included_KalleInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     KalleInterface
* Method:    preventSleep
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_KalleInterface_preventSleep(JNIEnv *, jclass);

/*
* Class:     KalleInterface
* Method:    allowSleep
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_KalleInterface_allowSleep(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

III. Implement C++ Interface

#include "esc_util_KalleInterface.h"

#include <IOKit/pwr_mgt/IOPMLib.h>

// IOPMAssertionCreateWithName ...
// kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
// kIOPMAssertionTypeNoIdleSleep prevents idle sleep

//reasonForActivity is a descriptive string used by the system whenever it needs
// to tell the user why the system is not sleeping. For example,
// "Mail Compacting Mailboxes" would be a useful string.

// IOPMAssertionDeclareUserActivity ...
// claims user activity


#ifdef __cplusplus
extern "C" {
#endif

CFStringRef reasonForActivity= CFSTR("User Activity Type");
// NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.


IOPMAssertionID assertionID;


static bool active = false;

/*
 * Class:     KalleInterface
 * Method:    preventSleep
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_esc_util_KalleInterface_preventSleep(JNIEnv*, jclass)
{
    IOReturn success = 0;
    
    if (active)
    {
        return (jboolean)true;
    }
    //success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
    //success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,   kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
    success = IOPMAssertionDeclareUserActivity(reasonForActivity, kIOPMUserActiveLocal, &assertionID);
    active =(success == kIOReturnSuccess);
    return (jboolean)active;

//Add the work you need to do without 
//  the system sleeping here.
    
}

/*
 * Class:     KalleInterface
 * Method:    allowSleep
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_esc_util_KalleInterface_allowSleep(JNIEnv *, jclass)
{
    IOReturn success = 0;
    
    if (!active)
    {
        return (jboolean)true;
    }

    success = IOPMAssertionRelease(assertionID);
    active = !(success == kIOReturnSuccess);
    //The system will be able to sleep again. 
    return (jboolean)(!active);
}


#ifdef __cplusplus
}
#endif

IV. Build Shared Library

Command line steps for building libKalleInterface.dylib are

g++ -c -fPIC -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/darwin -o KalleInterfaceCPP.o  KalleInterfaceCPP.cpp

g++  -dynamiclib -framework CoreFoundation -framework IOKit -o libKalleInterface.dylib KalleInterfaceCPP.o -lc

V. Test Class

// File KalleTest.java

public class KalleTest
{
    public static void main(String...args)
    {
        boolean ok1 = KalleInterface.preventSleep();
        System.out.println(ok1);
        try
        {
            Thread.sleep(60*10*1000);
        }
        catch (Exception x)
        {
            x.printStackTrace();
        }
        boolean ok2 = KalleInterface.allowSleep();
        System.out.println(ok2);
    }
}

Assuming compiled class is ./bin/KalleTest.class and shared library is ./libKalleInterface.dylib, test is invoked by

java -Djava.library.path=${PWD} -classpath ./bin KalleTest

Expected behaviour: Mac remains active for 10 minutes, each of preventSleep(), allowSleep() produce result/output true.

Sam Ginrich
  • 661
  • 6
  • 7
  • The question explicitly says that mouse movements from Robot are ignored. That was OP's previous solution which stopped working and they started looking for an alternative. – Roddy of the Frozen Peas Sep 20 '20 at 14:25