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.