因为项目需求需要在android的应用程序中去动态的执行预先放入手机中的一个程序,所以到处找了很多资料。虽然网上各种各样的东西不少,不过感觉多多少少都有点不够,折腾了半天之后终于满意了,记录整个过程。
要想执行su
指令必须要求手机root。
相关的类
- Process
- Runtime
测试工程代码
代码功能
获取su权限,执行命令 “ls /data/data”(需要root才能访问/data/data)
MainActivity.java
import android.app.Activity;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MainActivity extends Activity {
private final static String[] ARGS={"ls","-l"};
private final static String TAG="com.dd.test";
Button mButton,rButton,cButton;
TextView myTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton= (Button) findViewById(R.id.myButton);
cButton = (Button) findViewById(R.id.clearB);
myTextView= (TextView) findViewById(R.id.textView);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myTextView.setText(getResult());
}
});
cButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myTextView.setText("hello world");
}
});
}
public String getResult(){
ShellExecute cmdexe=new ShellExecute();
String result="";
try{
result=cmdexe.execute(ARGS,"/data/data/");
}catch (Exception e){
Log.e(TAG,"IOEXCEPTION");
e.printStackTrace();
}
return result;
}
private class ShellExecute{
public String execute (String[] command,String directory) throws IOException{
String result="";
String[] suC={"su"};
try{
ProcessBuilder builder= new ProcessBuilder(suC);
if (directory!=null)
builder.directory(new File(directory));
builder.redirectErrorStream(true);
Process process=builder.start();
DataOutputStream os;
os=new DataOutputStream(process.getOutputStream());
InputStream is= process.getInputStream();
os.writeBytes( "ls\n");
os.flush();
os.close();
byte[] buffer=new byte[1024];
while (is.read(buffer)!=-1){
result=result+new String(buffer);
}
is.close();
}catch (Exception e){
e.printStackTrace();
}
return result;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click"
android:id="@+id/myButton"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="clear"
android:id="@+id/clearB"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text..."
android:id="@+id/textView"
/>
</LinearLayout>
</RelativeLayout>
代码解释说明
布局文件就不多赘述了,很简单的一个布局
核心代码其实是
private class ShellExecute{
public String execute (String[] command,String directory) throws IOException{
String result="";
String[] suC={"su"};
try{
ProcessBuilder builder= new ProcessBuilder(suC);
if (directory!=null)
builder.directory(new File(directory));
builder.redirectErrorStream(true);
Process process=builder.start();
DataOutputStream os;
os=new DataOutputStream(process.getOutputStream());
InputStream is= process.getInputStream();
os.writeBytes( "ls\n");
os.flush();
os.close();
byte[] buffer=new byte[1024];
while (is.read(buffer)!=-1){
result=result+new String(buffer);
}
is.close();
}catch (Exception e){
e.printStackTrace();
}
return result;
}
}
这里先是将su
这条指令作为参数传入ProcessBuilder,然后调用它的start()
方法,获取到一个process。
这里,其实已经相当于在adb shell中执行了一条su
的指令了。
在实际的应用运行的过程中,会提示“应用程序需要获取root权限”。
接下来比较重要的是DataOutputStream
和 InputStream
在android文档中写的
InputStream
public abstract InputStream getInputStream ()
Returns an input stream that is connected to the standard output stream (stdout) of the native process represented by this object.
Returns
the input stream to read from the output stream associated with the native process.DataOutputStream
public abstract OutputStream getOutputStream ()
Returns an output stream that is connected to the standard input stream (stdin) of the native process represented by this object.
Returns
the output stream to write to the input stream associated with the native process.
可见,说直白点就是获取了一个shell的stdin和stdout,所以我们直接进行读写就相当于在shell中输入相关的命令并且获取对于的输出结果了。
一些参考文章
以下是一部分在网上查资料时看到的,权当记录
http://www.android-doc.com/reference/java/lang/Process.html
http://www.cnblogs.com/ycmoon/archive/2011/05/11/2042999.html?login=1
http://blog.csdn.net/y13872888163/article/details/6530430
http://www.open-open.com/lib/view/open1409190296025.html