AOSP學(xué)習(xí)(五)跨系統(tǒng)通信SOA架構(gòu)設(shè)計(jì)

[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)定性。

SOA.png

二、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的解析。

host-server.png

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)。

系統(tǒng)啟動(dòng).png

3.2 name-server編譯

將FDBUS放入Android AOSP源碼 /frameworks/native/services 中:

不是必須放入該目錄,這里以此目錄為例。

nameserver目錄.png

打開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。

basemk.jpg
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

fdbus-java-api.png

并修改AOSP源碼中的`/build/soong/scripts/check_boot_jars/package_allowed_list.txt

接著在/framework/base/Android.dp 中找到 **packages_to_document **,并在其中加入ipc.fdbus

1694098955411.jpg

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)必須打通,才能相互通信!

跨系統(tǒng).png

在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ù)器。

host-server.png

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:

阿里云.png

然后啟動(dòng)服務(wù):

#若沒(méi)有執(zhí)行權(quán)限,則先執(zhí)行:sudo chmod +x host_server
./host_server & 
./name_server &

服務(wù)啟動(dòng)后隨時(shí)可以執(zhí)行 lssvc 查看:


lssvc.png

可以看到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é)院

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容