Skip to content

Commit f5f2c6b

Browse files
authored
Binder/AIDL content updates (google#1618)
1 parent 4d0f23e commit f5f2c6b

27 files changed

+612
-111
lines changed

src/SUMMARY.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,21 @@
212212
- [Binary](android/build-rules/binary.md)
213213
- [Library](android/build-rules/library.md)
214214
- [AIDL](android/aidl.md)
215-
- [Interface](android/aidl/interface.md)
216-
- [Implementation](android/aidl/implementation.md)
217-
- [Server](android/aidl/server.md)
218-
- [Deploy](android/aidl/deploy.md)
219-
- [Client](android/aidl/client.md)
220-
- [Changing API](android/aidl/changing.md)
215+
- [Birthday Service Tutorial](android/aidl/birthday-service.md)
216+
- [Interface](android/aidl/example-service/interface.md)
217+
- [Service API](android/aidl/example-service/service-bindings.md)
218+
- [Service](android/aidl/example-service/service.md)
219+
- [Server](android/aidl/example-service/server.md)
220+
- [Deploy](android/aidl/example-service/deploy.md)
221+
- [Client](android/aidl/example-service/client.md)
222+
- [Changing API](android/aidl/example-service/changing-definition.md)
223+
- [Updating Implementations](android/aidl/example-service/changing-implementation.md)
224+
- [AIDL Types](android/aidl/types.md)
225+
- [Primitive Types](android/aidl/types/primitives.md)
226+
- [Array Types](android/aidl/types/arrays.md)
227+
- [Sending Objects](android/aidl/types/objects.md)
228+
- [Parcelables](android/aidl/types/parcelables.md)
229+
- [Sending Files](android/aidl/types/file-descriptor.md)
221230
- [Logging](android/logging.md)
222231
- [Interoperability](android/interoperability.md)
223232
- [With C](android/interoperability/with-c.md)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Birthday Service Tutorial
2+
3+
To illustrate how to use Rust with Binder, we're going to walk through the
4+
process of creating a Binder interface. We're then going to both implement the
5+
described service and write client code that talks to that service.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.example.birthdayservice;
2+
3+
parcelable BirthdayInfo {
4+
String name;
5+
int years;
6+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// ANCHOR: IBirthdayInfoProvider
16+
package com.example.birthdayservice;
17+
18+
interface IBirthdayInfoProvider {
19+
String name();
20+
int years();
21+
}

src/android/aidl/birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,33 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
// ANCHOR: IBirthdayService
1615
package com.example.birthdayservice;
1716

17+
import com.example.birthdayservice.IBirthdayInfoProvider;
18+
import com.example.birthdayservice.BirthdayInfo;
19+
20+
// ANCHOR: IBirthdayService
1821
/** Birthday service interface. */
1922
interface IBirthdayService {
2023
/** Generate a Happy Birthday message. */
2124
String wishHappyBirthday(String name, int years);
25+
// ANCHOR_END: IBirthdayService
26+
27+
// ANCHOR: with_info
28+
/** The same thing, but with a parcelable. */
29+
String wishWithInfo(in BirthdayInfo info);
30+
// ANCHOR_END: with_info
31+
32+
// ANCHOR: with_info_provider
33+
/** The same thing, but using a binder object. */
34+
String wishWithProvider(IBirthdayInfoProvider provider);
35+
36+
/** The same thing, but using `IBinder`. */
37+
String wishWithErasedProvider(IBinder provider);
38+
// ANCHOR_END: with_info_provider
39+
40+
// ANCHOR: with_file
41+
/** The same thing, but loads info from a file. */
42+
String wishFromFile(in ParcelFileDescriptor infoFile);
43+
// ANCHOR_END: with_file
2244
}

src/android/aidl/birthday_service/src/client.rs

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,87 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
// ANCHOR: main
1615
//! Birthday service.
16+
use com_example_birthdayservice::aidl::com::example::birthdayservice::BirthdayInfo::BirthdayInfo;
17+
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayInfoProvider::{
18+
BnBirthdayInfoProvider, IBirthdayInfoProvider,
19+
};
1720
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService;
18-
use com_example_birthdayservice::binder;
21+
use com_example_birthdayservice::binder::{self, BinderFeatures, ParcelFileDescriptor};
22+
use std::error::Error;
23+
use std::fs::File;
24+
use std::io::prelude::*;
1925

26+
// ANCHOR: main
2027
const SERVICE_IDENTIFIER: &str = "birthdayservice";
2128

22-
/// Connect to the BirthdayService.
23-
pub fn connect() -> Result<binder::Strong<dyn IBirthdayService>, binder::StatusCode>
24-
{
25-
binder::get_interface(SERVICE_IDENTIFIER)
26-
}
27-
2829
/// Call the birthday service.
29-
fn main() -> Result<(), binder::Status> {
30+
fn main() -> Result<(), Box<dyn Error>> {
3031
let name = std::env::args().nth(1).unwrap_or_else(|| String::from("Bob"));
3132
let years = std::env::args()
3233
.nth(2)
3334
.and_then(|arg| arg.parse::<i32>().ok())
3435
.unwrap_or(42);
3536

3637
binder::ProcessState::start_thread_pool();
37-
let service = connect().expect("Failed to connect to BirthdayService");
38+
let service = binder::get_interface::<dyn IBirthdayService>(SERVICE_IDENTIFIER)
39+
.map_err(|_| "Failed to connect to BirthdayService")?;
40+
41+
// Call the service.
3842
let msg = service.wishHappyBirthday(&name, years)?;
3943
println!("{msg}");
44+
// ANCHOR_END: main
45+
46+
// ANCHOR: wish_with_info
47+
service.wishWithInfo(&BirthdayInfo { name: name.clone(), years })?;
48+
// ANCHOR_END: wish_with_info
49+
50+
// ANCHOR: wish_with_provider
51+
52+
// Create a binder object for the `IBirthdayInfoProvider` interface.
53+
let provider = BnBirthdayInfoProvider::new_binder(
54+
InfoProvider { name: name.clone(), age: years as u8 },
55+
BinderFeatures::default(),
56+
);
57+
58+
// Send the binder object to the service.
59+
service.wishWithProvider(&provider)?;
60+
61+
// Perform the same operation but passing the provider as an `SpIBinder`.
62+
service.wishWithErasedProvider(&provider.as_binder())?;
63+
// ANCHOR_END: wish_with_provider
64+
65+
// ANCHOR: wish_with_file
66+
67+
// Open a file and put the birthday info in it.
68+
let mut file = File::create("/data/local/tmp/birthday.info").unwrap();
69+
writeln!(file, "{name}")?;
70+
writeln!(file, "{years}")?;
71+
72+
// Create a `ParcelFileDescriptor` from the file and send it.
73+
let file = ParcelFileDescriptor::new(file);
74+
service.wishFromFile(&file)?;
75+
// ANCHOR_END: wish_with_file
76+
4077
Ok(())
4178
}
79+
80+
// ANCHOR: InfoProvider
81+
/// Rust struct implementing the `IBirthdayInfoProvider` interface.
82+
struct InfoProvider {
83+
name: String,
84+
age: u8,
85+
}
86+
87+
impl binder::Interface for InfoProvider {}
88+
89+
impl IBirthdayInfoProvider for InfoProvider {
90+
fn name(&self) -> binder::Result<String> {
91+
Ok(self.name.clone())
92+
}
93+
94+
fn years(&self) -> binder::Result<i32> {
95+
Ok(self.age as i32)
96+
}
97+
}
98+
// ANCHOR_END: InfoProvider

src/android/aidl/birthday_service/src/lib.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
// ANCHOR: IBirthdayService
1615
//! Implementation of the `IBirthdayService` AIDL interface.
16+
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayInfoProvider::IBirthdayInfoProvider;
1717
use com_example_birthdayservice::aidl::com::example::birthdayservice::IBirthdayService::IBirthdayService;
18-
use com_example_birthdayservice::binder;
18+
use com_example_birthdayservice::aidl::com::example::birthdayservice::BirthdayInfo::BirthdayInfo;
19+
use com_example_birthdayservice::binder::{self, ParcelFileDescriptor, SpIBinder, Strong};
20+
use std::fs::File;
21+
use std::io::Read;
1922

23+
// ANCHOR: IBirthdayService
2024
/// The `IBirthdayService` implementation.
2125
pub struct BirthdayService;
2226

@@ -26,4 +30,63 @@ impl IBirthdayService for BirthdayService {
2630
fn wishHappyBirthday(&self, name: &str, years: i32) -> binder::Result<String> {
2731
Ok(format!("Happy Birthday {name}, congratulations with the {years} years!"))
2832
}
33+
// ANCHOR_END: IBirthdayService
34+
35+
fn wishWithInfo(&self, info: &BirthdayInfo) -> binder::Result<String> {
36+
Ok(format!(
37+
"Happy Birthday {}, congratulations with the {} years!",
38+
info.name, info.years,
39+
))
40+
}
41+
42+
fn wishWithProvider(
43+
&self,
44+
provider: &Strong<dyn IBirthdayInfoProvider>,
45+
) -> binder::Result<String> {
46+
Ok(format!(
47+
"Happy Birthday {}, congratulations with the {} years!",
48+
provider.name()?,
49+
provider.years()?,
50+
))
51+
}
52+
53+
fn wishWithErasedProvider(
54+
&self,
55+
provider: &SpIBinder,
56+
) -> binder::Result<String> {
57+
// Convert the `SpIBinder` to a concrete interface.
58+
let provider =
59+
provider.clone().into_interface::<dyn IBirthdayInfoProvider>()?;
60+
61+
Ok(format!(
62+
"Happy Birthday {}, congratulations with the {} years!",
63+
provider.name()?,
64+
provider.years()?,
65+
))
66+
}
67+
68+
// ANCHOR: wishFromFile
69+
fn wishFromFile(
70+
&self,
71+
info_file: &ParcelFileDescriptor,
72+
) -> binder::Result<String> {
73+
// Convert the file descriptor to a `File`. `ParcelFileDescriptor` wraps
74+
// an `OwnedFd`, which can be cloned and then used to create a `File`
75+
// object.
76+
let mut info_file = info_file
77+
.as_ref()
78+
.try_clone()
79+
.map(File::from)
80+
.expect("Invalid file handle");
81+
82+
let mut contents = String::new();
83+
info_file.read_to_string(&mut contents).unwrap();
84+
85+
let mut lines = contents.lines();
86+
let name = lines.next().unwrap();
87+
let years: i32 = lines.next().unwrap().parse().unwrap();
88+
89+
Ok(format!("Happy Birthday {name}, congratulations with the {years} years!"))
90+
}
91+
// ANCHOR_END: wishFromFile
2992
}

src/android/aidl/changing.md

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/android/aidl/client.md

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Changing API
2+
3+
Let us extend the API with more functionality: we want to let clients specify a
4+
list of lines for the birthday card:
5+
6+
```java
7+
package com.example.birthdayservice;
8+
9+
/** Birthday service interface. */
10+
interface IBirthdayService {
11+
/** Generate a Happy Birthday message. */
12+
String wishHappyBirthday(String name, int years, in String[] text);
13+
}
14+
```
15+
16+
This results in an updated trait definition for `IBirthdayService`:
17+
18+
```rust,ignore
19+
trait IBirthdayService {
20+
fn wishHappyBirthday(
21+
&self,
22+
name: &str,
23+
years: i32,
24+
text: &[String],
25+
) -> binder::Result<String>;
26+
}
27+
```
28+
29+
<details>
30+
31+
- Note how the `String[]` in the AIDL definition is translated as a `&[String]`
32+
in Rust, i.e. that idiomatic Rust types are used in the generated bindings
33+
wherever possible:
34+
- `in` array arguments are translated to slices.
35+
- `out` and `inout` args are translated to `&mut Vec<T>`.
36+
- Return values are translated to returning a `Vec<T>`.
37+
38+
</details>

0 commit comments

Comments
 (0)