本篇文章針對(duì)向ServiceManager注冊(cè)服務(wù) 和 獲取服務(wù)兩個(gè)流程來(lái)做總結(jié)。在這兩個(gè)過(guò)程中,ServiceManager都扮演的是服務(wù)端,與客戶端之間的通信也是通過(guò)Binder IPC。

我們提供的服務(wù)有:成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、外貿(mào)網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、華寧ssl等。為成百上千企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的華寧網(wǎng)站制作公司
在此之前先了解下Binder的進(jìn)程與線程的關(guān)系:
用戶空間 :ProcessState描述一個(gè)進(jìn)程,IPCThreadState對(duì)應(yīng)一個(gè)進(jìn)程中的一個(gè)線程。
內(nèi)核空間 :binder_proc描述一個(gè)進(jìn)程,統(tǒng)一由binder_procs全局鏈表保存,binder_thread對(duì)應(yīng)進(jìn)程的一個(gè)線程。
ProcessState與binder_proc是一一對(duì)應(yīng)的。
Binder線程池 :每個(gè)Server進(jìn)程在啟動(dòng)時(shí)會(huì)創(chuàng)建一個(gè)binder線程池,并向其中注冊(cè)一個(gè)Binder線程;之后Server進(jìn)程也可以向binder線程池注冊(cè)新的線程,或者Binder驅(qū)動(dòng)在探測(cè)到?jīng)]有空閑binder線程時(shí)會(huì)主動(dòng)向Server進(jìn)程注冊(cè)新的的binder線程。對(duì)于一個(gè)Server進(jìn)程有一個(gè)最大Binder線程數(shù)限制15,(#define DEFAULT_MAX_BINDER_THREADS 15)。對(duì)于所有Client端進(jìn)程的binder請(qǐng)求都是交由Server端進(jìn)程的binder線程來(lái)處理的。我的理解是:binder線程是進(jìn)程進(jìn)行binder ipc時(shí)的一條數(shù)據(jù)處理路徑。
MediaPlayerService向ServiceManager注冊(cè)過(guò)程如下:
相關(guān)類:
整個(gè)過(guò)程總結(jié)如下:
1 獲取BpServiceManager 與 BpBinder
由defaultServiceManager()返回的是BpServiceManager,同時(shí)會(huì)創(chuàng)建ProcessState對(duì)象和BpBinder對(duì)象。然后通過(guò)BpBinder執(zhí)行transact,把真正工作交給IPCThreadState來(lái)處理。
2 BpBinder transact
Binder代理類調(diào)用transact()方法,真正工作還是交給IPCThreadState來(lái)進(jìn)行transact工作。
3 通過(guò)IPCThreadState 包裝并轉(zhuǎn)換數(shù)據(jù)并進(jìn)行transact事務(wù)處理
每個(gè)線程都有一個(gè)IPCThreadState,每個(gè)IPCThreadState中都有一對(duì)Parcel變量:mIn、mOut。相當(dāng)于兩根數(shù)據(jù)管道:
最后執(zhí)行talkWithDriver。
writeTransactionData:將BC Protocol + binder_transaction_data結(jié)構(gòu)體 寫入mOut, 然后執(zhí)行waitForResponse:
由talkWithDriver將數(shù)據(jù)進(jìn)一步封裝到binder_write_read結(jié)構(gòu)體,通過(guò)ioctl(BINDER_WRITE_READ)與驅(qū)動(dòng)通信。同時(shí)等待驅(qū)動(dòng)返回的接收BR命令,從mIn取出返回的數(shù)據(jù)。
mIn包裝的數(shù)據(jù)結(jié)構(gòu)(注冊(cè)服務(wù)handle = 0 ,code 為ADD_SERVICE_TRANSACTION):
4 Binder Driver
把binder_write_read結(jié)構(gòu)體write_buffer里數(shù)據(jù)取出來(lái),分別得到BC命令和封裝好數(shù)據(jù)的事務(wù)binder_transaction_data, 然后根據(jù)handler,在當(dāng)前binder_proc中,找到相應(yīng)的binder_ref,由binder_ref再找到目標(biāo)binder_node實(shí)體,由目標(biāo)binder_node再找到目標(biāo)進(jìn)程binder_proc。然后就是插入數(shù)據(jù):當(dāng)binder驅(qū)動(dòng)可以找到合適的線程,就會(huì)把binder_transaction節(jié)點(diǎn)插入到servciemanager的線程的todo隊(duì)列中,如果找不到合適的線程,就把節(jié)點(diǎn)之間插入servciemanager的binder_proc的todo隊(duì)列。
5 ServiceManager
經(jīng)過(guò)Binder Driver的處理,數(shù)據(jù)已經(jīng)到了ServiceManager進(jìn)程,在BR_TRANSACTION的引導(dǎo)下,在binder_loop()中執(zhí)行binder_parser()取出數(shù)據(jù),執(zhí)行do_add_service()操作,最終向 svcinfo 列表中添加已經(jīng)注冊(cè)的服務(wù)(沒(méi)有數(shù)據(jù)的返回)。最后發(fā)送 BR_REPLY 命令喚醒等待的線程,通知注冊(cè)成功。結(jié)束MediaPlayerService進(jìn)程 waitForResponse()的狀態(tài),整個(gè)注冊(cè)過(guò)程結(jié)束。
獲取服務(wù)的過(guò)程與注冊(cè)類似,首先 ServiceManager 向 Binder 驅(qū)動(dòng)發(fā)送 BC_TRANSACTION 命令攜帶 CHECK_SERVICE_TRANSACTION 命令,同時(shí)獲取服務(wù)的線程進(jìn)入等待狀態(tài) waitForResponse()。Binder 驅(qū)動(dòng)收到請(qǐng)求命令向 ServiceManager 的發(fā)送 BC_TRANSACTION 查詢已注冊(cè)的服務(wù),會(huì)區(qū)分請(qǐng)求服務(wù)所屬進(jìn)程情況。
查詢到直接響應(yīng) BR_REPLY 喚醒等待的線程。若查詢不到將與 binder_procs 鏈表中的服務(wù)進(jìn)行一次通訊再響應(yīng)。
以startService為例來(lái)簡(jiǎn)單總結(jié)下執(zhí)行流程:
3.1 從方法執(zhí)行流程來(lái)看:
Client :
1 AMP.startService 標(biāo)記方法以及通過(guò)Parcel包裝數(shù)據(jù);
2 BinderProxy.transact 實(shí)際調(diào)用native的 android_os_BinderProxy_transact 傳遞數(shù)據(jù);
3 獲取BpServiceManager 與 BpBinder 同時(shí)會(huì)創(chuàng)建ProcessState。然后通過(guò)BpBinder執(zhí)行transact,把真正工作交給IPCThreadState來(lái)處理;
4 IPC.transact 主要執(zhí)行writeTransactionData,將上層傳來(lái)的數(shù)據(jù)重新包裝成binder_transaction_data,并將BC Protocol + binder_transaction_data結(jié)構(gòu)體 寫入mOut;
5 IPC waitForResponse talkWithDriver + 等待返回?cái)?shù)據(jù);
6 talkWithDriver 將數(shù)據(jù)進(jìn)一步封裝成binder_write_read,通過(guò)ioctl(BINDER_WRITE_READ)與驅(qū)動(dòng)通信;
Kernel :
7 binder ioctl 接收BINDER_WRITE_READ ioctl命令;
8 binder_ioctl_write_read 把用戶空間數(shù)據(jù)ubuf拷貝到內(nèi)核空間bwr;
9 binder_thread_write 當(dāng)bwr寫緩存有數(shù)據(jù),則執(zhí)行binder_thread_write;當(dāng)寫失敗則將bwr數(shù)據(jù)寫回用戶空間并退出;
10 binder_transaction 找到目標(biāo)進(jìn)程binder_proc并插入數(shù)據(jù)到目標(biāo)進(jìn)程的線程todo隊(duì)列,最終執(zhí)行到它
時(shí),將發(fā)起端數(shù)據(jù)拷貝到接收端進(jìn)程的buffer結(jié)構(gòu)體;
11 binder_thread_read 根據(jù)binder_transaction結(jié)構(gòu)體和binder_buffer結(jié)構(gòu)體數(shù)據(jù)生成新的binder_transaction_data結(jié)構(gòu)體,寫入bwr的read_buffer,當(dāng)bwr讀緩存有數(shù)據(jù),則執(zhí)行binder_thread_read;當(dāng)讀失敗則再將bwr數(shù)據(jù)寫回用戶空間并退出;最后,把內(nèi)核數(shù)據(jù)bwr拷貝到用戶空間ubuf。
12 binder_thread_write + binder_ioctl BR命令和數(shù)據(jù)傳遞
Server:
13 IPC.executeCommand 解析kernel傳過(guò)來(lái)的binder_transaction_data數(shù)據(jù),找到目標(biāo)BBinder并調(diào)用其transact()方法;
14 IPC.joinThreadPool 采用循環(huán)不斷地執(zhí)行g(shù)etAndExecuteCommand()方法, 處理事務(wù)。當(dāng)bwr的讀寫buffer都沒(méi)有數(shù)據(jù)時(shí),則阻塞在binder_thread_read的wait_event過(guò)程. 另外,正常情況下binder線程一旦創(chuàng)建則不會(huì)退出.
15 BBinder.transact 到Binder.exeTransact 調(diào)用 AMN.onTransact
16 AMN.onTransact 把數(shù)據(jù)傳遞到AMS.starService去執(zhí)行
17 AMS.starService Server處理了Client的請(qǐng)求了
然后原路replay回去,talkWithDriver 到Kernel ,然后找到Client進(jìn)程,把數(shù)據(jù)拷貝到read_buffer里,最終喚醒IPC,把反饋傳遞回AMP.startService。完成啟動(dòng)服務(wù)。
3.2 從通信協(xié)議流程來(lái)看:
非oneWay:
oneway:
oneway與非oneway區(qū)別: 都是需要等待Binder Driver的回應(yīng)消息BR_TRANSACTION_COMPLETE. 主要區(qū)別在于oneway的通信收到BR_TRANSACTION_COMPLETE則返回,而不會(huì)再等待BR_REPLY消息的到來(lái). 另外,oneway的binder IPC則接收端無(wú)法獲取對(duì)方的pid.
3.3 從數(shù)據(jù)流來(lái)看
從用戶空間開(kāi)始:
進(jìn)入驅(qū)動(dòng)后:
回到用戶空間:
參考:
在內(nèi)部存儲(chǔ)卡的的data/com.android.provides.contacts里面。
以三星的s8為例
找到通訊錄以及通話記錄方法:
1、打開(kāi)三星的s8手機(jī),在系統(tǒng)界面找到“我的文件”。
2、進(jìn)入到三星的s8手機(jī)“我的文件”里面找到“內(nèi)部存儲(chǔ)”點(diǎn)擊進(jìn)入。
3、進(jìn)入“內(nèi)部存儲(chǔ)”下翻,在列表中找到“data”文件夾,點(diǎn)擊打開(kāi)。
4、進(jìn)入“data”文件夾后找到“com.android.provides.contacts”文件夾,點(diǎn)擊打開(kāi)。
5、在“com.android.provides.contacts”文件夾里面,把CSV文件導(dǎo)出,就可以看到通訊錄文件了。
1.打開(kāi)串口。
2.串口處于監(jiān)聽(tīng)狀態(tài)
3.想串口寫入數(shù)據(jù),串口接收到數(shù)據(jù)返回?cái)?shù)據(jù)
SerialPort類所在的包一定要和上圖包名一直,因?yàn)榇谕ㄓ嵭枰褂胘ni中的函數(shù)。
package android_serialport_api;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import com.fx.serialporttest.L;
public class SerialPort {
/*
* Do not remove or rename the field mFd: it is used by native method
* close();
*/
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
/**
* 構(gòu)造方法
* @param device 串口地址
* @param baurate 波特率
* @param flags
* @throws IOException
* @throws InterruptedException
*/
public SerialPort(File device,int baudrate,int flags) {
/*
* 檢測(cè)是否有訪問(wèn)權(quán)限
*/
if(!device.canRead()||!device.canWrite()){
//如果沒(méi)有讀寫權(quán)限,嘗試chmod命令這個(gè)文件
L.tag("沒(méi)有讀寫權(quán)限");
Process su;
try {
su = Runtime.getRuntime().exec("/system/bin/su");//獲取root讀寫權(quán)限
String cmd = "chmod 777"+device.getAbsolutePath()+"\n"+"exit\n";
su.getOutputStream().write(cmd.getBytes()); //向此路徑文件寫入命令
if((su.waitFor()!=0||!device.canRead()||!device.canWrite())){
throw new SecurityException();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mFd = open(device.getAbsolutePath(),baudrate,flags);
if(mFd==null){
mFd = open(device.getAbsolutePath(),baudrate,flags);
L.tag("native open return null");
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
public FileInputStream getmFileInputStream() {
return mFileInputStream;
}
public void setmFileInputStream(FileInputStream mFileInputStream) {
this.mFileInputStream = mFileInputStream;
}
public FileOutputStream getmFileOutputStream() {
return mFileOutputStream;
}
public void setmFileOutputStream(FileOutputStream mFileOutputStream) {
this.mFileOutputStream = mFileOutputStream;
}
//JNI
private native static FileDescriptor open(String path,int baudrate,int flags);
public native void close();
static {
System.loadLibrary("serial_port");
}
}
package android_serialport_api;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import com.fx.serialporttest.L;
public? class SerialPortFinger {
private static ReadThread readThread;
private static FileInputStream mFileInputStream;
private static FileOutputStream mFileOutputStream;
static String path = "/dev/ttyS0";//設(shè)備主板的串口地址,地址有所不同
public? void startListener(){
SerialPort serialPort = new SerialPort(new File(path), 9600, 0);//9600是波特率,這個(gè)也是有所不同,具體要看設(shè)備
mFileInputStream = serialPort.getmFileInputStream();
mFileOutputStream = serialPort.getmFileOutputStream();//獲取串口寫入流
readThread? = new ReadThread();
readThread.start();//開(kāi)啟監(jiān)聽(tīng)
}
/**
* 發(fā)送指令到串口
*
* @param cmd
* @return
*/
public boolean sendCmds(String cmd) {
boolean result = true;
byte[] mBuffer = (cmd+"\r\n").getBytes();
try {
if (mFileOutputStream != null) {
mFileOutputStream.write(mBuffer);
} else {
result = false;
}
} catch (IOException e) {
e.printStackTrace();
result = false;
}
return result;
}
static class ReadThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
int len;
StringBuffer sb = new StringBuffer("");
while(true){ //循環(huán)監(jiān)聽(tīng)串口,讀取返回的數(shù)據(jù)
byte[] buffer = new byte[1024];
if(mFileInputStream==null){
return;
}
try {
len = mFileInputStream.read(buffer);
if(len0){
sb.append(new String(buffer, 0, len));
}
if(!sb.toString().equals(""))
{
L.tag(sb.toString());//收到串口的返回?cái)?shù)據(jù),在日志中打印出來(lái)
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
L.tag("接受完成");
}
}
}
}
當(dāng)前名稱:android通訊,android通訊錄論文
網(wǎng)站鏈接:http://chinadenli.net/article25/dsgpcji.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、軟件開(kāi)發(fā)、品牌網(wǎng)站建設(shè)、面包屑導(dǎo)航、建站公司、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)