一、Android應用啟動服務執行指令碼1 如何寫服務和指令碼在android源碼根目錄下有/device/tegatech/tegav2/init.rc檔案相信大家對這個檔案都不陌生(如果不明白就仔細研讀下android啟動流程)。如果在該指令檔中添加諸如以下服務:
service usblp_test /data/setip/init.usblpmod.sh
oneshot
disabled
註解:每個裝置下都會有自己對應的init.rc,init.裝置名稱.rc指令檔。oneshot disabled向我們說明了在系統啟動的時候這個服務是不會自動啟動的。並且該服務的目的是執行/data/setip/init.usblpmod.sh指令碼。指令碼的內容你可以隨便寫,只要符合shell文法就可以了,比如指令碼可以是簡單的設定eth0:
# ! /system/bin/sh //指令碼的開頭必須這樣寫。
Ifconfig eth0 172.16.100.206 netmask 255.255.0.0 up//設定ip的命令
2、如何在應用中啟動服務
1)首先瞭解下在服務啟動的流程
1. 在你的應用中讓init.rc中添加的服務啟動起來。
首先瞭解下在服務啟動的流程:
在裝置目錄下的init.c(切記並不是system/core/init/init.rc)
Main函數的for(;;)迴圈中有一個handle_property_set_fd(),函數:
for (i = 0; i < fd_count; i++) { if (ufds[i].revents == POLLIN) { if (ufds[i].fd == get_property_set_fd()) handle_property_set_fd(); else if (ufds[i].fd == get_keychord_fd()) handle_keychord(); else if (ufds[i].fd == get_signal_fd()) handle_signal(); } }
這個函數的實現也在system/core/init目錄下,該函數中的check_control_perms(msg.value, cr.uid, cr.gid)函數就是檢查該uid是否有許可權啟動服務(msg.value就是你服務的名字),如果應用為root或system使用者則直接返回1.之後就是調用handle_control_message((char*)
msg.name + 4, (char*) msg.value),該函數的參數就是去掉1.ctl.後的start和2.你服務的名字。這個函數的詳細內容:
void handle_control_message(const char *msg, const char *arg){ if (!strcmp(msg,"start")) { msg_start(arg); } else if (!strcmp(msg,"stop")) { msg_stop(arg); } else if (!strcmp(msg,"restart")) { msg_stop(arg); msg_start(arg); } else { ERROR("unknown control msg '%s'\n", msg); }}
匹配start後調用msg_start.服務就這樣起來了,我們的解決方案就是在檢查許可權的地方“下點功夫”,因為我們不確定uid,所以就讓check_control_perms這個函數不要檢查我們的uid,直接檢查我們服務的名字,看看這個函數:
static int check_control_perms(const char *name, unsigned int uid, unsigned int gid) { int i; if (uid == AID_SYSTEM || uid == AID_ROOT) return 1; /* Search the ACL */ for (i = 0; control_perms[i].service; i++) { if (strcmp(control_perms[i].service, name) == 0) { if ((uid && control_perms[i].uid == uid) || (gid && control_perms[i].gid == gid)) { return 1; } } } return 0;}
這個函數裡面是必須要檢查uid的,我們只要在for迴圈上寫上。
if(strcmp(“usblp_test”,name)==0) //usblp_test就是我們服務的名字。
return 1;
這樣做不會破壞android原本的結構,不會有什麼副作用。
init.c和init.rc都改好了,現在就可以編譯源碼了,編譯好了裝到機子開發板上就可以了。
2、在應用中啟動服務
在應用程式中調用:do_exec(start usblp_test);
do_exec的實現如下:
private String do_exec(String cmd) { String s = "/n"; try { Process p = Runtime.getRuntime().exec(cmd); BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); String line = null; while ((line = in.readLine()) != null) { s += line + "/n"; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } text.setText(s); return cmd; }
應用原始碼:http://download.csdn.net/detail/weijing331/4878065
二、編譯源碼執行shell指令碼
這個方法很簡單,指令碼已經寫好了,現在要解決的問題是在什麼時候怎麼執行這個指令碼,經過驗證最佳的位置在system/core/init/init.c,main函數中的如下位置,
queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
#if BOOTCHART
queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
/*add by weijing */
system("exec /system/bin/sh /data/setip/init.djstava.sh");
/*end by weijing */
for(;;) {