Help with something easy.

Abadus

Member
Joined
Apr 2, 2010
Messages
221
Reaction score
2
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.)
 

mwhartman

Super Moderator/RS
Premium Member
Joined
Jan 15, 2010
Messages
10,635
Reaction score
12
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
 
Joined
Jun 7, 2010
Messages
108
Reaction score
0
Code:
    p = Runtime.getRuntime().exec("cp " + BOOTANIMATION + " " + DESTINATION);

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);
        }
    }
}
 

dmill

New Member
Joined
Feb 3, 2011
Messages
2
Reaction score
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:

lynchmv

New Member
Joined
Apr 25, 2011
Messages
2
Reaction score
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.
 

lynchmv

New Member
Joined
Apr 25, 2011
Messages
2
Reaction score
0
Hey kevin@teslacoilsw,
...
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

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.
 
Top