[TOC]
前言
??今天就拿車載來(lái)講,各汽車主機(jī)廠家會(huì)根據(jù)自身的設(shè)計(jì)理念差異將整車劃分成不同的域。博世、大陸等傳統(tǒng) Tier1 劃分了5個(gè)域:動(dòng)力域、底盤域、車身域、座艙域和自動(dòng)駕駛域,也有的(如大眾MEB平臺(tái)、東軟睿馳等)把動(dòng)力域、底盤域和車身域融合為整車控制域,基于安全性和獨(dú)立性要求,不同的系統(tǒng)之間數(shù)據(jù)不能直接訪問(wèn)。但是不同域下的不同系統(tǒng)之間,同一域下的不同系統(tǒng)之間的通信需求現(xiàn)實(shí)存在?,F(xiàn)有的解決方案主要是基于TCP/IP協(xié)議棧的Socket(套接字)通訊。
一、SOA架構(gòu)設(shè)計(jì)
??SOA,或Service-Oriented Architecture(面向服務(wù)的架構(gòu)),是一種軟件架構(gòu)模式,旨在促進(jìn)系統(tǒng)中不同組件之間的松耦合和重用性。在 SOA 中,軟件系統(tǒng)被劃分為多個(gè)服務(wù),每個(gè)服務(wù)代表一個(gè)具體的業(yè)務(wù)功能或操作。這些服務(wù)通過(guò)標(biāo)準(zhǔn)化的接口進(jìn)行通信,可以獨(dú)立部署、維護(hù)和擴(kuò)展:
服務(wù):服務(wù)是 SOA 架構(gòu)的基本構(gòu)建塊。每個(gè)服務(wù)代表一個(gè)獨(dú)立的業(yè)務(wù)功能或操作。服務(wù)通常具有清晰的接口,定義了其提供的功能和數(shù)據(jù)格式。
松耦合:SOA 旨在實(shí)現(xiàn)松耦合,這意味著系統(tǒng)的不同部分可以獨(dú)立開發(fā)、部署和維護(hù),而不會(huì)對(duì)其他部分造成影響。這使得系統(tǒng)更加靈活且容易擴(kuò)展。
標(biāo)準(zhǔn)化接口:每個(gè)服務(wù)都通過(guò)標(biāo)準(zhǔn)化的接口提供其功能。這些接口通常是基于開放標(biāo)準(zhǔn)的,如Web服務(wù)描述語(yǔ)言(WSDL)或RESTful API。
服務(wù)注冊(cè)與發(fā)現(xiàn):在 SOA 中,服務(wù)通常需要在注冊(cè)表或目錄中進(jìn)行注冊(cè),以便其他組件能夠找到并使用它們。服務(wù)發(fā)現(xiàn)機(jī)制用于在運(yùn)行時(shí)查找服務(wù)的位置和接口。
重用性:SOA 提倡服務(wù)的重用,這意味著相同的服務(wù)可以在不同的應(yīng)用程序或系統(tǒng)中使用。這有助于減少重復(fù)開發(fā)和提高效率。
跨平臺(tái)通信:SOA 允許不同的系統(tǒng)和應(yīng)用程序在不同的平臺(tái)和編程語(yǔ)言中進(jìn)行通信。這通過(guò)使用標(biāo)準(zhǔn)的協(xié)議和數(shù)據(jù)格式來(lái)實(shí)現(xiàn)。
安全性:SOA 架構(gòu)強(qiáng)調(diào)安全性,確保只有經(jīng)過(guò)身份驗(yàn)證和授權(quán)的組件才能訪問(wèn)服務(wù)。
錯(cuò)誤處理:SOA 考慮了錯(cuò)誤處理和異常處理機(jī)制,以確保系統(tǒng)的可靠性和穩(wěn)定性。

