I would like to have a silent update in my app without any user interaction.
But I always get the error code 139.
The hardware is rooted!
Can anyone help?
Here is the code:
public class UpdateAPK extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.updateapk);
if (isRooted() == true) {
Toast.makeText(UpdateAPK.this, "Hardware is rooted", Toast.LENGTH_LONG).show();
try {
Process install = Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r /mnt/sdcard/app.apk"});
install.waitFor();
if (install.exitValue() == 0) {
// Success :)
Toast.makeText(UpdateAPK.this, "Success!", Toast.LENGTH_LONG).show();
} else {
// Fail
Toast.makeText(UpdateAPK.this, "Failure. Exit code: " + String.valueOf(install.exitValue()), Toast.LENGTH_LONG).show();
}
} catch (IOException e) {
System.out.println(e.toString());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
//Do soemthing else
}
}
Thank you!
I'd avoid hard-coding entire SD card path. Try something like this:
String filePath = Environment.getExternalStorageDirectory().toString() + "/your_app_directory/your_app_filename.apk";
Process installProcess = null;
int installResult = -666;
try
{
installProcess = Runtime.getRuntime().exec("su -c pm install -r " + filePath);
}
catch (IOException e)
{
// Handle IOException the way you like.
}
if (installProcess != null)
{
try
{
installResult = installProcess.waitFor();
}
catch(InterruptedException e)
{
// Handle InterruptedException the way you like.
}
}
if (installResult == 0)
{
// Success!
}
else
{
// Failure. :-/
}
Also, be careful about permissions... You could add:
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
First declare this variables, then call function wherever you want. Then grant superuser, on your superuser application, check the option to always grant, for non user interaction.
final String libs = "LD_LIBRARY_PATH=/vendor/lib:/system/lib ";
final String commands = libs + "pm install -r " + "your apk directory"+ "app.apk";
instalarApk(commands);
private void instalarApk( String commands ) {
try {
Process p = Runtime.getRuntime().exec( "su" );
InputStream es = p.getErrorStream();
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes(commands + "\n");
os.writeBytes("exit\n");
os.flush();
int read;
byte[] buffer = new byte[4096];
String output = new String();
while ((read = es.read(buffer)) > 0) {
output += new String(buffer, 0, read);
}
p.waitFor();
} catch (IOException e) {
Log.v(Debug.TAG, e.toString());
} catch (InterruptedException e) {
Log.v(Debug.TAG, e.toString());
}
}
Related
I'm trying to execute this command from the application emulator terminal (you can find it in google play) in this app i write su and press enter, so write:
screenrecord --time-limit 10 /sdcard/MyVideo.mp4
and press again enter and start the recording of the screen using the new function of android kitkat.
so, i try to execute the same code from java using this:
Process su = Runtime.getRuntime().exec("su");
Process execute = Runtime.getRuntime().exec("screenrecord --time-limit 10 /sdcard/MyVideo.mp4");
But don't work because the file is not created. obviously i'm running on a rooted device with android kitkat installed. where is the problem? how can i solve? because from terminal emulator works and in Java not?
You should grab the standard input of the su process just launched and write down the command there, otherwise you are running the commands with the current UID.
Try something like this:
try{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
outputStream.writeBytes("screenrecord --time-limit 10 /sdcard/MyVideo.mp4\n");
outputStream.flush();
outputStream.writeBytes("exit\n");
outputStream.flush();
su.waitFor();
}catch(IOException e){
throw new Exception(e);
}catch(InterruptedException e){
throw new Exception(e);
}
A modification of the code by #CarloCannas:
public static void sudo(String...strings) {
try{
Process su = Runtime.getRuntime().exec("su");
DataOutputStream outputStream = new DataOutputStream(su.getOutputStream());
for (String s : strings) {
outputStream.writeBytes(s+"\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
outputStream.close();
}catch(IOException e){
e.printStackTrace();
}
}
(You are welcome to find a better place for outputStream.close())
Usage example:
private static void suMkdirs(String path) {
if (!new File(path).isDirectory()) {
sudo("mkdir -p "+path);
}
}
Update:
To get the result (the output to stdout), use:
public static String sudoForResult(String...strings) {
String res = "";
DataOutputStream outputStream = null;
InputStream response = null;
try{
Process su = Runtime.getRuntime().exec("su");
outputStream = new DataOutputStream(su.getOutputStream());
response = su.getInputStream();
for (String s : strings) {
outputStream.writeBytes(s+"\n");
outputStream.flush();
}
outputStream.writeBytes("exit\n");
outputStream.flush();
try {
su.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
res = readFully(response);
} catch (IOException e){
e.printStackTrace();
} finally {
Closer.closeSilently(outputStream, response);
}
return res;
}
public static String readFully(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toString("UTF-8");
}
The utility to silently close a number of Closeables (Soсket may be no Closeable) is:
public class Closer {
// closeAll()
public static void closeSilently(Object... xs) {
// Note: on Android API levels prior to 19 Socket does not implement Closeable
for (Object x : xs) {
if (x != null) {
try {
Log.d("closing: "+x);
if (x instanceof Closeable) {
((Closeable)x).close();
} else if (x instanceof Socket) {
((Socket)x).close();
} else if (x instanceof DatagramSocket) {
((DatagramSocket)x).close();
} else {
Log.d("cannot close: "+x);
throw new RuntimeException("cannot close "+x);
}
} catch (Throwable e) {
Log.x(e);
}
}
}
}
}
Process p;
StringBuffer output = new StringBuffer();
try {
p = Runtime.getRuntime().exec(params[0]);
BufferedReader reader = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
p.waitFor();
}
}
catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
String response = output.toString();
return response;
Late reply, but it will benefit someone. You can use the sh command in the exec() method.
Here is my example:
try {
File workingDirectory = new File(getApplicationContext().getFilesDir().getPath());
Process shProcess = Runtime.getRuntime().exec("sh", null, workingDirectory);
try{
PrintWriter outputExec = new PrintWriter(new OutputStreamWriter(shProcess.getOutputStream()));
outputExec.println("PATH=$PATH:/data/data/com.bokili.server.nginx/files;export LD_LIBRARY_PATH=/data/data/com.bokili.server.nginx/files;nginx;exit;");
outputExec.flush();
} catch(Exception ignored){ }
shProcess.waitFor();
} catch (IOException ignored) {
} catch (InterruptedException e) {
try{ Thread.currentThread().interrupt(); }catch(Exception ignored){}
} catch (Exception ignored) { }
What have I done with this?
First I call the shell, then I change (set) the necessary environments in it, and finally I start my nginx with it.
This works on unrooted devices too.
Greetings.
I want to change the value of variable in xml. The value is based on another file which read by editXml.sh. So I need to run the editXml.sh before app is compiled.
I try to run the script in MainActivity with code as follows:
onCreate() {
......
execScript();
}
execScript(){
try{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("sh /.../editXml.sh");
} catch(Throwable t)
{
t.printStackTrace();
}
}
The editXml.sh is in my local, but the code doesn't work when I run app in Android studio.(Works on local) Should I put my script in the app? And which part of the app? Any suggestion?
Try this. I've tested this code and it works.
Let's you script named script.sh.
Put file script.sh to you project's /res/raw folder.
Use code below.
Build apk. Unpack apk (this is usual zip-archive) and make sure file /res/raw/script.sh exists there.
Install apk on device and start it.
public static void executeCommandAndGetOutput(String command){
BufferedReader reader = null;
String result = "";
try {
Process p = Runtime.getRuntime().exec(command);
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null){
result += line + "\n";
}
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(reader != null)
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Log.i("Test", result);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String pathToScript = getDir("my_scripts", 0).getAbsolutePath() + File.separator + "script.sh";
// Unpacking script to local filesystem
InputStream in = getResources().openRawResource(R.raw.script);
FileOutputStream out = null;
try {
out = new FileOutputStream(pathToScript);
byte[] buff = new byte[1024];
int read = 0;
while ((read = in.read(buff)) > 0) {
out.write(buff, 0, read);
}
}
catch(Exception e){
}
finally {
try {
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// Make script executable
executeCommand("chmod 775 " + pathToScript);
// Execute script
executeCommand("sh " + pathToScript);
}
public static String getSystemCommandOutput(String command){
BufferedReader reader = null;
String result = "";
try {
Process p = Runtime.getRuntime().exec(command);
reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null){
result += line + "\n";
}
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeQuietly(reader);
}
return result;
}
You can put script at raw resources and then unpack it to Context.getDir(...) folder and run from there with absolute path.
Also you need to run "chmod 775" (chmod +x) for this file before executing.
Example about copying a file from raw: Copying raw file into SDCard? You can copy to app folder (Context.getDir(...)) instead of sdcard
console output:
58:07.979 8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ onCreate
12:58:08.234 8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ PATH: /data/data/cc.softwarefactory.lokki.android/app_my_scripts/editxml.sh
12:58:08.258 8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ result:
12:58:08.287 8935-8935/cc.softwarefactory.lokki.android E/MainActivity﹕ result: not found
I changed
Log.i("Test", result) to Log.e(TAG,"result: " + result);
I am trying to develop a function for editing a value in the root file p2p_supplicant.conf which is located on /root/data/misc/wifi/p2p_supplicant.conf
The toast message always showing "File Not Found"
my code is:
private static final String FILE_PATH = "/root/data/misc/wifi/p2p_supplicant.conf";
private static final String MARKER_LINE = "p2p_oper_channel=";
private static final String TEXT_TO_ADD = "11";
public void changeConfig() {
String message = String.format("Entering Config Class");
Toast.makeText(getApplicationContext(), message,Toast.LENGTH_LONG).show();
List<String> fileLines = new ArrayList<String>();
Scanner scanner = null;
try {
scanner = new Scanner(new File(FILE_PATH));
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
fileLines.add(line);
if (line.trim().equalsIgnoreCase(MARKER_LINE)) {
fileLines.add(TEXT_TO_ADD);
String message2 = String.format("File Written");
Toast.makeText(getApplicationContext(), message2,Toast.LENGTH_LONG).show();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
String message1 = String.format("File Not found");
Toast.makeText(getApplicationContext(), message1,Toast.LENGTH_LONG).show();
} finally {
if (scanner != null) {
scanner.close();
}
}
PrintWriter pw = null;
try {
pw = new PrintWriter(new File(FILE_PATH));
for (String line : fileLines) {
pw.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
}
}
But the code did not find the location/path of the file. Please suggest.
N.B. My phone is rooted.
Basically, you are reading the file, changing the channel then rewriting the whole file. I am looking for a solution where you read the file first, edit it then write it back. Once I resolve that issue I will edit my answer here.
Note before testing it, make a backup file for your wpa_supplicant.conf file in case errors happen.
Step 1: reading the file = check this solution: Executing a Process in Android to read a file
Step 2: looping over the String containing the text of the file and changing the operating channel and saving the the whole text in String text
Step 3: writing text into the the file
Process p;
try {
// Preform su to get root privileges
p = Runtime.getRuntime().exec("su");
// Attempt to write a file to a root-only
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("echo \""+text+"\" > /data/misc/wifi/p2p_supplicant.conf\n");
// Close the terminal
os.writeBytes("exit\n");
os.flush();
try {
p.waitFor();
if (p.exitValue() != 255) {
// TODO Code to run on success
}
else {
// TODO Code to run on unsuccessful
}
} catch (InterruptedException e) {
// TODO Code to run in interrupted exception
}
} catch (IOException e) {
// TODO Code to run in input/output exception
}
I have set up my app to execute the su command using this code:
try {
Runtime.getRuntime().exec("su");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
altDialog.setTitle("No Root");
altDialog
.setMessage("I am afraid I have been unable to execute the su binary. Please check your root status.");
altDialog.setCancelable(false);
altDialog.setButton("Exit App",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
Log.e("Android .img Flasher",
"Exiting due to root error");
finish();
}
});
}
This catches if the su command doesn't exist (I believe), but not if root was actually granted.
How would I be able to check if root was actually granted?
On a side note, how would I be able to store the output of a command using the Runtime.getRuntime.exec() command?
You can use the code bellow. I've wrote it for generic command use, but it works with su command as well. It returns if the command succeed as well as the command output (or error).
public static boolean execCmd(String command, ArrayList<String> results){
Process process;
try {
process = Runtime.getRuntime().exec(new String [] {"sh", "-c", command});
} catch (IOException e) {
e.printStackTrace();
return false;
}
int result;
try {
result = process.waitFor();
} catch (InterruptedException e1) {
e1.printStackTrace();
return false;
}
if(result != 0){ //error executing command
Log.d("execCmd", "result code : " + result);
String line;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
try {
while ((line = bufferedReader.readLine()) != null){
if(results != null) results.add(line);
Log.d("execCmd", "Error: " + line);
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return false;
}
//Command execution is OK
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
try {
while ((line = bufferedReader.readLine()) != null){
if(results != null) results.add(line);
Log.d("execCmd", line);
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
You call it with two arguments:
command - string with command to execute
results - empty ArrayList to return the command output. If null, output is not returned.
To check sucommand you can do the following:
//Array list where the output will be returned
ArrayList<String> results = new ArrayList<String>();
//Command to be executed
String command = "su -c ls";
boolean result = execCmd(command,results);
//result returns command success
//results returns command output
Regards.
public static boolean isRootAvailable(){
Process p = null;
try{
p = Runtime.getRuntime().exec(new String[] {"su"});
writeCommandToConsole(p,"exit 0");
int result = p.waitFor();
if(result != 0)
throw new Exception("Root check result with exit command " + result);
return true;
} catch (IOException e) {
Log.e(LOG_TAG, "Su executable is not available ", e);
} catch (Exception e) {
Log.e(LOG_TAG, "Root is unavailable ", e);
}finally {
if(p != null)
p.destroy();
}
return false;
}
private static String writeCommandToConsole(Process proc, String command, boolean ignoreError) throws Exception{
byte[] tmpArray = new byte[1024];
proc.getOutputStream().write((command + "\n").getBytes());
proc.getOutputStream().flush();
int bytesRead = 0;
if(proc.getErrorStream().available() > 0){
if((bytesRead = proc.getErrorStream().read(tmpArray)) > 1){
Log.e(LOG_TAG,new String(tmpArray,0,bytesRead));
if(!ignoreError)
throw new Exception(new String(tmpArray,0,bytesRead));
}
}
if(proc.getInputStream().available() > 0){
bytesRead = proc.getInputStream().read(tmpArray);
Log.i(LOG_TAG, new String(tmpArray,0,bytesRead));
}
return new String(tmpArray);
}
I`am trying to download and install an apk from some link,
but for some reason i get an exception.
I have one method downloadfile() which downloading the file and a call
to and installFile() method, which supposed to install it in the device.
some code:
public void downloadFile()
{
String fileName = "someApplication.apk";
MsgProxyLogger.debug(TAG, "TAG:Starting to download");
try
{
URL u = new URL(
"http://10.122.233.22/test/someApplication.apk");
try
{
HttpURLConnection c = (HttpURLConnection) u.openConnection();
try
{
c.setRequestMethod("GET");
c.setDoOutput(true);
try
{
c.connect();
FileOutputStream f = context.openFileOutput(fileName,
context.MODE_WORLD_READABLE);
try
{
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
int totsize = 0;
try
{
while ((len1 = in.read(buffer)) > 0)
{
totsize += len1;
f.write(buffer, 0, len1);// .write(buffer);
}
} catch (IOException e)
{
e.printStackTrace();
}
f.close();
MsgProxyLogger.debug(TAG, TAG
+ ":Saved file with name: " + fileName);
InstallFile(fileName);
} catch (IOException e)
{
e.printStackTrace();
}
} catch (IOException e)
{
e.printStackTrace();
}
} catch (ProtocolException e)
{
e.printStackTrace();
}
} catch (IOException e)
{
e.printStackTrace();
}
} catch (MalformedURLException e)
{
e.printStackTrace();
}
}
and this is the install file method:
private void InstallFile(String fileName)
{
MsgProxyLogger.debug(TAG, TAG + ":Installing file " + fileName);
String src = String.format(
"file:///data/data/com.test/files/",
fileName);
Uri mPackageURI = Uri.parse(src);
PackageManager pm = context.getPackageManager();
int installFlags = 0;
try
{
PackageInfo pi = pm.getPackageInfo("com.mirs.agentcore.msgproxy",
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi != null)
{
MsgProxyLogger.debug(TAG, TAG + ":replacing " + fileName);
installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
}
} catch (NameNotFoundException e)
{
}
try
{
// PackageInstallObserver observer = new PackageInstallObserver();
pm.installPackage(mPackageURI);
} catch (SecurityException e)
{
//!!!!!!!!!!!!!here i get an security exception!!!!!!!!!!!
MsgProxyLogger.debug(TAG, TAG + ":not permission? " + fileName);
}
this is the exception details:
"Neither user 10057 nor current process has android.permission.INSTALL_PACKAGES".
and i have set in my main app that permission in the manifest.
anyone has any idea?
thanks,
ray.
You cannot install APKs that way -- only applications that are part of the system firmware can do that.
You should be able to use an ACTION_VIEW Intent, with a MIME type of application/vnd.android.package-archive and a Uri pointing to your file. Note that this may not work on devices that do not have "allow non-Market installs" checked.
You need add that permission to manifest
http://developer.android.com/reference/android/Manifest.permission.html