From 42b0ad635034b4f663055f7dec9088fc94820b1e Mon Sep 17 00:00:00 2001 From: Steve Slaven Date: Tue, 13 Dec 2011 08:44:31 -0800 Subject: Remote context diff --git a/README b/README new file mode 100644 index 0000000..8f822c2 --- /dev/null +++ b/README @@ -0,0 +1,27 @@ +To set up the project: + +Go to properties -> add external jar -> path to android/platforms/4/android.jar + + +To create the jar: + +Right-click the RootContext.java in eclipse -> export -> jar + +This will exclude the stub files needed to compile, creating a normal java +jar, then you need to make it a dex jar: + +dx --dex --outfile output.jar RootContext.jar + +Include the output.jar file for the app_process jar + +This jar needs to be dx'ed so it will run from android, normally if you +include a jar in your project and build an apk it will be dx'ed when it is +put in the apk. Since we use this as an asset and spool it out to run +natively we must dx it ourself. + +The dx tool can also create a jar from a single .class file, so if you +compiled using a command line tool you can just create the jar from the +.class: + +dx --dex --output=RemoteContext.jar net/hoopajoo/android/RemoteContext.class + diff --git a/src/android/os/IPowerManager.java b/src/android/os/IPowerManager.java new file mode 100644 index 0000000..3ad417b --- /dev/null +++ b/src/android/os/IPowerManager.java @@ -0,0 +1,14 @@ +package android.os; + +import android.os.Binder; +import android.os.IBinder; + +public interface IPowerManager { + public static class Stub { + public static IPowerManager asInterface( IBinder binder ) { + return null; + } + } + + public void goToSleep( long time ); +} diff --git a/src/android/os/ServiceManager.java b/src/android/os/ServiceManager.java new file mode 100644 index 0000000..b67d5b3 --- /dev/null +++ b/src/android/os/ServiceManager.java @@ -0,0 +1,7 @@ +package android.os; + +public class ServiceManager { + public static IBinder getService( String serviceName ) throws RemoteException { + return null; + } +} diff --git a/src/android/view/IWindowManager.java b/src/android/view/IWindowManager.java new file mode 100644 index 0000000..5bba8ca --- /dev/null +++ b/src/android/view/IWindowManager.java @@ -0,0 +1,15 @@ +package android.view; + +import android.os.Binder; +import android.os.IBinder; +import android.view.KeyEvent; + +public interface IWindowManager { + public static class Stub { + public static IWindowManager asInterface( IBinder binder ) { + return null; + } + } + + public boolean injectKeyEvent( KeyEvent keyEvent, boolean f ); +} \ No newline at end of file diff --git a/src/net/hoopajoo/android/RemoteContext.java b/src/net/hoopajoo/android/RemoteContext.java new file mode 100644 index 0000000..bf44cad --- /dev/null +++ b/src/net/hoopajoo/android/RemoteContext.java @@ -0,0 +1,139 @@ +package net.hoopajoo.android; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.util.Log; +import android.view.IWindowManager; +import android.view.KeyEvent; +import android.os.IPowerManager; +import android.content.Context; + +/* + * Inject events as root in to the android framework, accepts commands on stdin, + * + * This gives finer access control to keydown/up and also to put the device to sleep + * + * Other things that are blocked from normal apps that have an interface could be added here + * like pointer control + */ + +public class RemoteContext { + private boolean debug = false; + private final String LOG = "RootContext"; + + public static void main( String[] args ) { + (new RemoteContext()).run( args ); + } + + private void run( String[] args ) { + if( args.length > 0 ) { + debug = true; + d( "Debugging enabled" ); + } + + BufferedReader input = new BufferedReader( + new InputStreamReader( System.in ), + 2 * 1024 ); + + String cmd; + try { + while( true ) { + cmd = input.readLine(); + + d( "Read: " + cmd ); + + String[] parts = cmd.split( " " ); + + if( debug ) { + for( String s : parts ) { + d( "Part: " + s ); + } + } + + boolean processed = false; + if( parts.length > 0 ) { + if( parts[ 0 ].startsWith( "key") ) { + int code = Integer.parseInt( parts[ 1 ] ); + if( parts[ 0 ].equals( "keycode" ) ) { + // key down, up + d( "Sending keycode: " + code ); + sendKeyCode( code, KeyEvent.ACTION_DOWN ); + sendKeyCode( code, KeyEvent.ACTION_UP ); + processed = true; + }else if( parts[ 0 ].equals( "keycodedown" ) ) { + d( "Sending keycode DOWN: " + code ); + sendKeyCode( code, KeyEvent.ACTION_DOWN ); + processed = true; + }else if( parts[ 0 ].equals( "keycodeup" ) ) { + d( "Sending keycode UP: " + code ); + sendKeyCode( code, KeyEvent.ACTION_UP ); + processed = true; + } + } + + if( parts[ 0 ].equals( "sleep" ) ) { + d( "Going to sleep" ); + goToSleep(); + processed = true; + } + + if( parts[ 0 ].equals( "null" ) ) { + d( "null command" ); + processed = true; + } + + if( parts[ 0 ].equals( "system" ) ) { + Runtime r = Runtime.getRuntime(); + String exec = cmd.substring( "system ".length() ); + d( "Executing shell command: '" + exec + "'" ); + r.exec( exec ); + processed = true; + } + } + + if( ! processed ) { + Log.e( LOG, "Failed to process input: " + cmd ); + d( "Failed to process input: " + cmd ); + } + } + }catch( Exception e ) { + Log.i( LOG, e.toString() ); + } + + d( "Finished" ); + } + + private void d( String s ) { + if( debug ) { + //System.out.println( s ); + Log.d( LOG, s ); + } + } + + private void sendKeyCode( int code, int action ) { + long now = SystemClock.uptimeMillis(); + KeyEvent k = new KeyEvent(now, now, action, code, 0); + + try { + ( IWindowManager.Stub + .asInterface( ServiceManager.getService( Context.WINDOW_SERVICE) ) ) + .injectKeyEvent( k , true ); + } catch (RemoteException e) { + Log.i( LOG, e.toString() ); + } + } + + private void goToSleep() { + try { + ( IPowerManager.Stub + .asInterface( ServiceManager.getService( Context.POWER_SERVICE ) ) ) + .goToSleep( SystemClock.uptimeMillis() ); + } catch (RemoteException e) { + Log.i( LOG, e.toString() ); + } + } +} -- cgit v0.10.2