二、Android安全機(jī)制
2.1、權(quán)限分類
??DAC(Discretionary Access Control)和 MAC(Mandatory Access Control)是兩種不同的訪問(wèn)控制模型,用于管理操作系統(tǒng)和應(yīng)用程序?qū)ο到y(tǒng)資源的訪問(wèn)權(quán)限。它們之間的主要區(qū)別在于授權(quán)的方式和級(jí)別:
2.1.1 DAC(Discretionary Access Control)
DAC 是一種相對(duì)較簡(jiǎn)單的訪問(wèn)控制模型,它授權(quán)的權(quán)力由資源的所有者決定。每個(gè)資源(如文件、目錄、進(jìn)程)都有一個(gè)所有者,所有者可以自行決定誰(shuí)可以訪問(wèn)這些資源,以及如何訪問(wèn)。
在 DAC 模型中,資源的所有者可以分配權(quán)限給其他用戶或組。這些權(quán)限通常包括讀取、寫入和執(zhí)行等。其他用戶可以請(qǐng)求訪問(wèn)資源,但只有資源的所有者或被賦予適當(dāng)權(quán)限的用戶才能獲得訪問(wèn)權(quán)限。
DAC 模型適用于多用戶系統(tǒng),但容易受到濫用和誤用。因?yàn)闄?quán)限由資源的所有者決定,所以如果資源的所有者不謹(jǐn)慎,可能會(huì)導(dǎo)致系統(tǒng)安全性問(wèn)題。
2.1.2 MAC(Mandatory Access Control)
MAC 是一種更嚴(yán)格的訪問(wèn)控制模型,它不由資源的所有者決定,而是由系統(tǒng)管理員或安全政策規(guī)定。在 MAC 模型中,資源的訪問(wèn)權(quán)限是強(qiáng)制執(zhí)行的,不受資源的所有者控制。
MAC 模型通常使用標(biāo)簽或安全上下文來(lái)標(biāo)識(shí)資源和用戶。每個(gè)資源和用戶都分配有一個(gè)唯一的安全標(biāo)簽。然后,系統(tǒng)根據(jù)預(yù)定義的安全政策來(lái)決定哪些標(biāo)簽可以訪問(wèn)哪些資源。
MAC 模型適用于需要嚴(yán)格安全控制的環(huán)境,如政府、軍事和高度敏感的系統(tǒng)。它可以防止濫用權(quán)限,但也需要更復(fù)雜的配置和管理。
2.2、SEAndroid管理策略(MAC)
??Android中使用的MAC機(jī)制就是SEAndroid。SELinux(Security-Enhanced Linux) 是美國(guó)國(guó)家安全局(NSA)在Linux社區(qū)的幫助下設(shè)計(jì)的一個(gè)Linux歷史上最杰出的安全系統(tǒng),是一種MAC機(jī)制(Mandatory Access Control,強(qiáng)制訪問(wèn)控制)。在這種訪問(wèn)控制體系的限制下,進(jìn)程只能訪問(wèn)那些在他的任務(wù)中所需要文件。
??SEAndroid安全機(jī)制又稱為是基于TE(Type Enforcement)策略的安全機(jī)制。在/system/sepolicy目錄中,所有以.te為后綴的文件均為策略配置文件。
策略編寫流程:
2.2.1 編寫.te文件
我們來(lái)看看zxx-server進(jìn)程,因此在/system/sepolicy/private目錄下會(huì)有一個(gè)zxx-server.te作為該進(jìn)程的策略文件。文件內(nèi)容如下:
# 聲明zxx-server類型,并將domain屬性關(guān)聯(lián)到該類型 (進(jìn)程)
#必須具備mlstrustedsubject屬性才具備unix_stream_socket {connectto}
#參考:https://blog.csdn.net/a572423926/article/details/123209225
typeattribute zxx-server, domain,coredomain,mlstrustedsubject;
# 聲明zxx-server_exec類型(可執(zhí)行文件,類型要與file_contexts中的相同)
typeattribute zxx-server_exec, exec_type, file_type, system_file_type;
init_daemon_domain(zxx-server)
#allow語(yǔ)句表示允許的權(quán)限。
allow zxx-server self:tcp_socket { read write getattr getopt setopt shutdown create bind connect name_connect };
allow zxx-server self:netlink_route_socket {create};
allow zxx-server fwmarkd_socket:sock_file {write};
allow zxx-server port:tcp_socket {name_connect};
allow zxx-server netd:unix_stream_socket {connectto};
allow zxx-server self:capability {net_raw};
2.2.2 執(zhí)行文件分配上下文
為文件分配安全上下文:file_contexts 文件列出了 Android 系統(tǒng)中的各種文件以及它們的安全上下文標(biāo)簽。這有助于 SELinux 確定哪些進(jìn)程(主體)可以訪問(wèn)這些文件以及以何種方式訪問(wèn),需要我們?cè)趏licy/private/file_contexts中聲明SEAndroid系統(tǒng)文件的安全上下文:
//在Android.bp編譯底下在/system/bin/有個(gè)可執(zhí)行程序
/system/bin/zxx-server u:object_r:name-server_exec:s0
2.2.3 檢查缺少權(quán)限
運(yùn)行某個(gè)進(jìn)程,如果該進(jìn)程不具備對(duì)應(yīng)的權(quán)限,則可以在logcat 或者在執(zhí)行 adb root 后執(zhí)行 adb shell dmesg查看:
avc: denied { bind } for pid=417 comm="zxx-server" scontext=u:r:name-server:s0 tcontext=u:r:name-server:s0 tclass=tcp_socket permissive=0
avc: denied { connectto } for pid=417 comm="zxx-server" scontext=u:r:name-server:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket permissive=0
| 說(shuō)明 | 案例 |
|---|---|
| 缺少什么權(quán)限 | { bind } |
| 誰(shuí)缺少權(quán)限 | scontext=u:r:name-server:s0 |
| 對(duì)誰(shuí)缺少權(quán)限 | tcontext=u:r:name-server:s0 |
| 什么類型的權(quán)限 | tclass=tcp_socket |
此時(shí)就需要在TE文件中聲明:
#allow [誰(shuí)缺少權(quán)限] [對(duì)誰(shuí)缺少權(quán)限]:[什么類型的權(quán)限] [缺少什么權(quán)限]
#當(dāng)sconext與tcontext都是自己時(shí)候,可以將 [對(duì)誰(shuí)缺少權(quán)限]寫為:self
allow zxx-server self:tcp_socket {bind}
allow zxx-server netd:unix_stream_socket {connectto};
三、跨系統(tǒng)通信方案
大眾在FDBUS基礎(chǔ)上開發(fā)通信中間件完成系統(tǒng)間的通信。
FDBus:https://gitee.com/jeremyczhen/fdbus
Fast Distributed Bus,基于Socket(Unix Domain和TCP)的快速分布式總線。
UDS:Unix Domain Socket,專用于IPC。Zygote中的Local Socket即為UDS。
FDBUS為了更方便的進(jìn)行尋址,允許不通過(guò)IP+端口或者固定UDS地址,而是采用域名的方式進(jìn)行尋址。類似于在瀏覽器輸入www.baidu.com,與百度完成通信,則需要進(jìn)行DNS解析,將域名轉(zhuǎn)化為IP地址。
FDBUS同樣提供了name-server ,負(fù)責(zé)管理server名字(域名)與地址(IP)的映射,和DNS服務(wù)器一樣,完成server名字到IP的解析。

