I have a piece of server-ish software written in Java to run on Windows and OS X. (It is not running on a server, but just a normal user's PC - something like a torrent client.) I would like the software to signal to the OS to keep the machine awake (prevent it from going into sleep mode) while it is active.
Of course I don't expect there to be a cross platform solution, but I would love to have some very minimal C programs/scripts that my app can spawn to inform the OS to stay awake.
Any ideas?
I use this code to keep my workstation from locking. It's currently only set to move the mouse once every minute, you could easily adjust it though.
It's a hack, not an elegant solution.
import java.awt.*;
import java.util.*;
public class Hal{
public static void main(String[] args) throws Exception{
Robot hal = new Robot();
Random random = new Random();
while(true){
hal.delay(1000 * 60);
int x = random.nextInt() % 640;
int y = random.nextInt() % 480;
hal.mouseMove(x,y);
}
}
}
On Windows, use the SystemParametersInfo function. It's a Swiss army-style function that lets you get/set all sorts of system settings.
To disable the screen shutting off, for instance:
SystemParametersInfo( SPI_SETPOWEROFFACTIVE, 0, NULL, 0 );
Just be sure to set it back when you're done...
A much cleaner solution is use JNA to tap into the native OS API. Check your platform at runtime, and if it happens to be Windows then the following will work:
import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.Structure.FieldOrder;
import com.sun.jna.platform.win32.WTypes.LPWSTR;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.ULONG;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.win32.StdCallLibrary;
/**
* Power management.
*
* #see https://stackoverflow.com/a/20996135/14731
*/
public enum PowerManagement
{
INSTANCE;
#FieldOrder({"version", "flags", "simpleReasonString"})
public static class REASON_CONTEXT extends Structure
{
public static class ByReference extends REASON_CONTEXT implements Structure.ByReference
{
}
public ULONG version;
public DWORD flags;
public LPWSTR simpleReasonString;
}
private interface Kernel32 extends StdCallLibrary
{
HANDLE PowerCreateRequest(REASON_CONTEXT.ByReference context);
/**
* #param powerRequestHandle the handle returned by {#link #PowerCreateRequest(REASON_CONTEXT.ByReference)}
* #param requestType requestType is the ordinal value of {#link PowerRequestType}
* #return true on success
*/
boolean PowerSetRequest(HANDLE powerRequestHandle, int requestType);
/**
* #param powerRequestHandle the handle returned by {#link #PowerCreateRequest(REASON_CONTEXT.ByReference)}
* #param requestType requestType is the ordinal value of {#link PowerRequestType}
* #return true on success
*/
boolean PowerClearRequest(HANDLE powerRequestHandle, int requestType);
enum PowerRequestType
{
PowerRequestDisplayRequired,
PowerRequestSystemRequired,
PowerRequestAwayModeRequired,
PowerRequestMaximum
}
}
private final Kernel32 kernel32;
private HANDLE handle = null;
PowerManagement()
{
// Found in winnt.h
ULONG POWER_REQUEST_CONTEXT_VERSION = new ULONG(0);
DWORD POWER_REQUEST_CONTEXT_SIMPLE_STRING = new DWORD(0x1);
kernel32 = Native.load("kernel32", Kernel32.class);
REASON_CONTEXT.ByReference context = new REASON_CONTEXT.ByReference();
context.version = POWER_REQUEST_CONTEXT_VERSION;
context.flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
context.simpleReasonString = new LPWSTR("Your reason for changing the power setting");
handle = kernel32.PowerCreateRequest(context);
if (handle == WinBase.INVALID_HANDLE_VALUE)
throw new AssertionError(Native.getLastError());
}
/**
* Prevent the computer from going to sleep while the application is running.
*/
public void preventSleep()
{
if (!kernel32.PowerSetRequest(handle, Kernel32.PowerRequestType.PowerRequestSystemRequired.ordinal()))
throw new AssertionError("PowerSetRequest() failed");
}
/**
* Allow the computer to go to sleep.
*/
public void allowSleep()
{
if (!kernel32.PowerClearRequest(handle, Kernel32.PowerRequestType.PowerRequestSystemRequired.ordinal()))
throw new AssertionError("PowerClearRequest() failed");
}
}
Then when the user runs powercfg /requests they see:
SYSTEM:
[PROCESS] \Device\HarddiskVolume1\Users\Gili\.jdks\openjdk-15.0.2\bin\java.exe
Your reason for changing the power setting
You should be able to do something similar for macOS and Linux.
Adding to scarcher2's code snippet above and moving mouse by only 1 pixel. I have moved the mouse twice so that some change occurs even if pointer is on extremes:
while(true){
hal.delay(1000 * 30);
Point pObj = MouseInfo.getPointerInfo().getLocation();
System.out.println(pObj.toString() + "x>>" + pObj.x + " y>>" + pObj.y);
hal.mouseMove(pObj.x + 1, pObj.y + 1);
hal.mouseMove(pObj.x - 1, pObj.y - 1);
pObj = MouseInfo.getPointerInfo().getLocation();
System.out.println(pObj.toString() + "x>>" + pObj.x + " y>>" + pObj.y);
}
I have a very brute-force technique of moving the mouse 1 point in the x direction and then back every 3 minutes.
There may me a more elegant solution but it's a quick fix.
Wouldn't all the suggestions moving the mouse back and forth drive the user crazy? I know I'd remove any app that would do that as soon as I can isolate it.
Here is completed Batch file that generates java code, compile it, cleans the generated files, and runs in the background.. (jdk is required on your laptop)
Just save and run this as a Bat File. (somefilename.bat) ;)
#echo off
setlocal
rem rem if JAVA is set and run from :startapp labeled section below, else the program exit through :end labeled section.
if not "[%JAVA_HOME%]"=="[]" goto start_app
echo. JAVA_HOME not set. Application will not run!
goto end
:start_app
echo. Using java in %JAVA_HOME%
rem writes below code to Energy.java file.
#echo import java.awt.MouseInfo; > Energy.java
#echo import java.awt.Point; >> Energy.java
#echo import java.awt.Robot; >> Energy.java
#echo //Mouse Movement Simulation >> Energy.java
#echo public class Energy { >> Energy.java
#echo public static void main(String[] args) throws Exception { >> Energy.java
#echo Robot energy = new Robot(); >> Energy.java
#echo while (true) { >> Energy.java
#echo energy.delay(1000 * 60); >> Energy.java
#echo Point pObj = MouseInfo.getPointerInfo().getLocation(); >> Energy.java
#echo Point pObj2 = pObj; >> Energy.java
#echo System.out.println(pObj.toString() + "x>>" + pObj.x + " y>>" + pObj.y); >> Energy.java
#echo energy.mouseMove(pObj.x + 10, pObj.y + 10); >> Energy.java
#echo energy.mouseMove(pObj.x - 10, pObj.y - 10); >> Energy.java
#echo energy.mouseMove(pObj2.x, pObj.y); >> Energy.java
#echo pObj = MouseInfo.getPointerInfo().getLocation(); >> Energy.java
#echo System.out.println(pObj.toString() + "x>>" + pObj.x + " y>>" + pObj.y); >> Energy.java
#echo } >> Energy.java
#echo } >> Energy.java
#echo } >> Energy.java
rem compile java code.
javac Energy.java
rem run java application in background.
start javaw Energy
echo. Your Secret Energy program is running...
goto end
:end
rem clean if files are created.
pause
del "Energy.class"
del "Energy.java"
I've been using pmset to control sleep mode on my Mac for awhile now, and it's pretty easy to integrate. Here's a rough example of how you could call that program from Java to disable/enable sleep mode. Note that you need root privileges to run pmset, and therefore you'll need them to run this program.
import java.io.BufferedInputStream;
import java.io.IOException;
/**
* Disable sleep mode (record current setting beforehand), and re-enable sleep
* mode. Works with Mac OS X using the "pmset" command.
*/
public class SleepSwitch {
private int sleepTime = -1;
public void disableSleep() throws IOException {
if (sleepTime != -1) {
// sleep time is already recorded, assume sleep is disabled
return;
}
// query pmset for the current setting
Process proc = Runtime.getRuntime().exec("pmset -g");
BufferedInputStream is = new BufferedInputStream(proc.getInputStream());
StringBuffer output = new StringBuffer();
int c;
while ((c = is.read()) != -1) {
output.append((char) c);
}
is.close();
// parse the current setting and store the sleep time
String outString = output.toString();
String setting = outString.substring(outString.indexOf(" sleep\t")).trim();
setting = setting.substring(7, setting.indexOf(" ")).trim();
sleepTime = Integer.parseInt(setting);
// set the sleep time to zero (disable sleep)
Runtime.getRuntime().exec("pmset sleep 0");
}
public void enableSleep() throws IOException {
if (sleepTime == -1) {
// sleep time is not recorded, assume sleep is enabled
return;
}
// set the sleep time to the previously stored value
Runtime.getRuntime().exec("pmset sleep " + sleepTime);
// reset the stored sleep time
sleepTime = -1;
}
}
You can use the program Caffeine caffiene to keep your workstation awake. You could run the program via the open command in os X.
On OS X, just spawn caffeinate. This will prevent the system from sleeping until caffeinate is terminated.
In Visual Studio create a simple form.
From the toolbar, drag a Timer control onto the form.
In the Init code, set the timer interval to 60 seconds (60000 ms.).
Implement the timer callback with the following code "SendKeys.Send("{F15}");"
Run the new program.
No mouse movement needed.
Edit: At least on my Army workstation, simply programmatically generating mouse and key messages isn't enough to keep my workstation logged in and awake. The early posters with the Java Robot class are on the right track. JAVA Robot works on or below the OS's HAL (Hardware Abstraction Layer) However I recreated and tested the Java/Robot solution and it did not work - until I added a Robot.keyPress(123) to the code.
To go with the solution provided by user Gili for Windows using JNA, here's the JNA solution for MacOS.
First, the JNA library interface:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.mac.CoreFoundation;
import com.sun.jna.ptr.IntByReference;
public interface ExampleIOKit extends Library {
ExampleIOKit INSTANCE = Native.load("IOKit", ExampleIOKit.class);
CoreFoundation.CFStringRef kIOPMAssertPreventUserIdleSystemSleep = CoreFoundation.CFStringRef.createCFString("PreventUserIdleSystemSleep");
CoreFoundation.CFStringRef kIOPMAssertPreventUserIdleDisplaySleep = CoreFoundation.CFStringRef.createCFString("PreventUserIdleDisplaySleep");
int kIOReturnSuccess = 0;
int kIOPMAssertionLevelOff = 0;
int kIOPMAssertionLevelOn = 255;
int IOPMAssertionCreateWithName(CoreFoundation.CFStringRef assertionType,
int assertionLevel,
CoreFoundation.CFStringRef reasonForActivity,
IntByReference assertionId);
int IOPMAssertionRelease(int assertionId);
}
Here's an example of invoking the JNA method to turn sleep prevention on or off:
public class Example {
private static final Logger _log = LoggerFactory.getLogger(Example.class);
private int sleepPreventionAssertionId = 0;
public void updateSleepPrevention(final boolean isEnabled) {
if (isEnabled) {
if (sleepPreventionAssertionId == 0) {
final var assertionIdRef = new IntByReference(0);
final var reason = CoreFoundation.CFStringRef.createCFString(
"Example preventing display sleep");
final int result = ExampleIOKit.INSTANCE.IOPMAssertionCreateWithName(
ExampleIOKit.kIOPMAssertPreventUserIdleDisplaySleep,
ExampleIOKit.kIOPMAssertionLevelOn, reason, assertionIdRef);
if (result == ExampleIOKit.kIOReturnSuccess) {
_log.info("Display sleep prevention enabled");
sleepPreventionAssertionId = assertionIdRef.getValue();
}
else {
_log.error("IOPMAssertionCreateWithName returned {}", result);
}
}
}
else {
if (sleepPreventionAssertionId != 0) {
final int result = ExampleIOKit.INSTANCE.IOPMAssertionRelease(sleepPreventionAssertionId);
if (result == ExampleIOKit.kIOReturnSuccess) {
_log.info("Display sleep prevention disabled");
}
else {
_log.error("IOPMAssertionRelease returned {}", result);
}
sleepPreventionAssertionId = 0;
}
}
}
}
Wouldn't it be easier to disable the power management on the server? It might be argued that servers shouldn't go into powersave mode?
This code moves the pointer to the same location where it already is so the user doesn't notice any difference.
while (true) {
Thread.sleep(180000);//this is how long before it moves
Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
Robot rob = new Robot();
rob.mouseMove(mouseLoc.x, mouseLoc.y);
}
Run a command inside a timer like pinging the server..
I'd just do a function (or download a freebie app) that moves the mouse around. Inelegant, but easy.
This will work:
public class Utils {
public static void main(String[] args) throws AWTException {
Robot rob = new Robot();
PointerInfo ptr = null;
while (true) {
rob.delay(4000); // Mouse moves every 4 seconds
ptr = MouseInfo.getPointerInfo();
rob.mouseMove((int) ptr.getLocation().getX() + 1, (int) ptr.getLocation().getY() + 1);
}
}
}
One simple way which i use to avoid "Windows desktop Auto lock" is "Switch On/Off NumLock" every 6 seconds.
Here a Java Program to Switch ON/OFF NumLock.
import java.util.*;
import java.awt.*;
import java.awt.event.*;
public class NumLock extends Thread {
public void run() {
try {
boolean flag = true;
do {
flag = !flag;
Thread.sleep(6000);
Toolkit.getDefaultToolkit().setLockingKeyState(KeyEvent. VK_NUM_LOCK, flag);
}
while(true);
}
catch(Exception e) {}
}
public static void main(String[] args) throws Exception {
new NumLock().start();
}
}
Run this Java program in a separate command prompt; :-)
Related
I wrote a simple test to capture timing metrics using the SPF4J (Simple Profiler Framework For Java) MeasurementRecorder. I'm running a simple for loop and capturing time of a random sleep from 100-200 ms as shown in the complete code sample below.
When I run the test, the Time-Series DataBase (TSDB) files are created successfully, but they're empty while the test is running (around 2 mins). The buffered data are written to files when the application completes, but samples at the end are missing and the last one is truncated, like the buffer is not getting flushed properly.
If the application never terminates (e.g. web service), when will the buffered metrics be written to file - on a timer, or when a certain amount of data is buffered? Is this configurable and, if so, how?
package com.examples.spf4j;
import org.spf4j.perf.MeasurementRecorder;
import org.spf4j.perf.impl.RecorderFactory;
import java.io.File;
import java.util.Random;
import org.junit.Test;
public class TestMeasurementRecorder {
#Test
public void testMeasurementRecorder() throws InterruptedException {
initialize();
MeasurementRecorder measurementRecorder = getMeasurementRecorder();
Random random = new Random();
for (int i=0; i<=1000; i++) {
long startTime = System.currentTimeMillis();
Thread.sleep(100 + random.nextInt(100));
measurementRecorder.record(System.currentTimeMillis() - startTime);
}
}
public static void initialize() {
String tsDbFile = System.getProperty("user.dir") + File.separator + "spf4j-performance-monitor.tsdb2";
String tsTextFile = System.getProperty("user.dir") + File.separator + "spf4j-performance-monitor.txt";
System.setProperty("spf4j.perf.ms.config", "TSDB#" + tsDbFile + "," + "TSDB_TXT#" + tsTextFile);
}
public static MeasurementRecorder getMeasurementRecorder() {
int sampleTimeMillis = 1000;
return RecorderFactory.createScalableQuantizedRecorder("response time", "ms", sampleTimeMillis, 10, 0, 40, 10);
}
}
You will need to set the system property: spf4j.perf.ms.periodicFlush=true
to enable the periodic flush.
I am an old java programmer, translating code from Desktop to Raspberry Pi, with the aim of embedding software in a hardware interface.
I wired a 16*2 character LCD display, which worked with Python code, however when I use pi4j libraries to access the GPIO via Java, the screen is blank.
Am I missing a some binary on/off switch?
I am running pi4j 1.2, on an A+ Pi, got over the 1.1 processor bug that affected wiring Pi.
Thanks for reading, any suggestions are appreciated.
import com.pi4j.component.lcd.LCDTextAlignment;
import com.pi4j.component.lcd.impl.GpioLcdDisplay;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.system.NetworkInfo;
public class LCD {
public static void main(String args[]) {
System.out.println("SYSTEM PRINT TEST");
GpioController gpio = GpioFactory.getInstance();
GpioLcdDisplay lcd = new GpioLcdDisplay(2,16,
RaspiPin.GPIO_26,
RaspiPin.GPIO_31,
RaspiPin.GPIO_15,
RaspiPin.GPIO_16,
RaspiPin.GPIO_01,
RaspiPin.GPIO_04);
lcd.clear();
Thread.sleep(1000);
lcd.write(0, "LINE 1 TEST");
lcd.write(1, "LINE 2 TEST");
Thread.sleep(2000);
gpio.shutdown();
}
}
After spending several hours banging my head on the desk, I decided on this Google search
google.com >> raspberry pi java gpio not working python works
That led me to this question, which for some reason was down voted 3 times, but it was exactly what I was experiencing.
The second result of my search was this question:
Raspberry Pi4 with Pi4j Java
That clued me in on the fact that I needed to add this line of code because pi4j uses a different PIN layout by default.
GpioFactory.setDefaultProvider(new RaspiGpioProvider(RaspiPinNumberingScheme.BROADCOM_PIN_NUMBERING));
That wasn't enough, but that question led me to this question/answer:
Raspberry pi 4 controle GPIO with java
Which explained I needed to update my gpio binary to v2.52
This sample Python code was working without issue:
https://maker.pro/raspberry-pi/projects/controlling-a-dc-motor-with-raspberry-pi4-1
import RPi.GPIO as GPIO
from time import sleep
# Pins for Motor Driver Inputs
Motor1A = 20
Motor1B = 16
Motor1E = 21
def setup():
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # GPIO Numbering
GPIO.setup(Motor1A,GPIO.OUT) # All pins as Outputs
GPIO.setup(Motor1B,GPIO.OUT)
GPIO.setup(Motor1E,GPIO.OUT)
def loop():
# Going forwards
GPIO.output(Motor1A,GPIO.HIGH)
GPIO.output(Motor1B,GPIO.LOW)
GPIO.output(Motor1E,GPIO.HIGH)
print("Going forwards")
sleep(5)
# Going backwards
GPIO.output(Motor1A,GPIO.LOW)
GPIO.output(Motor1B,GPIO.HIGH)
GPIO.output(Motor1E,GPIO.HIGH)
print("Going backwards")
sleep(5)
# Stop
GPIO.output(Motor1E,GPIO.LOW)
GPIO.output(Motor1B,GPIO.LOW)
print("Stop")
def destroy():
GPIO.cleanup()
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt:
destroy()
But my attempts at using the Pi4J Java library were failing miserably.
This is my working Java code:
//This line was initially not here, it is part of the solution
GpioFactory.setDefaultProvider(new RaspiGpioProvider(RaspiPinNumberingScheme.BROADCOM_PIN_NUMBERING));
gpio = GpioFactory.getInstance();
in2 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_16, "IN2", PinState.LOW);
in1 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_20, "IN1", PinState.LOW);
en = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_21, "EN", PinState.LOW);
//Going forwards
in1.high();
in2.low();
en.high();
Thread.sleep(5000);
//Going backwards
in1.low();
in2.high();
en.high();
Thread.sleep(5000);
// stop
en.low();
in2.low();
gpio.shutdown();
The discrepancy between the pin numbering on this jargon code, and the original underlying wiringPi numbering was the cause of this frustration. Here is the revised code, where gpio 25 corresponds to wiringPi 6, not 26! Remember to update wiringPi and pi4j to the latest versions.
import com.pi4j.wiringpi.Gpio;
import com.pi4j.wiringpi.Lcd;
public class LCD {
public final static int LCD_ROWS = 2;
public final static int LCD_COLUMNS = 16;
public final static int LCD_BITS = 4;
public static void main(String args[]) {
System.out.println("SYSTEM PRINT TEST");
if (Gpio.wiringPiSetup() == -1) {
System.out.println("GPIO SETUP ERROR");
return;
}
int lcdHandle= Lcd.lcdInit(LCD_ROWS,
LCD_COLUMNS,
LCD_BITS,
6,
5,
15,
16,
1,
4,
0,
0,
0,
0);
if (lcdHandle == -1) {
System.out.println("LCD INIT ERROR");
return;
}
Lcd.lcdDisplay(lcdHandle,1);
Lcd.lcdClear(lcdHandle);
Lcd.lcdPuts (lcdHandle, "LCD TEST LINE 1") ;
Lcd.lcdPosition (lcdHandle, 0, 1) ;
Lcd.lcdPuts (lcdHandle, "LCD TEST LINE 2") ;
try {
Thread.sleep(10000);
} catch (Exception e) {}
Lcd.lcdDisplay(lcdHandle,0);
}
}
In our Android App we wish to capture Log messages.
We kick off a Process which invokes LogCat, asking for rolling logs.
LogCat starts. We get rolling logs. We get the right number of files. In fact allAll the arguments we specify are honored except for the individual file size argument, -r. No matter what argument we specify for -r we get individual 16K files. We've tried -r 10000 and -r 250 and -r 100 and -r 64. Always 16K files.
EDIT: -r 12 (smaller value) also ignored - get 16K files.
EDIT: As of a few months ago, LogCat spontaneously started to honor our size argument. It must have been a bug that they fixed. Thanks all.
What are we doing wrong?
Here's the call we make:
logcat -f /storage/emulated/0/Android/data/com.example.my.app/files/MyAppLogs.txt -v time -n 20 -r 64 CookActivity:D CookingService:D destroy:W distcooked:D finishedSpeaking:D freeMealReceived:D gotFocus:D keptMenu:D settingNextWakeAlarm:D settingReTryAlarm:D speakBroadcast:D speakerDestroyed:D stopped:D timeupdate:D dalvikvm:W dalvikvm-heap:W MyImageCache:D LogCatManager:D MainActivity:I MainActivity:D *:W *:E
If you're curious:
We take the code structure and file system checks from this and other StackOverflow pages:
Android unable to run logcat from application
We take the call to exec() from this page and others:
http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#exec(java.lang.String[])
From other places we learned that we have to request the app permissions for WRITE_EXTERNAL_STORAGE and READ_LOGS
EDIT: The class we use to manage logCat:
package com.example.my.app.main;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import android.app.Activity;
import android.os.Environment;
import android.os.SystemClock;
import android.util.Log;
/**
* Manages starting the external logCat process and shutting it down.
*
* When this is asked to start an instance of logCat for this application and one is already running,
* a second one is not started.
*
* When this application is shut down gracefully, it tries to shut down its instance of logCat.
*
*/
public class LogCatManager {
private static final String TAG = "LogCatManager";
//The process for logCat - set up initially, tear down when we're done.
Process logSaveProcess = null;
// logcat -f /storage/emulated/0/Android/data/com.example.my.app/files/MyAppLogs.txt -v time -n 20 -r 64 CookActivity:D CookingService:D destroy:W distcooked:D finishedSpeaking:D freeMealReceived:D gotFocus:D keptMenu:D settingNextWakeAlarm:D settingReTryAlarm:D speakBroadcast:D speakerDestroyed:D stopped:D timeupdate:D dalvikvm:W dalvikvm-heap:W MyImageCache:D LogCatManager:D MainActivity:I MainActivity:D *:W *:E
//The index to which the output file name string should be assigned.
static final int logCatOutputFileIndex = 2 ;
//The index to which the number-of-Kbytes-in-each-logfile threshhold should be assigned.
static final int logCatLogKSizeIndex = 8;
//The index to which the number-of-logfiles should be assigned
static final int logCatLogNLogsIndex = 6;
String logCatTokenArray[] = {
"logcat"
,"-f"
,"--THE_OUTPUT_FILE_NAME_GOES_HERE--"
,"-v"
,"time"
,"-n"
,"--THE_NUMBER_OF_LOGFILES_GOES_HERE--"
,"-r"
,"--THE_MAX_LOGFILE_SIZE_GOES_HERE--"
/*\
* entries after this are search criteria - logCat entries matching these are included in the saved file
\*/
,"CookActivity:D"
,"CookingService:D"
,"destroy:W"
,"distcooked:D"
,"finishedSpeaking:D"
,"freeMealReceived:D"
,"gotFocus:D"
,"keptMenu:D"
,"settingNextWakeAlarm:D"
,"settingReTryAlarm:D"
,"speakBroadcast:D"
,"speakerDestroyed:D"
,"stopped:D"
,"timeupdate:D"
,"dalvikvm:W"
,"dalvikvm-heap:W"
,"MyImageCache:D"
,"LogCatManager:D"
,"MainActivity:I"
,"MainActivity:D"
/*\
* these mean 'anything with W or E, include'.
\*/
,"*:W"
,"*:E"
};
/** Turns on and off saving logCat data to a file. **/
public void setLogSaving(Activity act, boolean shouldStart)
{
try
{
if (shouldStart)
{
if (logSaveProcess == null)
{
Log.i(TAG, "logCat starting LogSaving");
startLogSaving(act);
} else {
Log.e(TAG,"logCat asked to start LogSaving - but saving already happening (process reference not null)! request ignored");
}
}
else
{
if (logSaveProcess == null)
{
Log.e(TAG,"could not simply destroy logCat process - have no reference");
}
else
{
Log.i(TAG,"have reference to logCat process object - stopping LogSaving");
logSaveProcess.destroy();
logSaveProcess = null;
}
}
}
catch(Exception e)
{
Log.e(TAG,"exception in setLogSaving("+ shouldStart + ") - " + e.toString());
}
}
//10-18-2014 current experience with current software and logCat arguments
// has RM being able to record about 140 minutes of log data in a megabyte.
//The settings below attempt to give us more than 10 hours on average before rollover.
public final static String SAVINGLOGFILENAME = "MyAppLogs.txt" ;
public final static String SAVINGLOGMAXSIZE = "12" ; //... "64", "100", "250", "10000" (10Meg) too big.
public final static String SAVINGLOGMAXNLOGS = "20" ; //10 has also been honored...
// Took structure and file system checks from this and other StackOverflow pages:
// https://stackoverflow.com/questions/6219345/android-unable-to-run-logcat-from-application?rq=1
//
// Took call to exec() from this and others:
// http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#exec(java.lang.String[])
//
// ** make sure your app has the WRITE_EXTERNAL_STORAGE and READ_LOGS permissions **
//
private void startLogSaving(Activity act) {
String filename = null;
String directory = null;
String fullPath = null;
String externalStorageState = null;
// The directory will depend on if we have external storage available to us or not
try {
filename = SAVINGLOGFILENAME ;
externalStorageState = Environment.getExternalStorageState();
if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
if(android.os.Build.VERSION.SDK_INT <= 7) {
directory = Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
directory = act.getExternalFilesDir(null).getAbsolutePath();
}
} else {
directory = act.getFilesDir().getAbsolutePath();
}
fullPath = directory + File.separator + filename;
// Finish token array by contributing the output file name.
logCatTokenArray[ logCatOutputFileIndex ] = fullPath ;
// ...and the max size.
logCatTokenArray[ logCatLogKSizeIndex ] = SAVINGLOGMAXSIZE ;
// ...and the max number of log files (rotating).
logCatTokenArray[ logCatLogNLogsIndex ] = SAVINGLOGMAXNLOGS ;
Log.w(TAG, "About to start LogCat - " + strJoin(logCatTokenArray, " ") );
logSaveProcess =
Runtime.getRuntime().exec( logCatTokenArray );
} catch (Exception e) {
Log.e(TAG, "startLogSaving, exception: " + e.getMessage());
}
}
// from https://stackoverflow.com/questions/1978933/a-quick-and-easy-way-to-join-array-elements-with-a-separator-the-oposite-of-spl
private static String strJoin(String[] aArr, String sSep) {
StringBuilder sbStr = new StringBuilder();
for (int i = 0, il = aArr.length; i < il; i++) {
if (i > 0)
sbStr.append(sSep);
sbStr.append(aArr[i]);
}
return sbStr.toString();
}
}
As the title says, I'm wondering if it is possible for a program written in Java (and only java) to relaunch himself (preferably a .jar) with administrator privileges, showing in the way the native Windows UAC (in order to make it more trustable for the user), i did my homework and found out that it is possible to accomplish this using bridges between c++ and java, but i would really like to do this as a pure java project.
P.S: In the remote case that this result to be impossible, can someone show me the "easy" way to do this using another language (i mean, I've found tutorials, but they are to complicated for something I think it should not be that complicated).
P.S2: In case it is possible to accomplish this, would it work, on other platforms (OS X, Linux)
It cannot be done in pure java.
Best bet would be to write this to a file:
#echo Set objShell = CreateObject("Shell.Application") > %temp%\sudo.tmp.vbs
#echo args = Right("%*", (Len("%*") - Len("%1"))) >> %temp%\sudo.tmp.vbs
#echo objShell.ShellExecute "%1", args, "", "runas" >> %temp%\sudo.tmp.vbs
#cscript %temp%\sudo.tmp.vbs
and save it as something.bat in Windows temp directory (as we have access to this).
You would then execute this from your application using Runtime or ProcessBuilder and exit your application (System.exit(0);).
You should add an immediate start up check to your application that checks if the program has elevation, if it has proceed if not re-run the batch and exit.
Here is an example I made (this must be run when compiled as a Jar or it wont work):
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.JOptionPane;
/**
*
* #author David
*/
public class UacTest {
public static String jarName = "UacTest.jar", batName = "elevate.bat";
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
if (checkForUac()) {//uac is on
JOptionPane.showMessageDialog(null, "I am not elevated");
//attempt elevation
new UacTest().elevate();
System.exit(0);
} else {//uac is not on
//if we get here we are elevated
JOptionPane.showMessageDialog(null, "I am elevated");
}
}
private static boolean checkForUac() {
File dummyFile = new File("c:/aaa.txt");
dummyFile.deleteOnExit();
try {
//attempt to craete file in c:/
try (FileWriter fw = new FileWriter(dummyFile, true)) {
}
} catch (IOException ex) {//we cannot UAC muts be on
//ex.printStackTrace();
return true;
}
return false;
}
private void elevate() {
//create batch file in temporary directory as we have access to it regardless of UAC on or off
File file = new File(System.getProperty("java.io.tmpdir") + "/" + batName);
file.deleteOnExit();
createBatchFile(file);
runBatchFile();
}
private String getJarLocation() {
return getClass().getProtectionDomain().getCodeSource().getLocation().getPath().substring(1);
}
private void runBatchFile() {
//JOptionPane.showMessageDialog(null, getJarLocation());
Runtime runtime = Runtime.getRuntime();
String[] cmd = new String[]{"cmd.exe", "/C",
System.getProperty("java.io.tmpdir") + "/" + batName + " java -jar " + getJarLocation()};
try {
Process proc = runtime.exec(cmd);
//proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void createBatchFile(File file) {
try {
try (FileWriter fw = new FileWriter(file, true)) {
fw.write(
"#echo Set objShell = CreateObject(\"Shell.Application\") > %temp%\\sudo.tmp.vbs\r\n"
+ "#echo args = Right(\"%*\", (Len(\"%*\") - Len(\"%1\"))) >> %temp%\\sudo.tmp.vbs\r\n"
+ "#echo objShell.ShellExecute \"%1\", args, \"\", \"runas\" >> %temp%\\sudo.tmp.vbs\r\n"
+ "#cscript %temp%\\sudo.tmp.vbs\r\n"
+ "del /f %temp%\\sudo.tmp.vbs\r\n");
}
} catch (IOException ex) {
//ex.printStackTrace();
}
}
}
Use a batch file and the runas command.
I doubt "only Java". At best you would have to have a JNI wrapper around the MSFT module. Unless just invoking the exe using ProcessBuilder counts as "only Java" -- your code to bring up the user console would be only Java but not what it invokes. IOW, Win does not come with a Java API
To relaunch your application elevated, you have to call ShellExecute or ShellExecuteEx function from Windows API and use runas verb.
You can use these API in pure Java with JNA library.
To relaunch yourself, you would have to know the full path to java.exe or javaw.exe, the command-line parameters (class path, if any, and the path to your jar). Obviously you can get this information by using Windows API.
What do you mean by remote case?
You cannot start remote elevated process this way.
You can re-launch your application elevated from a network share. Yet it won't work with mapped drives: after elevation there's no access to user's mapped drives.
No, this can't work on other platforms. UAC is a Windows feature. It's similar to sudo in Linux in some ways, so for Linux you can use sudo $pathtojava/java.exe <yourparameters>. However this won't work nicely if your application is not started from a console. Window Managers usually have wrappers which prompt for password in a GUI dialog.
Just do this with Hackaprofaw (v29). Also it was released in 2002 and started development in 1997 soooooo ye. in 2021 its on version 29.10.7 but-
if raw ram = 0
disable "featureII" program = "JAVA(math = any)"
run on "Hackaprofaw (math = v29(x))
when "featureII" disabled
end
I want to be able to execute the .Jar file, and if the heap space isn't set big enough, it should launch a new JVM with the same .Jar file, but set with a bigger heap space, and then close the first JVM and .Jar.
I've tried using the ProcessBuilder, but I can't get it to work.
It has to work cross platform.
-ONi
I have found the solution, and it works cross platform. To restart the JVM from code, use the following. This answer is taken from another question I found after hours of search in here. If you want, you can follow it with an System.exit(0), to terminate the JVM that started the new process, after a call to this method.
public static void startSecondJVM() throws Exception {
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-Xmx1024m", "-cp",
classpath,
Main.class.getName());
Process process = processBuilder.start();
}
You can launch java with an initial heap size, and also specify a maximum heap size which will be only be used as required. I'm not sure what you're trying to do but it might emulate the behaviour you want?
java -Xms256m -Xmx1g -jar myapp.jar
In this example you start with 256M, if the app needs more memory it will take it, incrementally, up until 1G.
You might try combining these two sources.
MemoryRecoveryTest.java
Makes attempts to recover from an OutOfMemoryError.
/*License - LGPL
<h3>Recovery from an OutOfMemory Error</h3>
<p>The JavaDocs for Error state, in the first sentence..
<blockquote>"An Error is a subclass of Throwable that indicates
serious problems that a reasonable application should
not try to catch."</blockquote>
<p>This advice has led to the fallacy that an OutOfMemoryError
should not be caught and dealt with.But this demo. shows
that it is quite easy to recover to the point of providing
the user with meaningful information, and advice on how to
proceed.
<p>I aim to make my applications 'unreasonable'.;-)
*/
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JOptionPane;
import javax.swing.JDialog;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import java.util.ArrayList;
/** A demo. showing recovery from an OutOfMemoryError.
Our options once an OOME is encountered are relatively
few, but we can still warn the end user and provide
advice on how to correct the problem.
#author Andrew Thompson */
public class MemoryRecoveryTest {
public static void main(String[] args) {
// reserve a buffer of memory
byte[] buffer = new byte[2^10];
ArrayList<Object> list = new ArrayList<Object>();
final JProgressBar memory = new JProgressBar(
0,
(int)Runtime.getRuntime().totalMemory());
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
memory.setValue(
(int)Runtime.getRuntime().freeMemory() );
}
};
Timer timer = new Timer(500, listener);
timer.start();
JDialog dialog = new JDialog();
dialog.setTitle("Available Memory");
JPanel memoryPanel = new JPanel();
memoryPanel.add(memory);
memoryPanel.setBorder(new EmptyBorder(25,25,25,25));
dialog.add( memoryPanel );
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
dialog.addWindowListener( new WindowAdapter(){
#Override
public void windowClosing(WindowEvent we) {
System.exit(0);
}
} );
// prepare a memory warning panel in advance
JPanel memoryWarning = new JPanel();
memoryWarning.add( new JLabel(
"<HTML><BODY>There is not enough memory to" +
" complete the task!<BR> Use a variant " +
" of the application that assigns more memory.") );
try {
// do our 'memory intensive' task
while(true) {
list.add( new Object() );
}
} catch(OutOfMemoryError oome) {
// provide the VM with some memory 'breathing space'
// by clearing the buffer
buffer = null;
// tell the user what went wrong, and how to fix it
JOptionPane.showMessageDialog(
dialog,
memoryWarning,
"Out of Memory!",
JOptionPane.ERROR_MESSAGE);
}
}
}
IWantToBeBig.java
Ensures a Process is started with a memory size specified.
import java.awt.EventQueue;
import javax.swing.JOptionPane;
import java.io.File;
class IWantToBeBig {
public static void main(String[] args) throws Exception {
if (args.length==0) {
ProcessBuilder pb = new ProcessBuilder(
"java",
"-jar",
"-Xmx512m",
"big.jar",
"anArgument"
);
pb.directory(new File("."));
Process process = pb.start();
process.waitFor();
System.out.println("Exit value: " + process.exitValue());
} else {
Runnable r = new Runnable() {
public void run() {
JOptionPane.showMessageDialog(
null,
"Max Memory: " +
Runtime.getRuntime().maxMemory() +
" bytes.");
}
};
EventQueue.invokeLater(r);
}
}
}
I'd do this kind of work in an outer script file - in pseudo code:
$heap := 128
$ok := true
do {
exitCode = java -Xmx$heapM -jar myApp.jar
if (exitCode = OOME) {
heap += 128
$ok := false
}
while(!$ok)
Catch OOME and exiting with a custom code should always be possible. There's one problem with this approach - if the $heap value exceeds the maximum heap space that is possible for the target system (example: ~1.4GByte on Win32 systems) then it will not terminate.
Note: this is just an answer to the question - usually one would assign a high amount of memory and/or fight the memory leaks - but I don't know the actual requirments/restrictions