Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected different results from the same String input

I have a BroadcastReceiver that receives input from an outside source.

This receiver must then behave as a "mouse-like" program and send input events to the system. I have Root access and permissions.

My problem is that when I send a String such as "input tap 275 410", the program behaves correctly, if I even split the string such as "input" + " tap" + " 275" + " 410", it still works...

However, when I assemble the string as the desired:

"input " + CursorSystem.command + " " + coords[0] + " " + coords[1]

Then nothing happens... while debugging, all the watched Strings are exactly the same (minus the location):

value = {char[26]@830031306976}  0 = 'i' 105 1 = 'n' 110 2 = 'p' 112 3 = 'u' 117 4 = 't' 116 5 = ' ' 32 6 = 't' 116 7 = 'a' 97 8 = 'p' 112 9 = ' ' 32 10 = '2' 50 11 = '7' 55 12 = '5' 53 13 = ' ' 32 14 = '4' 52 15 = '1' 49 16 = '0' 48 17 = '\u0000' 0 18 = '\u0000' 0 19 = '\u0000' 0 20 = '\u0000' 0 21 = '\u0000' 0 22 = '\u0000' 0 23 = '\u0000' 0 24 = '\u0000' 0 25 = '\u0000' 0

I would like some guidance or a property to study, since my results are not being effective. As far as I can tell, this is not a permission issue, nor is it a thread issue, since Logs show the permission request (and the grant), an the thread lives for as long as the Receiver is being executed (but if I debug it for too long, then it gets killed after a while [30+ seconds])

The Receiver.onReceive:

public void onReceive(Context context, Intent intent) {
    String command = intent.getStringExtra("command");
    String touch = intent.getStringExtra("touch");
    if (Executor.isRootAvailable()) {
        Executor executor = new Executor();
        ArrayList<String> commands = new ArrayList<>();
        if (command != null) {
            if (command.length() > 0) {
                if (commands.add("input " + command)) {
                    executor.execute(commands);
                }
            }
        } else if (touch != null) {
            if (CursorSystem.isAlive) { // Always true for the executions
                CursorSystem.doInput();
                if (CursorSystem.state == CursorSystem.STATE) { // Always true for the executions
                    int[] coords = CursorSystem.coordinates;
                    if (coords != null) {
// This line is where (I guess) that the problem lies.
// CursorSystem.command is "tap", coords[0] and coords[1] is the result of (a view).getLocationOnScreen(coordinates)
// It results in a 2 positions int array with (x, y) coordinates, these values are always correct.
                        if (commands.add("input " + CursorSystem.command + " " + coords[0] + " " + coords[1])) {
                            executor.execute(commands);
                            CursorSystem.doInput();
                        } else {
                            // error...
                        }
                    } else {
                        // error...
                    }
                } else {
                    // error...
                }
            } else {
                error...
            }
        } else {
            error...
        }
    } else {
        error...
    }
}

The Executor.execute:

public final boolean execute(ArrayList<String> commands) {
    boolean resp = false;
    try {
        if (commands != null && commands.size() > 0) {
            Process suProcess = Runtime.getRuntime().exec("su");
            DataOutputStream dataOutputStream = new DataOutputStream(suProcess.getOutputStream());
            for (String currCommand : commands) {
                dataOutputStream.writeBytes(currCommand);
                dataOutputStream.writeBytes("\n");
                dataOutputStream.flush();
            }
            dataOutputStream.writeBytes("exit\n");
            dataOutputStream.flush();
            try {
                int suProcessRetval = suProcess.waitFor();
                return (suProcessRetval != 255); // Always yields 0
            } catch (Exception ex) {
                // errors...
            }
        } else {
            // error...
        }
    } catch (IOException ex) {
        Log.w(TAG, "IOException: ", ex);
    } catch (SecurityException ex) {
        Log.w(TAG, "SecurityException: ", ex);
    } catch (Exception ex) {
        Log.w(TAG, "Generic Exception: ", ex);
    }
    return resp;
}
like image 811
Bonatti Avatar asked Dec 22 '15 19:12

Bonatti


1 Answers

For anyone interested:

The problem found was that the CursorSystem used ImageViews, that aided the user to "target" what interaction was desired (and where). During execution, the command could be received, and the image be moved to where the command would happens, thus "receiving" the event.

Adding the following flags:

.LayoutParams.FLAG_NOT_FOCUSABLE
.LayoutParams.FLAG_NOT_TOUCHABLE
.LayoutParams.FLAG_LAYOUT_NO_LIMITS

Allowed the system to not consider the Views as interactable, as well as "draw" them outside of bounds, so that the user could "swipe" the device hidden menus, as well as click on a target that could potentially NOT exist. This caused some "Launcher" programs to intercept the MotionEvent, and do nothing.

The command was being executed successfully, just no result was being displayed, and caused us to interpret it as "doing nothing".

like image 159
Bonatti Avatar answered Oct 13 '22 03:10

Bonatti