3.1 部署name-server
name--server和Android中的ServiceManager一樣,都是負(fù)責(zé)完成服務(wù)的注冊(cè)與查詢。與ServiceManager一樣,系統(tǒng)啟動(dòng)第一時(shí)間就需要啟動(dòng)該服務(wù)進(jìn)程,以便于其他進(jìn)程進(jìn)行服務(wù)注冊(cè)與查詢。因此我們需要將name-server部署到init.rc中,讓其第一時(shí)間隨系統(tǒng)而啟動(dòng)。

3.2 name-server編譯
將FDBUS放入Android AOSP源碼 /frameworks/native/services 中:
不是必須放入該目錄,這里以此目錄為例。

打開Android.bp文件,將其修改為:
//=====================================================================================
// makefile to build fdbus in aosp source tree |
//=====================================================================================
//=====================================================================================
// build libfdbus.so |
//=====================================================================================
SRC_FILES = [
"fdbus/CBaseClient.cpp",
"fdbus/CFdbBaseObject.cpp",
"fdbus/CFdbMessage.cpp",
"fdbus/CFdbSimpleSerializer.cpp",
"fdbus/CBaseEndpoint.cpp",
"fdbus/CFdbCJsonMsgBuilder.cpp",
"fdbus/CFdbSessionContainer.cpp",
"log/CLogProducer.cpp",
"fdbus/CBaseServer.cpp",
"fdbus/CFdbContext.cpp",
"fdbus/CFdbBaseContext.cpp",
"fdbus/CFdbSession.cpp",
"fdbus/CFdbMsgDispatcher.cpp",
"fdbus/CEventSubscribeHandle.cpp",
"fdbus/CFdbUDPSession.cpp",
"fdbus/CBaseSession.cpp",
"fdbus/CFdbWatchdog.cpp",
"fdbus/CFdbEventRouter.cpp",
"platform/CEventFd_eventfd.cpp",
"platform/linux/CBaseMutexLock.cpp",
"platform/linux/CBasePipe.cpp",
"platform/linux/CBaseSysDep.cpp",
"platform/linux/CBaseThread.cpp",
"platform/socket/CBaseSocketFactory.cpp",
"platform/socket/linux/CLinuxSocket.cpp",
"platform/socket/sckt-0.5/sckt.cpp",
"platform/socket/CGenericClientSocket.cpp",
"platform/socket/CGenericServerSocket.cpp",
"platform/socket/CGenericSession.cpp",
"platform/socket/CGenericSocket.cpp",
"platform/socket/CGenericTcpSession.cpp",
"platform/socket/CGenericUdpSession.cpp",
"platform/socket/CGenericUdpSocket.cpp",
"security/CApiSecurityConfig.cpp",
"security/CFdbToken.cpp",
"security/CFdbusSecurityConfig.cpp",
"security/CHostSecurityConfig.cpp",
"security/CServerSecurityConfig.cpp",
"utils/fdb_option_parser.cpp",
"worker/CBaseEventLoop.cpp",
"worker/CBaseWorker.cpp",
"worker/CFdEventLoop.cpp",
"worker/CThreadEventLoop.cpp",
"worker/CSysFdWatch.cpp",
"utils/CBaseNameProxy.cpp",
"fdbus/CIntraNameProxy.cpp",
"server/CAddressAllocator.cpp",
"log/CLogPrinter.cpp",
"log/CFdbLogCache.cpp",
"utils/cJSON/cJSON.c",
"fdbus/CFdbAFComponent.cpp",
"datapool/CDataPool.cpp",
"datapool/CDpClient.cpp",
"datapool/CDpServer.cpp",
]
cc_library_shared {
name: "libfdbus",
vendor_available: true,
cppflags: [
"-Wno-non-virtual-dtor",
"-frtti",
"-fexceptions",
"-Wno-unused-parameter",
"-D__LINUX__",
"-DFDB_CFG_SOCKET_PATH=\"/data/misc/fdbus\"",
"-DCONFIG_DEBUG_LOG",
"-DCONFIG_SOCKET_CONNECT_TIMEOUT=0",
"-DCONFIG_LOG_TO_STDOUT",
"-DCONFIG_FDB_NO_RTTI",
"-DCONFIG_FDB_MESSAGE_METADATA",
"-DFDB_CONFIG_UDS_ABSTRACT",
"-DCFG_ALLOC_PORT_BY_SYSTEM",
],
cflags: [
"-Wno-non-virtual-dtor",
"-Wno-unused-parameter",
"-D__LINUX__",
"-DFDB_CFG_SOCKET_PATH=\"/data/misc/fdbus\"",
"-DCONFIG_DEBUG_LOG",
"-DCONFIG_SOCKET_CONNECT_TIMEOUT=0",
"-DCONFIG_LOG_TO_STDOUT",
"-DCONFIG_FDB_MESSAGE_METADATA",
"-DFDB_CONFIG_UDS_ABSTRACT",
"-DCFG_ALLOC_PORT_BY_SYSTEM",
],
shared_libs: [
"liblog",
"libutils",
],
srcs: SRC_FILES,
export_include_dirs: ["public"],
local_include_dirs: [],
}
//=====================================================================================
// build libfdbus-jni.so |
//=====================================================================================
cc_library_shared {
name: "libfdbus-jni",
cppflags: [
"-Wno-non-virtual-dtor",
"-frtti",
"-fexceptions",
"-Wno-unused-parameter",
"-D__LINUX__",
"-DFDB_CFG_SOCKET_PATH=\"/data/misc/fdbus\"",
"-DCONFIG_DEBUG_LOG",
"-DCFG_JNI_ANDROID",
"-DFDB_CFG_KEEP_ENV_TYPE",
],
cflags: [
"-Wno-non-virtual-dtor",
"-Wno-unused-parameter",
"-D__LINUX__",
"-DFDB_CFG_SOCKET_PATH=\"/data/misc/fdbus\"",
"-DCONFIG_DEBUG_LOG",
"-DCFG_JNI_ANDROID",
],
srcs: [
"jni/src/cpp/CJniClient.cpp",
"jni/src/cpp/CJniMessage.cpp",
"jni/src/cpp/CJniServer.cpp",
"jni/src/cpp/FdbusGlobal.cpp",
"jni/src/cpp/CJniAFComponent.cpp",
],
shared_libs: ["libfdbus"],
include_dirs: [
"frameworks/base/core/jni",
"frameworks/base/core/jni/include",
],
}
//=====================================================================================
// build name-server |
//=====================================================================================
cc_binary {
name: "name-server",
vendor_available: true,
//init_rc: ["fdbus-name-server.rc"],
cppflags: [
"-Wno-non-virtual-dtor",
"-frtti",
"-fexceptions",
"-Wno-unused-parameter",
"-D__LINUX__",
"-DFDB_CFG_SOCKET_PATH=\"/data/misc/fdbus\"",
"-DCONFIG_DEBUG_LOG",
],
cflags: [
"-Wno-non-virtual-dtor",
"-Wno-unused-parameter",
"-D__LINUX__",
"-DFDB_CFG_SOCKET_PATH=\"/data/misc/fdbus\"",
"-DCONFIG_DEBUG_LOG",
],
srcs: [
"server/main_ns.cpp",
"server/CNameServer.cpp",
"server/CInterNameProxy.cpp",
"server/CIntraHostProxy.cpp",
"server/CBaseHostProxy.cpp",
"server/CSvcAddrUtils.cpp",
"server/CNameProxyContainer.cpp",
"security/CServerSecurityConfig.cpp",
],
shared_libs: [
"libfdbus",
"liblog",
"libutils",
],
}
上述腳本會(huì)編譯出libfdbus.so、libfdbus-jni.so與name-server可執(zhí)行文件。其中so需要放入編譯出的系統(tǒng)ROM中的/system/lib目錄,而name-server需要放入/system/bin。
為了在編譯ROM時(shí)能編譯fdbus,需要在 /build/target/product/base.mk 中的****中加入一個(gè)base_system_custom.mk文件專門中的****中加入:libfdbus、libfdbus-jni與name-server。

