Help with something easy.

Discussion in 'Android App Developers' started by Abadus, Jun 13, 2010.

  1. Abadus
    Offline

    Abadus New Member

    Joined:
    Apr 2, 2010
    Messages:
    221
    Likes Received:
    2
    Trophy Points:
    0
    At least I think this is easy.

    I was going to write an app to install a boot animation.

    Now with my app I can copy my boot animation to any folder on my SD card so I know my code is working but I cannot for the life of me copy it to anywhere on the system.

    I have su access and my app shows up under my super user ninja. So I am unsure what the issue is. I am trying to write to /data/local and you don't have to mount that area to write to it you just need su.

    I can check /data/local for the bootanimation.zip and that works fine... but like I said nothing I do allows me to move it there.

    Code:
     Process p;
      try {
        p = Runtime.getRuntime().exec("cp " + BOOTANIMATION + " " + DESTINATION);
    		} catch (IOException e) {
    		// TODO Auto-generated catch block
    				e.printStackTrace();
    				}
    ^^ should work with BOOTANIMATION being /sdcard/bootanimation.zip and DESTINATION being /data/local/bootanimation.zip

    I forget the other way I tried but anyways be gentle I am a TOTAL noob. I just wanted to make a nice little app to help people install boot animations. People always seem to have problems doing it. (Not even sure if this is the right place for this.)
  2. mwhartman
    Offline

    mwhartman Super Moderator/RS Premium Member

    Joined:
    Jan 15, 2010
    Messages:
    10,739
    Likes Received:
    12
    Trophy Points:
    38
    Location:
    South FL
    Sorry this is above my pay grade. Until someone more knowledgeable responds you may be able to find some answers in one of more of the forum sections (development, themes, FAQ).

    Mike
  3. Abadus
    Offline

    Abadus New Member

    Joined:
    Apr 2, 2010
    Messages:
    221
    Likes Received:
    2
    Trophy Points:
    0
    Maybe I do need to mount first?
  4. kevin@teslacoilsw
    Offline

    kevin@teslacoilsw New Member

    Joined:
    Jun 7, 2010
    Messages:
    108
    Likes Received:
    0
    Trophy Points:
    0
    Root apps are tricky.
    As you said, you need to use su, so:
    Code:
        p = Runtime.getRuntime().exec("su -c 'cp " + BOOTANIMATION + " " +  DESTINATION + "'");
    might work. However every root method is a bit different so if you want this to run on many phones then that's a bit fragile.
    1) Not all phones' su supports -c
    2) Not all phones have a cp command

    So I'd recommend using "cat foo > bar" and printing that to an su session.

    I wrote some code to handle this (I use it in my QuickSSHd app) you can try it (and feel free to use it in your app in any way)
    http://teslacoilsw.com/files/ShellCommand.java

    Use with
    Code:
    ShellCommand cmd = new ShellCommand();
    cmd.su.run("cat " + BOOTANIMATION + " > " + DESTINATION);
    
    ShellCommand.java
    Code:
    package com.teslacoilsw.quicksshd;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    
    import android.util.Log;
    
    public class ShellCommand {
        private static final String TAG = "ShellCommand.java";
        private Boolean can_su;    
    
        public SH sh;
        public SH su;
        
        public ShellCommand() {
            sh = new SH("sh");
            su = new SH("su");
        }
        
        public boolean canSU() {
            return canSU(false);
        }
        
        public boolean canSU(boolean force_check) {
            if (can_su == null || force_check) {
                CommandResult r = su.runWaitFor("id");
                StringBuilder out = new StringBuilder();
                
                if (r.stdout != null)
                    out.append(r.stdout).append(" ; ");
                if (r.stderr != null)
                    out.append(r.stderr);
                
                Log.v(TAG, "canSU() su[" + r.exit_value + "]: " + out);
                can_su = r.success();
            }
            return can_su;
        }
    
        public SH suOrSH() {
            return canSU() ? su : sh;
        }
        
        public class CommandResult {
            public final String stdout;
            public final String stderr;
            public final Integer exit_value;
            
            CommandResult(Integer exit_value_in, String stdout_in, String stderr_in)
            {
                exit_value = exit_value_in;
                stdout = stdout_in;
                stderr = stderr_in;
            }
            
            CommandResult(Integer exit_value_in) {
                this(exit_value_in, null, null);
            }
            
            public boolean success() {
                return exit_value != null && exit_value == 0;
            }
        }
    
        public class SH {
            private String SHELL = "sh";
    
            public SH(String SHELL_in) {
                SHELL = SHELL_in;
            }
    
            public Process run(String s) {
                Process process = null;
                try {
                    process = Runtime.getRuntime().exec(SHELL);
                    DataOutputStream toProcess = new DataOutputStream(process.getOutputStream());
                    toProcess.writeBytes("exec " + s + "\n");
                    toProcess.flush();
                } catch(Exception e) {
                    Log.e(QuickSSHD.TAG, "Exception while trying to run: '" + s + "' " + e.getMessage());
                    process = null;
                }
                return process;
            }
            
            private String getStreamLines(InputStream is) {
                String out = null;
                StringBuffer buffer = null;
                DataInputStream dis = new DataInputStream(is);
    
                try {
                    if (dis.available() > 0) { 
                        buffer = new StringBuffer(dis.readLine());
                        while(dis.available() > 0)
                            buffer.append("\n").append(dis.readLine());
                    }
                    dis.close();
                } catch (Exception ex) {
                    Log.e(TAG, ex.getMessage());
                }
                if (buffer != null)
                    out = buffer.toString();
                return out;
            }
    
            public CommandResult runWaitFor(String s) {
                Process process = run(s);
                Integer exit_value = null;
                String stdout = null;
                String stderr = null;
                if (process != null) {
                    try {
                        exit_value = process.waitFor();
                        
                        stdout = getStreamLines(process.getInputStream());
                        stderr = getStreamLines(process.getErrorStream());
                        
                    } catch(InterruptedException e) {
                        Log.e(TAG, "runWaitFor " + e.toString());
                    } catch(NullPointerException e) {
                        Log.e(TAG, "runWaitFor " + e.toString());
                    }
                }
                return new CommandResult(exit_value, stdout, stderr);
            }
        }
    }
    
  5. dmill
    Offline

    dmill New Member

    Joined:
    Feb 3, 2011
    Messages:
    2
    Likes Received:
    0
    Trophy Points:
    0
    I failed....

    Hey kevin@teslacoilsw,

    I've been attempting to have an input field (EditText view) grab that and put it through your code. I'm on And SDK 2.2 (droid is rooted and busybox is installed, permissions have been allowed). Compiler says no errors but the program kills itself when a command is run.

    here's my code:
    Code:
    public void onClick(View v) {
        
                    // commandInput is a EditView
                    commandInput = input.getText();
                    command.setText(commandInput);
    
                    // Calling your ShellCommand.java
                    ShellCommand cmd = new ShellCommand();
    
                    output.setText((CharSequence) cmd.su.run(commandInput.toString()));
               
    }
    
    Haven't changed your code at all.... in "ShellCommand.java"...

    it asks my Droid for permissions (as it is calling "su") and the dies...

    I've used another piece of code as well but the only command that works on that is "ls" (as far as I've found):

    Code:
    public void onClick(View v) {
    
                    // commandInput is a EditView
                    commandInput = input.getText();
                    command.setText(commandInput);
    
                    // Run command and set output (Scrollable TextView)
                    output.setText(runThis(commandInput.toString()));
               
                }
                private String runThis(String input) {
                    // This runs the command and returns the result as a String
                    try {
                       
                        // Executes the command.
                        Process process = Runtime.getRuntime().exec(input);
                       
                        // Reads stdout.
                        BufferedReader reader = new BufferedReader(
                                new InputStreamReader(process.getInputStream()));
                        int read;
                        char[] buffer = new char[4096];
                        StringBuffer output = new StringBuffer();
                        while ((read = reader.read(buffer)) > 0) {
                            output.append(buffer, 0, read);
                        }
                        reader.close();
                       
                        // Waits for the command to finish.
                        process.waitFor();
    
                        // Returns output
                        return output.toString();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
    
    Firstly hope this helps and secondly can anyone help

    One this I can attribute to this is if the output is too long for a "String"... The other one is that it just aint going to work.


    *Edited stuff...

    I'm wanting to return a string to display... I've changed:
    Code:
    output.setText((CharSequence) cmd.su.run(commandInput.toString()));
    
    To:
    Code:
    output.setText(cmd.su.run(commandInput.toString()).toString());
    
    Now its just giving me the process ID.... so it is working but I see your code isn't for displaying the output... what do I have to change to do that? (in your code that is....). Much appreciated.... thanks
    Last edited: Feb 3, 2011
  6. lynchmv
    Offline

    lynchmv New Member

    Joined:
    Apr 25, 2011
    Messages:
    2
    Likes Received:
    0
    Trophy Points:
    0
    dmill, did you ever figure out how to get that code to output the command output instead of the process id? If so, could you post your solution? If not, thanks for at least helping me get on the right track with kevin@teslacoilsw's code.
  7. lynchmv
    Offline

    lynchmv New Member

    Joined:
    Apr 25, 2011
    Messages:
    2
    Likes Received:
    0
    Trophy Points:
    0
    dmill, I figured it out.

    Code:
                String btmac = getMyPrefs("btaddr");
                ShellExec cmd = new ShellExec();
                ShellExec.CommandResult cmdRes = cmd.su.runWaitFor("sdptool search DUN --bdaddr " + btmac);
                StringBuilder out = new StringBuilder();
                
                if(cmdRes.stdout != null) {
                    out.append(cmdRes.stdout);
                }
                
                String cmdResOut = out.toString();
                Log.d(TAG,"Command output: " + cmdResOut);
    
    There may be a more graceful way to get it, but I think you can get the idea from that.
Search tags for this page
android exec(su)
,
android runtime exec block
,
android runtime.getruntime example
,

android runtime.getruntime().exec

,
runtime.exec(su) android