From 6c80251c3b3362368d14e7eed0fb0f8620b7aa0f Mon Sep 17 00:00:00 2001 From: gary-wzl77 Date: Thu, 21 Nov 2024 11:30:54 +0800 Subject: [PATCH] feat(exchange-oob-data): polish the out-of-band-v2 chapter Polish the out-of-band-v2 chapter and to resolve the comments in the https://github.com/canonical/anbox-cloud-docs/pull/223 PR --- howto/stream/exchange-oob-data.md | 230 +++++++++++++++++++----------- 1 file changed, 145 insertions(+), 85 deletions(-) diff --git a/howto/stream/exchange-oob-data.md b/howto/stream/exchange-oob-data.md index 101472b0..bcab5ba4 100644 --- a/howto/stream/exchange-oob-data.md +++ b/howto/stream/exchange-oob-data.md @@ -9,9 +9,9 @@ Anbox Cloud provides two versions of this OOB data exchange: * [Version 2](#version-2) provides a full-duplex bidirectional data transmission mode in which data can flow in both directions at the same time. Use this version if you start your implementation now. If you already have an existing implementation, you should plan to update it to use version 2. -* [Version 1](#version-1) enables Android application developers to trigger an action from an Android application running in an instance and forward it to a WebRTC client through the Anbox WebRTC platform. When Anbox receives the action, as one peer of the WebRTC platform, the action is propagated from Anbox to the remote peer (the WebRTC client) through a WebRTC data channel. The client can then react to the action received from the remote peer and respond accordingly on the UI. +* [Version 1](#version-1) enables Android application developers to trigger an action from an Android application running in an instance and forward it to a WebRTC client through the Anbox runtime. When Anbox receives the action, as one peer of the WebRTC platform, the action is propagated from Anbox to the remote peer (the WebRTC client) through a WebRTC data channel. The client can then react to the action received from the remote peer and respond accordingly on the UI. - This version supports only half-duplex data transmission. It allows sending data from an Android application to a WebRTC client through the Anbox WebRTC platform, but it is not possible to receive data from the WebRTC client to an Android application. + This version supports only half-duplex data transmission. It allows sending data from an Android application to a WebRTC client through the Anbox runtime, but it is not possible to receive data from the WebRTC client to an Android application. ```{caution} The support for [version 1](#version-1) of the out-of-band data exchange between an Android application and a WebRTC client has been removed in the Anbox Cloud 1.16 release. Therefore, you should migrate your integration of version 1 of the OOB data exchange to [version 2](#version-2) for full-duplex data transmission and better performance. @@ -24,62 +24,93 @@ The following instructions guide you to exchange OOB data using a specific imple The following instructions will walk you through how to set up data channels and perform data transmission in both directions between an Android application and a WebRTC platform. -Before proceeding, ensure that you have set up a web-based streaming client using the Anbox Cloud streaming stack. If you haven't done so, please follow our setup [guide](https://documentation.ubuntu.com/anbox-cloud/en/latest/tutorial/stream-client/). - ### Prepare your web application -In your web-based client application, import the {ref}`sec-streaming-sdk`. +This guide builds upon the [streaming client setup tutorial](https://documentation.ubuntu.com/anbox-cloud/en/latest/tutorial/stream-client/) for Anbox Cloud. Ensure you have completed the setup of a web-based streaming client as described in the tutorial before proceeding. + +#### Extend `AnboxStream` Configuration -Create a data channel (named `foo` in the following example) under the `dataChannels` property of an `AnboxStream` object and register event handlers that respond to the events sent from an Android application: +Following the tutorial's [step](https://documentation.ubuntu.com/anbox-cloud/en/latest/tutorial/stream-client/#implement-the-stream-client) to create an AnboxStream object, add the `dataChannels` property to define a new data channel. For example: ``` -let stream = new AnboxStream({ - ... - ... - dataChannels: { - "foo": { - callbacks: { - close: () => { - console.log('data channel is closed') - }, - open: () => { - console.log('data channel is open') - }, - error: (err) => { - console.log(`error: ${err}`) - }, - message: (data) => { - console.log(`data received: ${data}`) - } - } - } - } -}); + +
+
+ + +
+ + + + ``` +1. This extend a `AnboxStream` object to create a data channel named `foo` and registers event handlers for data communication between the Anbox instance and web client. +2. It also adds a new `div` to the web page, containing an input field for typing a message and a button to send the message over the `foo` channel to Anbox runtime. + + ```{note} An `AnboxStream` object can create a maximum of five data channels. If the number of data channels exceeds the allowed maximum, an exception is thrown when instantiating the `AnboxStream` object. ``` -To launch a new WebRTC session, the client must call `stream.connect()`. The `AnboxStream` object then builds up a WebRTC native data channel internally, based on the name declared under its `dataChannels` property for peer-to-peer communication (`foo` in the example). +### Data exchange between Anbox runtime and web client -To send data to an Android application through the channel, the client must use the member function `sendData` of the `AnboxStream` class: +Launch a stream-enabled instance ``` -stream.sendData('foo', 'hello world'); +amc launch --name test-app \ + --raw jammy:android12:amd64 \ + --enable-streaming ``` +Once the instance is up and running, retrieve the session id: -### Anbox WebRTC platform + amc ls --filter name=test-app --format=csv | awk -F',' '{split($6, r, "="); print r[2]}' -When establishing a peer connection, a number of data channels are set up in the Anbox WebRTC platform on the server side, upon request by the client. +Replace `` with the session ID retrieved earlier in the streaming client. Next, launch your web client. Once the webpage is fully loaded, it establishs a WebRTC connection to the active session. After the WebRTC peer connection is successfully made, the `foo` data channel will be created on the Anbox runtime server side, in response to the client's request. -At the same time, a number of Unix domain sockets are created under the `/run/user/1000/anbox/sockets` folder. They use the format `webrtc_data_` and represent the established communication bridge between a WebRTC client and the Anbox WebRTC platform. Those Unix domain sockets can be used by a service or daemon to: +At the same time, a Unix domain socket is created under the `/run/user/1000/anbox/sockets` folder in the format of `webrtc_data_` (`webrtc_data_foo` in the example) and represent the established communication bridge between a WebRTC client and the Anbox runtime. This Unix domain socket can be used by a service or daemon to: - Receive data sent from a WebRTC client over the data channel and forward it to an Android application. - Receive data sent from an Android application and forward it to a WebRTC client over the data channel. -A trivial example to simulate the data transmission between an instance and a WebRTC client is using the [`socat`](https://manpages.ubuntu.com/manpages/bionic/man1/socat.1.html) command to connect the Unix domain socket and perform bidirectional asynchronous data sending and receiving: +To simulate data transmission between the Anbox runtime and the web client, you can use the [`socat`](https://manpages.ubuntu.com/manpages/bionic/man1/socat.1.html) command to connect the Unix domain socket and perform bidirectional asynchronous data sending and receiving: 1. Connect the Unix domain socket: @@ -87,20 +118,16 @@ A trivial example to simulate the data transmission between an instance and a We socat - UNIX-CONNECT:/run/user/1000/anbox/sockets/webrtc_data_foo ``` -1. After the Unix domain socket is connected, type a message and hit the `Enter` key: +1. This command establishes a connection to the `webrtc_data_foo` Unix domain socket, allowing you to send and receive data directly through the established data channel between Anbox runtime and the web client. After the Unix domain socket is connected, type a message and hit the `Enter` key: hello world - The data is now sent from the Anbox WebRTC platform over the data channel to the WebRTC client. -1. Observe that the message is displayed in the console of a web browser, responding to the message event: + The data is now sent from the Anbox runtime over the data channel to the web client. +1. Observe that the message is displayed in the console of a web client, responding to the message event: data received: hello world -1. To test the other direction of the communication, send a message from a WebRTC client to the Anbox WebRTC platform through the data channel: - - ``` - session.sendData('foo', 'anbox cloud') - ``` +1. To test the other direction of the communication, in the web client, type `anbox cloud` and click the `Send` button to send the message over the `foo` data channel to the Anbox runtime. 1. Observe that the received data is printed out in the `socat` TCP session: @@ -110,19 +137,24 @@ A trivial example to simulate the data transmission between an instance and a We anbox cloud <-- the received data ``` -### Anbox WebRTC data proxy +This enables data exchange between a service running on the Anbox instance and the web client. However, it does not yet facilitate data exchange between an Android application running inside the Android container and the web client. -To build up the communication bridge between an Android application and the Anbox WebRTC platform, Anbox Cloud provides a system daemon named `anbox-webrtc-data-proxy`. This daemon is responsible for: +### Data exchange between Android application and web client + +To build up the communication bridge between an Android application and the web client, Anbox Cloud provides a system daemon named `anbox-webrtc-data-proxy`. This daemon is responsible for: + + * Registering a system service named `org.anbox.webrtc.IDataProxyService` in Android container * Accepting connection requests from an Android application - * Connecting to one specific data channel via the Unix domain socket exposed by the Anbox WebRTC platform + * Connecting to one specific data channel via the Unix domain socket exposed by the Anbox runtime * Passing the connected socket as a file descriptor to the Android application -The `anbox-webrtc-data-proxy` system daemon runs in the instance and registers an Android system service named `org.anbox.webrtc.IDataProxyService`. This service allows Android developers to easily make use of binder interprocess communication (IPC) for data communication between an Android application and the Anbox WebRTC platform through a file descriptor. +This allows Android developers to easily make use of binder interprocess communication (IPC) for data communication between an Android application and the Anbox runtime through a file descriptor, enabling further data exchange with the web client. + #### Get notified about the availability of data channels -To get notified about the availability of data channels, an Android application can register the following broadcast receiver in the `AndroidManifest.xml` file: +To receive notifications about the availability of data channels, your Android application should register the following broadcast receiver in the `AndroidManifest.xml` file: ``` { @@ -259,13 +291,13 @@ public class DataReadTask extends AsyncTask { } ``` -#### Send data to the Anbox WebRTC platform +#### Send data to the Anbox runtime -To send data to the Anbox WebRTC platform through the file descriptor: +To send data to the Anbox runtime platform through the file descriptor: ``` -OutputStream ostream = new FileOutputStream(mFd.getFileDescriptor()); try { + OutputStream ostream = new FileOutputStream(mFd.getFileDescriptor()); ostream.write(data.getBytes(), 0, data.length()); } catch (IOException ex) { Log.i(TAG, "Failed to write data: " + ex.getMessage()); @@ -273,38 +305,58 @@ try { } ``` + +For a complete Android example, see the [out_of_band_v2](https://github.com/canonical/anbox-streaming-sdk/tree/master/examples/android/out_of_band_v2) project. + #### Install the APK as system app To connect the data channel to the Anbox WebRTC data proxy service within an Android container, the Android app must be installed and running as a system app. To do so, proceed with the following steps: -1. Add the attribute `android:sharedUserId="android.uid.system"` into the `` tag in the `AndroidManifest.xml` file of your Android app -2. Create an addon to install your APK as a system app through the pre-start hook with the following content: - ``` - #!/bin/bash -ex - - # Only install the APK as a system app when bootstrapping an application. - if [ "$INSTANCE_TYPE" = "regular" ]; then - exit 0 - fi - - aam install-system-app \ - --apk="${ADDON_DIR}"/app.apk \ - --permissions= \ - --package-name= - --access-hidden-api - ``` +1. Add the attribute `android:sharedUserId="android.uid.system"` to the `` tag in the `AndroidManifest.xml` file of your Android app, then build your application. +1. Create an Addon to install your apk as system App + - First, create a directory for your addon. Inside this directory, create a manifest.yaml file that defines your addon. - See [How to install an APK as a system app](https://documentation.ubuntu.com/anbox-cloud/en/latest/howto/port/install-apk-system-app/#howto-install-apk-system-app) for details. + ``` + name: install-system-app + description: Install APK as a system app through the pre-start hook + ``` -3. Navigate to the addon directory and add it to AMS: - ``` - amc addon add install-out-of-band-app . - ``` + - Place the your APK in the same directory, create a `pre-start` hook under the `hooks` foler with the following content: + + ``` + #!/bin/bash -ex + + # Only install the APK as a system app when bootstrapping an application. + if [ "$INSTANCE_TYPE" = "regular" ]; then + exit 0 + fi + + aam install-system-app \ + --apk="${ADDON_DIR}"/ \ + --permissions= \ + --package-name= + --access-hidden-api + ``` + + - Make sure the `pre-start` hook is executable: + + ``` + chmod +x hooks/pre-start + ``` + + - Navigate to the addon root folder and add it to AMS: + + ``` + amc addon add install-system-app . + ``` + + See [How to install an APK as a system app](https://documentation.ubuntu.com/anbox-cloud/en/latest/howto/port/install-apk-system-app/#howto-install-apk-system-app) for details. #### Run end-to-end test To launch a stream-enabled instance with the addon you created, run: ``` -amc launch --raw jammy:android12:amd64 \ +amc launch --name test-oobv2 \ + --raw jammy:android12:amd64 \ --enable-streaming \ --features allow_custom_system_signatures \ --addons install-out-of-band-app @@ -314,15 +366,23 @@ amc launch --raw jammy:android12:amd64 \ Enabling the `allow_custom_system_signatures` feature is required to run the Android application as a system app in an Android container. ``` -Once the session is active: +In the [Anbox Streaming SDK](https://github.com/canonical/anbox-streaming-sdk), there is an [out_of_band_v2](https://github.com/canonical/anbox-streaming-sdk/tree/master/examples/android/out_of_band_v2) project. You can either: +- compile and modify the example application to meet your needs. +- use the prebuilt out-of-band v2 APK from the [release tarball](https://github.com/canonical/anbox-streaming-sdk/releases) for a quicker test of the functionality. -1. Use the web client, which creates a custom data channel `foo` to initiate the WebRTC connection. -2. After the WebRTC connection is established, verify that the Android application receives a notification indicating the availability of the `foo` data channel. -3. Confirm that the Android application can connect to the `foo` data channel created by the web client. -4. Send messages from either the Android application or the WebRTC client, and ensure that the messages are successfully sent and and received over the `foo` data channel. +The following instructions use an APK built from this example for end-to-end testing. To do so: + 1. Use the out-of-band v2 APK in the above addon creation. + 1. Launch a stream-enabled instance with the addon created as mentioned above. + 1. Retrieve the session id that asssoicated to the `test-oobv2` instance + + amc ls --filter name=test-oobv2 --format=csv | awk -F',' '{split($6, r, "="); print r[2]}' + + 1. To join the session, make sure to replace `` the session ID retrieved above in the stream client. + 1. Launch the stream client that extends to [create the `foo` data channel](https://documentation.ubuntu.com/anbox-cloud/en/latest/howto/stream/exchange-oob-data/#prepare-your-web-application) upon establishing a WebRTC connection. + 1. Once the WebRTC connection is connect, open the Out of Band v2 application in the Android container. enter 'foo' as the channel name in the line edit widget, then click the `CONNECT` button. Check if a toast message saying 'Channel "foo" is connected' appears. + 1. Next, in the edit text widget, enter 'hello' as the text and click the `SEND` button. In the web client console, verify if the message is printed. + 1. In the web client, type 'world' in the text box and click `Send` button, Then, check the Android application to see if the message appears in the 'Received Data' edit box. - -For a complete Android example, see the [out_of_band_v2](https://github.com/canonical/anbox-streaming-sdk/tree/master/examples/android/out_of_band_v2) project. (sec-oob-data-version-1)= ## Version 1 : half-duplex unidirectional data