PRODUCT_PACKAGES += \
libfdbus \
libfdbus-jni \
name-server \
3.3 name-server啟動(dòng)
為了讓name-server開機(jī)啟動(dòng),需要在 init.rc中配置啟動(dòng)腳本。
把FDBUS源碼根目錄下的fdbus-name-server.rc 刪掉!
打開 /system/core/rootdir/init.rc 在文件最后加入:
#1、在掛載 /data 后創(chuàng)建/data/misc/fdbus 并設(shè)置system用戶組權(quán)限
on post-fs-data
mkdir /data/misc/fdbus 0755 system system
#2、啟動(dòng)name-server
service name-server /system/bin/name-server -u tcp://139.224.136.101:60000 -n android
class core
user root
group system root inet
writepid /dev/cpuset/system-background/tasks
1、因?yàn)镕DBUS支持uds與tcp。在當(dāng)前系統(tǒng)中其他進(jìn)程需要連接name-server會(huì)采用UDS的方式,/data/misc/fdbus 則為name-server的uds固定地址。
mkdir /data/misc/fdbus 0755 system system:創(chuàng)建文件并設(shè)置權(quán)限。
2、-u 參數(shù)后文解釋,-n 參數(shù)為當(dāng)前name-server的別名可以隨意傳遞。
class core:當(dāng)前服務(wù)屬主,系統(tǒng)能根據(jù)屬主統(tǒng)一管理同屬主下所有的進(jìn)程,同一個(gè)class的所有服務(wù)必須同時(shí)啟動(dòng)或者停止。
group inet:當(dāng)前服務(wù)的用戶組。 inet 組表示允許網(wǎng)絡(luò)訪問(wèn)!在/framework/base/data/etc/platform.xml 中可以查看權(quán)限對(duì)應(yīng)的用戶組:
package權(quán)限.png
3.4 name-server權(quán)限
更詳細(xì)內(nèi)容見(jiàn)《SEAndroid安全機(jī)制》
完成上述配置后,系統(tǒng)啟動(dòng)就會(huì)拉起name-server,但是此時(shí)name-server還無(wú)法正常工作。Android是建立在標(biāo)準(zhǔn)的Linux Kernel基礎(chǔ)上,通過(guò)Linux的 SELinux(SEAndroid)進(jìn)行訪問(wèn)權(quán)限控制。name-server需要訪問(wèn)tcp_socket、unix_stream_socket則必須開啟SElinux的訪問(wèn)限制。
在 system/sepolicy/private/file_contexts 的最后一行加入:
/system/bin/name-server u:object_r:name-server_exec:s0
接著在system/sepolicy/private/下創(chuàng)建name-server.te 在文件中寫入:
type name-server, domain, mlstrustedsubject;
type name-server_exec, exec_type, file_type;
allow name-server self:tcp_socket { read write getattr getopt setopt shutdown create bind connect name_connect };
allow name-server self:netlink_route_socket {create};
allow name-server fwmarkd_socket:sock_file {write};
allow name-server port:tcp_socket {name_connect};
allow name-server netd:unix_stream_socket {connectto};
allow name-server self:capability {net_raw};
init_daemon_domain(name-server)
同時(shí)name-server需要與netd進(jìn)程(網(wǎng)絡(luò)管理進(jìn)程)交互,還需要在當(dāng)前目錄下的netd.te 增加:
typeattribute netd coredomain;
typeattribute netd domain_deprecated;
#增加==============
allow netd name-server:fd {use};
allow netd name-server:tcp_socket {getopt};
allow netd name-server:tcp_socket {setopt};
allow netd name-server:tcp_socket {read write};
#==============
init_daemon_domain(netd)
# Allow netd to spawn dnsmasq in it's own domain
domain_auto_trans(netd, dnsmasq_exec, dnsmasq)
# Allow netd to start clatd in its own domain
domain_auto_trans(netd, clatd_exec, clatd)
如果需要普通APP使用name-server, 還需要在system/sepolicy/private/untrusted_app.te中加入:
# ......
create_pty(untrusted_app)
# 加入此處規(guī)則
allow untrusted_app name-server:unix_stream_socket{connectto};
3.5 FDBUS API
在上一步,我們不僅完成了name-server的部署,同時(shí)編譯出libfdbus-jni.so,該動(dòng)態(tài)庫(kù)為FDBUS的Java層API的JNI封裝。為了在Java中完成FDBUS的使用,可以將FDBUS集成進(jìn)入Framework與SDK中。
3.5.1 Framework/SDK 集成
將FDBUS中的jni\src\java 下的Java代碼放入AOSP源碼中的/frameworks/base/core/java 中

