作者 : 萬境絕塵
轉載請著名出處 : http://blog.csdn.net/shulianghan/article/details/36438365
示例代碼下載下傳 :
-- CSDN : http://download.csdn.net/detail/han1202012/7639253;
-- GitHub : https://github.com/han1202012/TracerouteAndBusybox ;
1. 原理思路
檔案權限修改無法實作 : 如果 沒有 root 權限, 就不能改變二進制檔案的檔案權限;
-- 将busybox推送到Android系統中 : 使用 adb push 指令, 将 busybox 傳入到 sd 卡中, 注意, 上傳到記憶體中無法實作;
-- 上傳到sd卡成功 : 使用 adb push 檔案名 手機中的檔案全路徑名 指令;
[email protected]:~/csdn$ adb push busybox-armv7l /sdcard/octopus/busybox
3256 KB/s (1109128 bytes in 0.332s)
-- 上傳到記憶體失敗 : 使用 adb push 上傳到記憶體中失敗, 因為 adb 使用的是 system 使用者, 隻有 root 使用者才有權限向記憶體中寫入資料;
[email protected]:~/csdn$ adb push busybox-armv7l /data/busybox
failed to copy 'busybox-armv7l' to '/data/busybox': Permission denied
-- 檢視并修改busybox權限失敗 : system 使用者沒有修改 sd 卡檔案模式的權限;
[email protected]:/sdcard/octopus $ ll
-rw-rw-r-- root sdcard_rw 1109128 2014-07-08 19:49 busybox
[email protected]:/sdcard/octopus $ chmod 755 busybox
Unable to chmod busybox: Operation not permitted
應用程式解決方案 :
-- 應用程式專屬使用者 : Android 作業系統會為每個應用程式設定一個使用者, 這個使用者對其安裝目錄(/data/data/包名/)下的檔案有完整的權限;
-- 将可執行二進制檔案拷貝到安裝目錄中 : 将交叉編譯好的 busybox 放到 工程目錄下的 res/assets/ 目錄下;
2. 實作政策
檔案初始放置 : 将 交叉編譯好的 busybox 檔案放在 工程目錄的 /res/assets/ 目錄下;
檔案拷貝 : 将該 二進制檔案 拷貝到 app 的安裝目錄的 files 目錄下, 即 /data/data/包名/files/下;
修改檔案權限 : 使用指令可以直接修改該目錄下的權限, 注意這個操作是可以執行的;
執行busybox : 在代碼中執行 ./data/data/包名/files/busybox ;
擷取執行結果 :
3. 使用到的api解析
(1) 擷取 assets 目錄檔案的輸入流
InputStream is = context.getAssets().open(source);
-- 擷取AssetsManager : 調用 Context 上下文對象的 context.getAssets() 即可擷取 AssetsManager對象;
-- 擷取輸入流 : 調用 AssetsManager 的 open(String fileName) 即可擷取對應檔案名的輸入流;
(2) 檔案流相關操作
根據輸入流擷取檔案大小 : 調用輸入流的 inputStream.available() 方法;
int size = is.available();
将檔案讀取到緩沖區中 : 建立一個與檔案大小相同的位元組數組緩沖區, 輸入流将資料存放到緩沖區中;
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
将檔案寫到記憶體中 : 調用上下文對象的 openFileOutput(絕對路徑名, 權限), 即可建立一個檔案的輸出流;
FileOutputStream output = context.openFileOutput(destination, Context.MODE_PRIVATE);
output.write(buffer);
output.close();
(3) 擷取檔案的絕對路徑
擷取app絕對安裝路徑 : 調用 上下文對象的 getFilesDir().getAbsolutePath() 方法;
String filesPath = context.getFilesDir().getAbsolutePath();
(4) 執行二進制檔案
建立 Process 對象, 并使用該 process 執行shell腳本指令 :
Runtime runtime = Runtime.getRuntime();
process = runtime.exec(cmd);
擷取執行的指令行結果 :
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = br.readLine()) != null) {
processList.add(line);
}
br.close();
4. 代碼示例
MainActivity 主程式代碼 :
package cn.org.octopus.tracerouteandbusybox;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
/** 看不懂注釋我就吃半斤狗糧 :-) */
public class MainActivity extends ActionBarActivity {
private EditText et_cmd;
private String app_path;
private TextView tv_result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
/*初始化控件*/
et_cmd = (EditText) findViewById(R.id.et_cmd);
tv_result = (TextView) findViewById(R.id.tv_result);
/* 擷取app安裝路徑 */
app_path = getApplicationContext().getFilesDir().getAbsolutePath();
}
/** 按鈕點選事件 */
public void onClick(View view) {
int id = view.getId();
switch (id) {
case R.id.copy_busybox: /* 拷貝busybox可執行檔案 */
varifyFile(getApplicationContext(), "busybox");
break;
case R.id.copy_traceroute:/* 拷貝traceroute可執行檔案 */
varifyFile(getApplicationContext(), "traceroute");
break;
case R.id.exe_busybox:/* 将busybox指令添加到Editext中 */
String cmd = "." + app_path + "/busybox";
System.out.println(et_cmd);
et_cmd.setText(cmd);
break;
case R.id.exe_traceroute:/* 将traceroute指令添加到Editext中 */
cmd = "." + app_path + "/traceroute 8.8.8.8";
et_cmd.setText(cmd);
break;
case R.id.exe: /* 執行Editext中的指令 */
cmd = et_cmd.getText().toString();
/* 執行腳本指令 */
List<String> results = exe(cmd);
String result = "";
/* 将結果轉換成字元串, 輸出到 TextView中 */
for(String line : results){
result += line + "\n";
}
tv_result.setText(result);
break;
default:
break;
}
}
/** 驗證檔案是否存在, 如果不存在就拷貝 */
private void varifyFile(Context context, String fileName) {
try {
/* 檢視檔案是否存在, 如果不存在就會走異常中的代碼 */
context.openFileInput(fileName);
} catch (FileNotFoundException notfoundE) {
try {
/* 拷貝檔案到app安裝目錄的files目錄下 */
copyFromAssets(context, fileName, fileName);
/* 修改檔案權限腳本 */
String script = "chmod 700 " + app_path + "/" + fileName;
/* 執行腳本 */
exe(script);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** 将檔案從assets目錄中拷貝到app安裝目錄的files目錄下 */
private void copyFromAssets(Context context, String source,
String destination) throws IOException {
/* 擷取assets目錄下檔案的輸入流 */
InputStream is = context.getAssets().open(source);
/* 擷取檔案大小 */
int size = is.available();
/* 建立檔案的緩沖區 */
byte[] buffer = new byte[size];
/* 将檔案讀取到緩沖區中 */
is.read(buffer);
/* 關閉輸入流 */
is.close();
/* 打開app安裝目錄檔案的輸出流 */
FileOutputStream output = context.openFileOutput(destination,
Context.MODE_PRIVATE);
/* 将檔案從緩沖區中寫出到記憶體中 */
output.write(buffer);
/* 關閉輸出流 */
output.close();
}
/** 執行 shell 腳本指令 */
private List<String> exe(String cmd) {
/* 擷取執行工具 */
Process process = null;
/* 存放腳本執行結果 */
List<String> list = new ArrayList<String>();
try {
/* 擷取運作時環境 */
Runtime runtime = Runtime.getRuntime();
/* 執行腳本 */
process = runtime.exec(cmd);
/* 擷取腳本結果的輸入流 */
InputStream is = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
/* 逐行讀取腳本執行結果 */
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
}
home_activity.xml 布局檔案代碼 :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/copy_busybox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="拷貝busybox"
android:textSize="7dp"
android:textStyle="bold" />
<Button
android:id="@+id/copy_traceroute"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="拷貝traceroute"
android:textSize="7dp"
android:textStyle="bold" />
<Button
android:id="@+id/exe_busybox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="執行busybox"
android:textSize="7dp"
android:textStyle="bold" />
<Button
android:id="@+id/exe_traceroute"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="執行traceroute"
android:textSize="7dp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/et_cmd"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:hint="輸入要執行的指令"
android:textStyle="bold" />
<Button
android:id="@+id/exe"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="執行"
android:textSize="10dp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:textColor="#FFF"
android:textSize="10dp"
android:textStyle="bold" />
</LinearLayout>
5. 執行結果
執行 busybox 程式 :
執行 traceroute 程式 :
示例代碼下載下傳 :
-- CSDN : http://download.csdn.net/detail/han1202012/7639253;
-- GitHub : https://github.com/han1202012/TracerouteAndBusybox ;
作者 : 萬境絕塵
轉載請著名出處 : http://blog.csdn.net/shulianghan/article/details/36438365