在程式中執行cmd & AT command

在程式中難免會遇到需執行指令的時後,根據目前遇過的寫法,以下分別整理如何使用java, c++來執行指令。

import java.lang.Process;

String cmd = "ls";

Process process = Runtime.getRuntime.exec(cmd);//執行cmd

或使用ProcessBuilder,會較簡潔,

Process process = new ProcessBuilder("指令的絕對路徑","參數1","參數2",...,"參數n").start(); 
//For example
Process process = new ProcessBuilder("/system/bin/logcat","-b","radio","-t","10").start(); 

此外,若要接這個指令的error,ProcessBuilder的很簡單,只要加上.redirectErrorStream(true)即可。如

Process process = new ProcessBuilder("/system/bin/logcat","-b","radio","-t","10") 
.redirectErrorStream(true).start();|

另一種方法則是用process.getErrorStream()

InputStream stderr = process.getErrorStream();  
InputStreamReader esr = new InputStreamReader (stderr);  
  
//再用BufferReader 把他讀出來  
BufferReader errReader = new BufferReader (esr);  
String line;  

while(line =errReader.readLine() != null)//將err結果一行行的讀出來

    System.out.println(line);          

如需要取得執行結果,可用process.getInputStream():

import java.io.*;

DataInputStream stdout = new DataInputStream(process.getInputStream());

while(line = stdout.readLine() != null){//將程式執行結果一行行的讀出來
    //做相應處理
}

例如可以將執行結果讀出來後,找尋特定keyword,把要的結果組起來放在StringBuffer裡面。

StringBuffer output = new StringBuffer();

while(line = stdout.readLine() != null){

     if(line.contains("someWords"))

     output.append(line).append('\n');

}

C++

目前我使用過的方式是用logwrap來做,

首先, 為了不要讓c++把logwrap做mangleing,所以要用extern "C",亦即:

extern "C" logwrap(int argc, const char **argv, int background);|

從上面就知道函數需要傳入什麼參數,直接用例子來解釋會比較清楚,

static char  FSCK_PATH[] = "system/bin/ntfs-3g";  
int rc = 0;  
//注意: 指令只要中間有空格隔開,就得放一個element  
const char *args[4];  
arg[0] = FSCK_PATH   

arg[1] = "--readwrite"

arg[2] = fspath

rc = logwrap(3, args, 1);//rc接回傳值,接著可從指令的回傳值來做相應的動作,例如使用switch case,但前提是要先知道回傳值的義意,可用man指令來查 

此外,可以在執行logwrap之前,用access先做path的check

access(FSCK_PATH, X_OK);//可以打開會回傳0

不過有其他種寫法,可參考http://topic.csdn.net/u/20081023/23/f34de986-f666-4f83-af56-434327f643c5.html

AT_Command

AT Command主要是對模組下的特定command,例如3g, bluetooth都會用到。因此他必需指定指令要下到的device,以3g為例,可以是下在/dev/ttyUSB0或USB2,看要求。

BufferWriter out = new BufferWriter(new FileWriter("/dev/ttyUSB2");  
out.write("AT^COMMAND?\r");  
out.close();

然後用adb logcat -b radio就可以看到這個command有沒有下成功了!有成功的話會顯示OK

AIDL

AIDL

使用時機: 在不同的thread要進行IPC時, 比如在不用的app底下,想取得在別的process執行的service

但其他情況:

在同一個app中做IPC,則使用binder即可。

若一個service,不需要用multi-threading處理事情時,就選用Messenger來實作介面。

使用AIDL的介面,主要有3個步驟:

1.建立.aidl 檔案(ex. IBluetoothHeadset.aidl),然後經過aidl.exe會產出java檔案

2.實作介面(aidl file中所定義的methods)(ex. BluetoothHeadset.java)

3.Expose the interface to clients

繼承Service,並實作onBind()

但在BluetoothService的實際作法是BluetoothService extends IBluetooth.Stub

就可把BluetoothService變成「Remotable Object」(即BpBinder),(而用binder的話,寫法是直接extends Binder)

一旦成為Remotable Object,就可讓有實作binder的Remote Object與它作IPC的溝通。

以下是取得service的source code,

IBinder mBinder = ServiceManager.getService(name);  
IXXXService service = IXXX.Stub.asInsterface(mBinder);//若是在非同一個process呼叫,才會return remote boject(BpBinder), 否則會return native binder, 即BnBinder  

使用IBluetooth.Stub.asInsterface(mBinder)可取得BluetoothService的分身(proxy object),其實就是透過這個proxy object與remote object溝通。而service是呼叫ServiceManager.getService(name),由ServiceManager,在存放服務與IBinder的HashMap中,以name去找到該service的IBinder,再回傳。以bluetooth為例,即為ServiceManager.getService(“bluetooth”);

而再深入去看,發現asInsterface()中,由IBluetooth.Stub.Proxy()去取得proxy object。

public static android.bluetooth.IBluetooth asInterface(IBinder obj) {  
…  
return new IBluetooth.Stub.Proxy(obj);  
}