Trusty 提供的 API 可用來開發兩種應用程式/服務:
- 在 TEE 處理器上執行的可信任應用程式或服務
- 在主要處理器上執行,且使用所提供服務的一般/不受信任的應用程式 由信任的應用程式提供
值得信賴 API 通常描述 Trusty 處理序間通訊 (IPC) 系統, 包括與不安全世界的通訊這類軟體是在 主要處理器可以使用 Trusty API 連結至信任的應用程式/服務 並與使用者交換任意訊息,就像透過 IP 網路服務一樣。 模型的資料格式和語意,是由應用程式決定 訊息。可靠的訊息傳送方式 Google 的底層基礎架構 在主要處理器上執行),且通訊也完全非同步。
連接埠與通道
Trusty 應用程式會使用通訊埠,以下列格式呈現服務端點
與用戶端連線的具名路徑之間這可提供以字串為基礎的簡單
服務 ID,以供用戶端使用。命名慣例是反向 DNS 樣式
命名,例如com.google.servicename
。
當用戶端連線到通訊埠時,用戶端會收到用於互動的管道 使用該服務。服務必須接受傳入的連線,以及何時 他們也會收到頻道基本上,系統會使用通訊埠查詢服務 然後透過兩個相連的頻道 (即 連線執行個體)。用戶端連線到通訊埠時 已建立雙向連線。透過這個全雙工路徑 伺服器可交換任意訊息,直到其中一側決定撕破 然後中斷連線
只有安全外部的受信任應用程式或 Trusty 核心模組才能建立 通訊埠。在不安全的環境 (在正常環境中) 上執行的應用程式, 只能連線至安全端發布的服務
根據需求而定,信任的應用程式可以同時是用戶端和 伺服器。可信任的應用程式,將服務發布為 伺服器) 可能需要連線至其他服務 (做為用戶端)。
處理 API
帳號代碼是無正負號整數,代表通訊埠及 管道,類似於 UNIX 中的檔案描述元。帳號代碼建立後, 放在應用程式專屬的帳號代碼表格中,可以參照
呼叫端可以使用
set_cookie()
方法。
Handle API 的方法
帳號代碼只適用於應用程式。應用程式
除非有明確指示,否則不得將控制代碼值傳遞至其他應用程式
。只能比較與
應用程式可使用的 INVALID_IPC_HANDLE #define,
表示帳號代碼無效或未設定。
set_cookie()
將呼叫端提供的私人資料與指定控制代碼建立關聯。
long set_cookie(uint32_t handle, void *cookie)
[in] handle
:其中一個 API 呼叫傳回的控制代碼
[in] cookie
:Trusty 應用程式中任意使用者空間資料的指標
[retval]:成功時為 NO_ERROR
,否則傳回 < 0
錯誤代碼
這個呼叫很適合用來處理稍後發生的事件 帳號代碼已建立。事件處理機制會提供帳號代碼 並將 Cookie 傳回事件處理常式
您可以在事件發生時透過 wait()
呼叫等待處理常式。
等待()
等待指定的控制代碼在一段指定時間內發生事件。
long wait(uint32_t handle_id, uevent_t *event, unsigned long timeout_msecs)
[in] handle_id
:其中一個 API 呼叫傳回的控制代碼
[out] event
:代表該結構的指標
這個帳號代碼發生事件
[in] timeout_msecs
:逾時值 (以毫秒為單位);換
-1 的值是無限逾時
[retval]:NO_ERROR
如果發生在
指定的逾時間隔;如果經過指定的逾時時間,但沒有回應,則為 ERR_TIMED_OUT
是否發生;針對其他錯誤,請< 0
成功 (retval == NO_ERROR
) 時,wait()
呼叫
填入指定的 uevent_t
結構,並在其中填入
發生的事件。
typedef struct uevent { uint32_t handle; /* handle this event is related to */ uint32_t event; /* combination of IPC_HANDLE_POLL_XXX flags */ void *cookie; /* cookie associated with this handle */ } uevent_t;
event
欄位包含下列值的組合:
enum { IPC_HANDLE_POLL_NONE = 0x0, IPC_HANDLE_POLL_READY = 0x1, IPC_HANDLE_POLL_ERROR = 0x2, IPC_HANDLE_POLL_HUP = 0x4, IPC_HANDLE_POLL_MSG = 0x8, IPC_HANDLE_POLL_SEND_UNBLOCKED = 0x10, … more values[TBD] };
IPC_HANDLE_POLL_NONE
- 沒有待處理的活動,
呼叫端應重新啟動等待時間
IPC_HANDLE_POLL_ERROR
- 發生不明內部錯誤
IPC_HANDLE_POLL_READY
- 取決於帳號代碼類型,如下所示:
- 針對通訊埠,這個值表示有待處理的連線
- 對頻道而言,這個值表示非同步連線
已建立 (請參閱
connect()
)
下列事件僅與頻道相關:
IPC_HANDLE_POLL_HUP
- 表示頻道已由同業關閉IPC_HANDLE_POLL_MSG
- 表示這個頻道有待審核的訊息IPC_HANDLE_POLL_SEND_UNBLOCKED
:表示先前 封鎖的來電者,可能會嘗試 訊息 (詳情請參閱send_msg()
的說明)
事件處理常式應準備處理指定的組合 因為可以同時設定多個位元。舉例來說 您可能會收到待處理訊息,並可透過 這會同時供兩人連線
大多數事件都是固定的,只要基礎條件
持續發生 (例如:已收到所有待處理的訊息,但尚未完成連線)
來處理的要求)。只有
IPC_HANDLE_POLL_SEND_UNBLOCKED
事件,
讀取後均清除,而且應用程式只有一次機會
處理資料
如要刪除帳號代碼,請呼叫 close()
方法。
關閉()
刪除與指定帳號代碼相關聯的資源,並從中移除 處理常式資料表。
long close(uint32_t handle_id);
[in] handle_id
:要刪除的控點
[retval]:0 (成功時);否則就會發生負面錯誤
伺服器 API
伺服器一開始會建立一或多個已命名的通訊埠, 服務端點每個充電座都以控點表示。
Server API 中的方法
通訊埠_create()
建立已命名的服務通訊埠。
long port_create (const char *path, uint num_recv_bufs, size_t recv_buf_size, uint32_t flags)
[in] path
:通訊埠的字串名稱 (如上所述)。這個
名稱在整個系統中不得重複就無法建立重複項目。
[in] num_recv_bufs
:管道數量上限
這個通訊埠可以預先分配好,以便與用戶端交換資料。計算緩衝區次數
需要分別處理雙向資料,因此在這裡指定 1 代表 1
傳送和 1 個接收緩衝區。一般來說,緩衝區數量
會取決於用戶端和用戶端
伺服器如果是非常同步的通訊協定,這個數字小到 1
(傳送訊息,接收回覆前需先接收回覆)。但這個數字
客戶可能希望在回覆前傳送多封郵件
出現 (例如,一段訊息為前兆,另一個則當做實際命令)。
分配的緩衝區集是以管道為單位,因此兩個不同的連線 (頻道)
會有獨立的緩衝區組合
[in] recv_buf_size
:
或緩衝區空間上方此值為
交換的訊息大小上限會因通訊協定而異,且會有效限制可交換的訊息大小上限
和對等互連
[in] flags
:指定其他通訊埠行為的標記組合
這個值應為下列值的組合:
IPC_PORT_ALLOW_TA_CONNECT
- 允許其他安全應用程式的連線
IPC_PORT_ALLOW_NS_CONNECT
- 允許來自不安全世界的連線
[retval]:用於處理已建立的通訊埠。如果通訊埠為正數,或是發生特定錯誤, 負面
接著,伺服器會輪詢連入連線的通訊埠控制代碼清單
使用 wait()
呼叫。收到連線後
由 Pod 所設定的 IPC_HANDLE_POLL_READY
位元指定
uevent_t
結構的 event
欄位,
伺服器應呼叫 accept()
來完成建立連線並建立
管道 (以
另一個控制代碼) 來處理收到的訊息。
接受()
接受傳入的連線,並取得頻道的帳號代碼。
long accept(uint32_t handle_id, uuid_t *peer_uuid);
[in] handle_id
:這個控制代碼代表用戶端已連線的通訊埠
[out] peer_uuid
:指向 uuid_t
結構的指標
填入連線用戶端應用程式的 UUID。這項服務
如果連線是來自不安全世界,則會設為全部零
[retval]:處理伺服器可對該通道執行的操作 (如果不是負數的話) 與用戶端交換訊息 (或其他錯誤代碼)
用戶端 API
本節包含 Client API 的方法。
Client API 中的方法
Connect()
啟動連至由名稱指定的通訊埠的連線。
long connect(const char *path, uint flags);
[in] path
:Trusty 應用程式發布的通訊埠名稱
[in] flags
:指定其他的選用行為
[retval]:用來處理訊息與可交換訊息的頻道 伺服器;如果為負值
如果沒有指定 flags
(flags
參數)
如果設為 0),呼叫 connect()
會啟動同步連線
連線至指定通訊埠
如果該通訊埠不存在,就會傳回錯誤,然後建立一個區塊,直到
否則伺服器會接受連線
您可以指定兩個值的組合,以修改此行為。 說明:
enum { IPC_CONNECT_WAIT_FOR_PORT = 0x1, IPC_CONNECT_ASYNC = 0x2, };
IPC_CONNECT_WAIT_FOR_PORT
- 強制使用 connect()
呼叫等待指定的通訊埠沒有在執行時立即存在。
而不會立即失敗
IPC_CONNECT_ASYNC
:如果已設定,系統會啟動非同步連線。一個
就必須輪詢
傳回的控制代碼 (方法是呼叫 wait()
,
IPC_HANDLE_POLL_READY
指定的連線完成事件
在開始之前,請在 uevent_t
結構的事件欄位中設定位元
執行一般作業
訊息 API
Messaging API 呼叫可讓系統透過 先前建立的連線 (頻道)。Messaging API 呼叫是 伺服器和用戶端也是如此
用戶端透過核發 connect()
,收到頻道的帳號代碼
而伺服器會從 accept()
呼叫取得頻道控制代碼,
相同。
可靠訊息的結構
如下圖所示,Trusty API 交換的訊息很少 請將該要求傳送至伺服器和用戶端,達成協議 實際內容:
/* * IPC message */ typedef struct iovec { void *base; size_t len; } iovec_t; typedef struct ipc_msg { uint num_iov; /* number of iovs in this message */ iovec_t *iov; /* pointer to iov array */ uint num_handles; /* reserved, currently not supported */ handle_t *handles; /* reserved, currently not supported */ } ipc_msg_t;
訊息可以由一或多個不連續緩衝區所組成,
iovec_t
結構的陣列。可信
讀取及寫入這些區塊
方法是使用 iov
陣列。可說明緩衝區的內容
iov
陣列是完全隨機的。
Messaging API 中的方法
send_msg()
透過指定頻道傳送訊息。
long send_msg(uint32_t handle, ipc_msg_t *msg);
[in] handle
:用於傳送訊息的管道
[in] msg
:指向說明訊息的 ipc_msg_t structure
[retval]:成功傳送的位元組總數;否則就會發生負面錯誤
用戶端 (或伺服器) 嘗試透過頻道傳送訊息,且
目的地對等互連訊息佇列中沒有任何空間,則管道可能
進入封鎖傳送狀態的狀態 (如果是簡易同步,就不應該發生這個情況
可能會發生
系統會傳回 ERR_NOT_ENOUGH_BUFFER
錯誤代碼。
在這樣的情況下,呼叫端必須等待對等點釋出
藉由擷取處理和取消訊息的方式,在接收佇列中增加空間,
由應用程式的 IPC_HANDLE_POLL_SEND_UNBLOCKED
位元設定
uevent_t
結構的 event
欄位
wait()
呼叫傳回的字串。
get_msg()
取得傳入訊息佇列中下一訊息的相關中繼資訊
特定頻道的 ID 值
long get_msg(uint32_t handle, ipc_msg_info_t *msg_info);
[in] handle
:必須擷取新訊息的管道處理常式
[out] msg_info
:如下所述訊息資訊結構:
typedef struct ipc_msg_info { size_t len; /* total message length */ uint32_t id; /* message id */ } ipc_msg_info_t;
每則訊息都會獲派專屬 ID,範圍涵蓋所有待處理訊息 並填入每則訊息的總長度如果已在 Pod 中設定及允許 用戶端可能會同時擁有多個未解決 (已開啟) 的訊息, 特定頻道
[retval]:NO_ERROR
表示成功;否則就會發生負面錯誤
read_msg()
從 對於指定偏移值而言
long read_msg(uint32_t handle, uint32_t msg_id, uint32_t offset, ipc_msg_t *msg);
[in] handle
:要讀取訊息的管道處理常式
[in] msg_id
:要讀取的訊息 ID
[in] offset
:開始閱讀訊息的偏移值
[out] msg
:指標指向描述的 ipc_msg_t
結構
一組用來儲存傳入訊息的緩衝區
資料
[retval]:儲存在 msg
緩衝區中的位元組總數
成功;否則就會發生負面錯誤
您可以多次呼叫 read_msg
方法,從
不同 (不一定是
序列) 偏移。
Put_msg()
撤銷含有指定 ID 的訊息。
long put_msg(uint32_t handle, uint32_t msg_id);
[in] handle
:收到訊息的頻道帳號代碼
[in] msg_id
:即將淘汰的訊息 ID
[retval]:NO_ERROR
表示成功;否則就會發生負面錯誤
如果訊息已淘汰,且 容器已釋出的空間。
檔案描述元 API
File Descriptor API 包含 read()
、write()
、
和 ioctl()
呼叫。這些呼叫都可以在預先定義的 (靜態) 檔案組上運作
也就是以小數字表示的描述元在目前的
檔案描述元空間與處理序間通訊 (IPC) 控制代碼分開
空白鍵。Trusty 中的 File Descriptor API 是
,類似傳統的檔案描述元式 API
根據預設,有兩種預先定義的 (標準和知名) 檔案描述元:
- 0 - 標準輸入內容。標準輸入值
fd
的預設實作方式 是免人工管理 (因為受信任的應用程式不應有 遊戲),因此讀取、書寫或叫用ioctl()
(fd
0 應傳回ERR_NOT_SUPPORTED
錯誤。 - 1 - 標準輸出。可以轉送寫入標準輸出的資料 (取決於
LK 偵錯層級) 到 UART 和/或可在不安全網站上使用的記憶體記錄
視平台和設定而定非關鍵的偵錯記錄檔
訊息應以標準輸出格式顯示《
read()
》和《ioctl()
》 方法為不可操作,且應該傳回ERR_NOT_SUPPORTED
錯誤。 - 2 - 標準錯誤。寫入標準錯誤的資料應轉送至 UART
視平台和平台而定
此外還會從 0 自動調整資源配置
您完全不必調整資源調度設定建議您只將重要訊息寫入標準
錯誤,因為這個串流很有可能會發生節流限制。
read()
和ioctl()
方法為非作業,應傳回ERR_NOT_SUPPORTED
錯誤。
雖然這個檔案描述元集可以擴充
fds
(用於實作平台專屬的擴充功能)、擴充檔案描述元需求
請謹慎運動擴充檔案描述元相當容易
因此通常不建議採取此做法。
File Descriptor API 的方法
read()
嘗試從指定檔案描述元讀取最多 count
個位元組的資料。
long read(uint32_t fd, void *buf, uint32_t count);
[in] fd
:要讀取的檔案描述元
[out] buf
:指向要儲存資料的緩衝區
[in] count
:可讀取的位元組數上限
[retval]:傳回讀取的位元組數;否則就會發生負面錯誤
Write()
最多會將 count
位元組的資料寫入指定的檔案描述元。
long write(uint32_t fd, void *buf, uint32_t count);
[in] fd
:要寫入的檔案描述元
[out] buf
:要寫入的資料指標
[in] count
:可寫入的位元組數量上限
[retval]:傳回的寫入位元組數;否則就會發生負面錯誤
ioctl()
針對特定檔案描述元叫用指定的 ioctl
指令。
long ioctl(uint32_t fd, uint32_t cmd, void *args);
[in] fd
:要叫用 ioctl()
的檔案描述元
[in] cmd
:ioctl
指令
[in/out] args
:指向 ioctl()
引數的指標
其他 API
Miscellaneous API 中的方法
gettime()
傳回目前的系統時間 (以奈秒為單位)。
long gettime(uint32_t clock_id, uint32_t flags, int64_t *time);
[in] clock_id
:取決於平台;預設的值為 0
[in] flags
:已保留,應為零
[out] time
:指向用於儲存目前時間的 int64_t
值
[retval]:NO_ERROR
表示成功;否則就會發生負面錯誤
Nanosleep()
在指定時間範圍內暫停執行呼叫應用程式的執行作業 已恢復訂閱
long nanosleep(uint32_t clock_id, uint32_t flags, uint64_t sleep_time)
[in] clock_id
:已保留,應為零
[in] flags
:已保留,應為零
[in] sleep_time
:以奈秒為單位的睡眠時間
[retval]:NO_ERROR
表示成功;否則就會發生負面錯誤
可信任應用程式伺服器的範例
下列範例應用程式顯示上述 API 的用法。範例 建立「echo」這項服務可處理多個傳入連線 反映給呼叫端的全部來自用戶端的訊息 透過安全或不安全的環境
#include <uapi/err.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <trusty_ipc.h> #define LOG_TAG "echo_srv" #define TLOGE(fmt, ...) \ fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__) # define MAX_ECHO_MSG_SIZE 64 static const char * srv_name = "com.android.echo.srv.echo"; static uint8_t msg_buf[MAX_ECHO_MSG_SIZE]; /* * Message handler */ static int handle_msg(handle_t chan) { int rc; struct iovec iov; ipc_msg_t msg; ipc_msg_info_t msg_inf; iov.iov_base = msg_buf; iov.iov_len = sizeof(msg_buf); msg.num_iov = 1; msg.iov = &iov; msg.num_handles = 0; msg.handles = NULL; /* get message info */ rc = get_msg(chan, &msg_inf); if (rc == ERR_NO_MSG) return NO_ERROR; /* no new messages */ if (rc != NO_ERROR) { TLOGE("failed (%d) to get_msg for chan (%d)\n", rc, chan); return rc; } /* read msg content */ rc = read_msg(chan, msg_inf.id, 0, &msg); if (rc < 0) { TLOGE("failed (%d) to read_msg for chan (%d)\n", rc, chan); return rc; } /* update number of bytes received */ iov.iov_len = (size_t) rc; /* send message back to the caller */ rc = send_msg(chan, &msg); if (rc < 0) { TLOGE("failed (%d) to send_msg for chan (%d)\n", rc, chan); return rc; } /* retire message */ rc = put_msg(chan, msg_inf.id); if (rc != NO_ERROR) { TLOGE("failed (%d) to put_msg for chan (%d)\n", rc, chan); return rc; } return NO_ERROR; } /* * Channel event handler */ static void handle_channel_event(const uevent_t * ev) { int rc; if (ev->event & IPC_HANDLE_POLL_MSG) { rc = handle_msg(ev->handle); if (rc != NO_ERROR) { /* report an error and close channel */ TLOGE("failed (%d) to handle event on channel %d\n", rc, ev->handle); close(ev->handle); } return; } if (ev->event & IPC_HANDLE_POLL_HUP) { /* closed by peer. */ close(ev->handle); return; } } /* * Port event handler */ static void handle_port_event(const uevent_t * ev) { uuid_t peer_uuid; if ((ev->event & IPC_HANDLE_POLL_ERROR) || (ev->event & IPC_HANDLE_POLL_HUP) || (ev->event & IPC_HANDLE_POLL_MSG) || (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) { /* should never happen with port handles */ TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle); abort(); } if (ev->event & IPC_HANDLE_POLL_READY) { /* incoming connection: accept it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) { TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle); return; } handle_t chan = rc; while (true){ struct uevent cev; rc = wait(chan, &cev, INFINITE_TIME); if (rc < 0) { TLOGE("wait returned (%d)\n", rc); abort(); } handle_channel_event(&cev); if (cev.event & IPC_HANDLE_POLL_HUP) { return; } } } } /* * Main application entry point */ int main(void) { int rc; handle_t port; /* Initialize service */ rc = port_create(srv_name, 1, MAX_ECHO_MSG_SIZE, IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT); if (rc < 0) { TLOGE("Failed (%d) to create port %s\n", rc, srv_name); abort(); } port = (handle_t) rc; /* enter main event loop */ while (true) { uevent_t ev; ev.handle = INVALID_IPC_HANDLE; ev.event = 0; ev.cookie = NULL; /* wait forever */ rc = wait(port, &ev, INFINITE_TIME); if (rc == NO_ERROR) { /* got an event */ handle_port_event(&ev); } else { TLOGE("wait returned (%d)\n", rc); abort(); } } return 0; }
run_end_to_end_msg_test()
方法會以非同步方式傳送 10,000 則訊息
並轉換成服務和控制代碼
以及回覆內容
static int run_echo_test(void) { int rc; handle_t chan; uevent_t uevt; uint8_t tx_buf[64]; uint8_t rx_buf[64]; ipc_msg_info_t inf; ipc_msg_t tx_msg; iovec_t tx_iov; ipc_msg_t rx_msg; iovec_t rx_iov; /* prepare tx message buffer */ tx_iov.base = tx_buf; tx_iov.len = sizeof(tx_buf); tx_msg.num_iov = 1; tx_msg.iov = &tx_iov; tx_msg.num_handles = 0; tx_msg.handles = NULL; memset (tx_buf, 0x55, sizeof(tx_buf)); /* prepare rx message buffer */ rx_iov.base = rx_buf; rx_iov.len = sizeof(rx_buf); rx_msg.num_iov = 1; rx_msg.iov = &rx_iov; rx_msg.num_handles = 0; rx_msg.handles = NULL; /* open connection to echo service */ rc = sync_connect(srv_name, 1000); if(rc < 0) return rc; /* got channel */ chan = (handle_t)rc; /* send/receive 10000 messages asynchronously. */ uint tx_cnt = 10000; uint rx_cnt = 10000; while (tx_cnt || rx_cnt) { /* send messages until all buffers are full */ while (tx_cnt) { rc = send_msg(chan, &tx_msg); if (rc == ERR_NOT_ENOUGH_BUFFER) break; /* no more space */ if (rc != 64) { if (rc > 0) { /* incomplete send */ rc = ERR_NOT_VALID; } goto abort_test; } tx_cnt--; } /* wait for reply msg or room */ rc = wait(chan, &uevt, 1000); if (rc != NO_ERROR) goto abort_test; /* drain all messages */ while (rx_cnt) { /* get a reply */ rc = get_msg(chan, &inf); if (rc == ERR_NO_MSG) break; /* no more messages */ if (rc != NO_ERROR) goto abort_test; /* read reply data */ rc = read_msg(chan, inf.id, 0, &rx_msg); if (rc != 64) { /* unexpected reply length */ rc = ERR_NOT_VALID; goto abort_test; } /* discard reply */ rc = put_msg(chan, inf.id); if (rc != NO_ERROR) goto abort_test; rx_cnt--; } } abort_test: close(chan); return rc; }
不安全的世界 API 和應用程式
一組 Trusty 服務,從安全端發布,並標註
IPC_PORT_ALLOW_NS_CONNECT
屬性,可供核心存取
使用者空間程式
有安全疑慮的情況
非安全端 (核心和使用者空間) 上的執行環境為 與安全端的執行環境有極大差異 因此,不會有兩個環境共用一個程式庫,而是有兩個 不同的 API 組合在核心中,Client API 是由 Trusty-ipc 核心驅動程式,並註冊可用的字元裝置節點 藉由使用者空間程序與
使用者空間 Trusty IPC 用戶端 API
使用者空間 Trusty IPC Client API 程式庫是位於
裝置節點「fd
」。
使用者空間程式啟動了通訊工作階段
呼叫 tipc_connect()
初始化連至指定的 Trusty 服務的連線。Google 內部
tipc_connect()
呼叫會開啟指定的裝置節點,
取得檔案描述元並叫用 TIPC_IOC_CONNECT ioctl()
呼叫,並使用 argp
參數,指向包含
連線目的地服務名稱
#define TIPC_IOC_MAGIC 'r' #define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char *)
產生的檔案描述元只能用於與服務通訊
這個名稱檔案描述元
不再需要連線時呼叫 tipc_close()
。
透過 tipc_connect()
呼叫取得的檔案描述元
的行為與一般字元裝置節點相同檔案描述元:
- 可視需要切換為非封鎖模式
- 可使用標準
write()
進行編寫 打電話,傳送訊息給對方 - 可透過
poll()
呼叫或select()
呼叫進行輪詢 做為一般檔案描述元的可用性 - 可讀取以擷取收到的訊息
呼叫端會對 Trusty 服務執行寫入呼叫
指定的 fd
。傳遞至上述 write()
呼叫的所有資料
會由 Trusty-ipc 驅動程式轉換成訊息訊息是
傳輸至安全端,其中 IPC 子系統處理資料所在的安全端
Trusty 核心並轉送至正確的目的地,並傳送至應用程式
特定管道上做為 IPC_HANDLE_POLL_MSG
事件的事件迴圈
控制代碼。根據特定用途
服務專屬通訊協定,Trusty 服務可能會傳送一或多則回覆
並放置在
使用者可擷取的適當管道檔案描述元訊息佇列
聊天室應用程式「read()
」呼叫。
tipc_connect()
開啟指定的 tipc
裝置節點並啟動
連線至指定的 Trusty 服務。
int tipc_connect(const char *dev_name, const char *srv_name);
[in] dev_name
:要開啟的 Trusty IPC 裝置節點路徑
[in] srv_name
:要連結的已發布 Trusty 服務名稱
[retval]:有效的檔案描述元 (成功時),否則為 -1。
tipc_close()
關閉檔案描述元指定的 Trusty 服務連線。
int tipc_close(int fd);
[in] fd
:先前由 開啟的檔案描述元
tipc_connect()
通話
核心 Trusty IPC 用戶端 API
核心 Trusty IPC Client API 適用於核心驅動程式。該使用者 space Trusty IPC API 是由這個 API 之上實作。
一般來說,這個 API 的常見用途包含建立呼叫端
使用 tipc_create_channel()
建立 struct tipc_chan
物件
函式,然後使用 tipc_chan_connect()
呼叫啟動
連線至
可終止與遠端端的連線
呼叫 tipc_chan_shutdown()
,後面接著
釋出資源:tipc_chan_destroy()
。
收到通知時 (透過 handle_event()
回呼)
成功建立連線後
包括:
- 使用
tipc_chan_get_txbuf_timeout()
呼叫取得訊息緩衝區 - 撰寫訊息,以及
- 使用
tipc_chan_queue_msg()
將訊息排入佇列 傳送至 Trusty 服務的方式 (在安全端), 已連結頻道
排入佇列成功後,呼叫端應清除訊息緩衝區
因為訊息緩衝區最終會回到免費緩衝區集區
即可 (供稍後重複使用) 處理其他訊息。該使用者
只有在無法呼叫 tipc_chan_put_txbuf()
的情況下,
將這類緩衝區排入佇列,或者不再需要該緩衝區。
API 使用者透過處理
handle_msg()
通知回呼 (會在
建立 Trusty-ipc rx
工作佇列的結構定義),
會提供指向 rx
緩衝區的指標,其中包含
。
handle_msg()
回呼應該是
實作會將指標傳回有效的 struct tipc_msg_buf
。
如果是在本機處理訊息,可以與傳入訊息緩衝區相同
也不再需要使用或者,可以是新的緩衝區,方法是使用
tipc_chan_get_rxbuf()
呼叫 (如果傳入緩衝區已排入佇列)
以便後續處理必須追蹤卸離的 rx
緩衝區
而且最終會透過 tipc_chan_put_rxbuf()
呼叫釋出
就不必再使用
核心 Trusty IPC 用戶端 API 中的方法
tipc_create_channel()
針對特定的 Trusty IPC 頻道建立和設定執行個體 。
struct tipc_chan *tipc_create_channel(struct device *dev, const struct tipc_chan_ops *ops, void *cb_arg);
[in] dev
:指向裝置適用的 Trusty-ipc
建立管道
[in] ops
:指向 struct tipc_chan_ops
的指標,
(僅限來電者)
已填入的回呼
[in] cb_arg
:將要傳遞的資料指標
呼叫 tipc_chan_ops
回呼
[retval]:指向新建立的
struct tipc_chan
,
另有 ERR_PTR(err)
一般來說,呼叫端必須提供兩個非同步叫用的回呼 以及相對應的活動發生時。
系統會叫用 void (*handle_event)(void *cb_arg, int event)
事件
通知呼叫端頻道狀態變更。
[in] cb_arg
:傳遞至
tipc_create_channel()
次通話
[in] event
:可以是下列其中一個值:
TIPC_CHANNEL_CONNECTED
- 表示連線成功 遠端更新端TIPC_CHANNEL_DISCONNECTED
:表示遠端端拒絕了 或新的建立關係要求 先前連結的頻道中斷連線TIPC_CHANNEL_SHUTDOWN
- 表示遠端端已關閉, 永久終止所有連線
struct tipc_msg_buf *(*handle_msg)(void *cb_arg, struct tipc_msg_buf *mb)
叫用回呼以提供通知,告知有新訊息
獲得的觀看次數:
- [in]
cb_arg
:傳遞至tipc_create_channel()
次通話 - [in]
mb
:指向struct tipc_msg_buf
的指標 說明收到的訊息 - [retval]:回呼實作應將指標傳回至
struct tipc_msg_buf
,可能收到的相同指標 作為mb
參數 (如果訊息是在本機處理且不是 變得更加所需 可以是透過tipc_chan_get_rxbuf()
呼叫取得的新緩衝區)
tipc_chan_connect()
啟動連至指定 Trusty IPC 服務的連線。
int tipc_chan_connect(struct tipc_chan *chan, const char *port);
[in] chan
:指向
tipc_create_chan()
次通話
[in] port
:指向包含
要連線的服務名稱
[retval]:0 為成功,否則發生負錯誤
建立連線後,系統會通知來電者
handle_event
回呼。
tipc_chan_Shut()
終止與先前啟動的 Trusty IPC 服務的連線
tipc_chan_connect()
呼叫。
int tipc_chan_shutdown(struct tipc_chan *chan);
[in] chan
:指向由
tipc_create_chan()
通話
tipc_chan_destroy()
刪除指定的 Trusty IPC 頻道。
void tipc_chan_destroy(struct tipc_chan *chan);
[in] chan
:指向
tipc_create_chan()
次通話
tipc_chan_get_txbuf_timeout()
取得訊息緩衝區,以用於在特定的指定上傳送資料 頻道。如果無法立即取得緩衝區,可能會封鎖呼叫端 指定的逾時時間 (以毫秒為單位)。
struct tipc_msg_buf * tipc_chan_get_txbuf_timeout(struct tipc_chan *chan, long timeout);
[in] chan
:將訊息指向要排入佇列的管道
[in] chan
:等待的逾時時間上限
tx
緩衝區可供使用
[retval]:成功時的有效訊息緩衝區,
發生錯誤時:ERR_PTR(err)
tipc_chan_queue_msg()
將訊息排入指定的佇列 值得信賴的處理序間通訊 (IPC) 頻道。
int tipc_chan_queue_msg(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
:指向要排入佇列的訊息管道
[in] mb:
指向待佇列訊息的指標
(由 tipc_chan_get_txbuf_timeout()
呼叫取得)
[retval]:0 為成功,否則發生負錯誤
tipc_chan_put_txbuf()
釋出指定的 Tx
訊息緩衝區
先前經由 tipc_chan_get_txbuf_timeout()
呼叫取得
void tipc_chan_put_txbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
:指標指向
這個訊息緩衝區屬於
[in] mb
:指向要釋出的訊息緩衝區的指標
[retval]:無
tipc_chan_get_rxbuf()
取得新的訊息緩衝區,可用來透過 指定頻道。
struct tipc_msg_buf *tipc_chan_get_rxbuf(struct tipc_chan *chan);
[in] chan
:指向這個訊息緩衝區所屬的頻道指標
[retval]:成功時的有效訊息緩衝區,發生錯誤時則為 ERR_PTR(err)
tipc_chan_put_rxbuf()
釋出先前由
tipc_chan_get_rxbuf()
呼叫。
void tipc_chan_put_rxbuf(struct tipc_chan *chan, struct tipc_msg_buf *mb);
[in] chan
:指向這個訊息緩衝區所屬的頻道指標
[in] mb
:指向要釋出的訊息緩衝區
[retval]:無