并修改AOSP源碼中的`/build/soong/scripts/check_boot_jars/package_allowed_list.txt
接著在/framework/base/Android.dp 中找到 **packages_to_document **,并在其中加入ipc.fdbus

3.5.2 系統(tǒng)內(nèi)IPC通信
按照《Android源碼編譯》課程,編譯Android源碼,并將ROM刷至設(shè)備。然后按照《自定義系統(tǒng)服務(wù)》將SDK制作完成,接下來(lái)就可以在APP中使用FDBUS完成IPC通信:
服務(wù)端:
public class IPCServer implements FdbusServerListener {
private static final String TAG = "IPCServer";
private FdbusServer server;
public IPCServer() {
server = new FdbusServer();
server.setListener(this);
server.bind("svc://enjoy");
}
public void destroy() {
server.unbind();
server.destroy();
}
@Override
public void onOnline(int sid, boolean is_first, int qos) {
Log.i(TAG, "onOnline: " + sid);
}
@Override
public void onOffline(int sid, boolean is_last, int qos) {
Log.i(TAG, "onOffline: " + sid);
}
@Override
public void onInvoke(FdbusMessage fdbusMessage) {
String s = new String(fdbusMessage.byteArray());
Log.i(TAG, "onInvoke: " + fdbusMessage.code() + " " + s);
fdbusMessage.reply(("服務(wù)端響應(yīng) ==>" + s).getBytes());
}
@Override
public void onSubscribe(FdbusMessage msg, ArrayList<SubscribeItem> sub_list) {
for (SubscribeItem subscribeItem : sub_list) {
Log.i(TAG, "客戶端注冊(cè)事件監(jiān)聽(tīng): " + subscribeItem.code() + " " + subscribeItem.topic());
}
}
public FdbusServer getService() {
return server;
}
}
客戶端:
public class IPCClient implements FdbusClientListener {
private static final String TAG = "IPCClient";
private final FdbusClient mClient;
public IPCClient() {
mClient = new FdbusClient();
mClient.setListener(this);
}
public FdbusClient getClient() {
return mClient;
}
@Override
public void onOnline(int sid, int i1) {
Log.i(TAG, "onOnline: " + sid);
ArrayList<SubscribeItem> subscribe_items = new ArrayList<SubscribeItem>();
subscribe_items.add(SubscribeItem.newEvent(100));
mClient.subscribe(subscribe_items);
}
@Override
public void onOffline(int sid, int i1) {
Log.i(TAG, "onOffline: " + sid);
}
@Override
public void onReply(FdbusMessage fdbusMessage) {
Log.i(TAG, "onReply: " + new String(fdbusMessage.byteArray()));
}
@Override
public void onGetEvent(FdbusMessage fdbusMessage) {
// server.initEventCache()
//
Log.i(TAG, "onGetEvent: " +new String(fdbusMessage.byteArray()));
}
@Override
public void onBroadcast(FdbusMessage fdbusMessage) {
Log.i(TAG, "onBroadcast: " + new String(fdbusMessage.byteArray()));
fdbusMessage.destroy();
}
}
//......
IPCClient ipcClient = new IPCClient();
ipcClient.getClient().connect("svc://enjoy");
// 發(fā)送消息給服務(wù)端
FdbusMessage fdbusMessage = ipcClient.getClient().invokeSync(1, "我是客戶端1".getBytes());
ipcClient.getClient().invokeAsync(2, "我是客戶端2".getBytes(), new FdbusAppListener.Action() {
@Override
public void handleMessage(FdbusMessage fdbusMessage) {
Log.i(TAG, "ipc: " + new String(fdbusMessage.byteArray()));
}
});
ipcClient.getClient().send(3, "我是客戶端3".getBytes());
3.5.3 跨系統(tǒng)通信
車載系統(tǒng)中,由于Hypervisor的采用,有的域內(nèi)可能會(huì)有多個(gè)節(jié)點(diǎn)。如智能座艙域,一個(gè)SOC芯片上可能會(huì)同時(shí)運(yùn)行QNX和Android,雖然位于同一個(gè)SOC上,但還是被認(rèn)為是兩個(gè)節(jié)點(diǎn)。這兩個(gè)節(jié)點(diǎn)必須打通,才能相互通信!

在Android與QNX系統(tǒng)中各自部署name-server,Android與QNX的name-server只能管理系統(tǒng)自身內(nèi)部服務(wù),為了打通兩個(gè)系統(tǒng),F(xiàn)DBUS提供了host-server。
就好像DNS解析,本地DNS服務(wù)器無(wú)法解析,就會(huì)請(qǐng)求遠(yuǎn)程服務(wù)器。如果說(shuō)name-server是本地DNS服務(wù)器,那么host-server就是遠(yuǎn)程DNS服務(wù)器。

3.6 host-server部署
host-server可以搭建在域內(nèi),也可以搭建在域外,只要保證Android與QNX都能夠訪問(wèn)即可。
我們以阿里云服務(wù)器為例,現(xiàn)在讓Android與阿里云使用FDBUS完成通信。Android端的name-server已經(jīng)搭建完成,我們還需要在阿里云上搭建name-server與host-server。
按照:https://fdbus.readthedocs.io/en/latest/readme.html#for-ubuntu-host-version-running-at-host-machine 中的介紹,在阿里云中編譯fdbus:

然后啟動(dòng)服務(wù):
#若沒(méi)有執(zhí)行權(quán)限,則先執(zhí)行:sudo chmod +x host_server
./host_server &
./name_server &
服務(wù)啟動(dòng)后隨時(shí)可以執(zhí)行 lssvc 查看:

可以看到host-server端口為:60000,配置阿里云安全規(guī)則,打開阿里云60000端口訪問(wèn)。在Android端的init.rc中配置的name-server填寫阿里云的IP與60000端口:
#1、在掛載 /data 后創(chuàng)建/data/misc/fdbus 并設(shè)置system用戶組權(quán)限
on post-fs-data
mkdir /data/misc/fdbus 0755 system system
#2、啟動(dòng)name-server
service name-server /system/bin/name-server -u tcp://139.224.136.101:60000 -n android
class core
group system inet
writepid /dev/cpuset/system-background/tasks
-u 參數(shù)就是阿里云host-server的地址
-n 則為在當(dāng)前服務(wù)端別名,相當(dāng)于當(dāng)前的name-server在host_server中的用戶名
至此,基于host-server即可完成跨系統(tǒng)的通信!
感謝
享學(xué)課堂
碼牛學(xué)院
