Google cam kết thúc đẩy công bằng chủng tộc cho Cộng đồng người da đen. Xem cách thực hiện.

Các mẫu Android gỉ

Trang này chứa thông tin về Android Logging , cung cấp ví dụ về Rust AIDL , cho bạn biết cách gọi Rust từ C và cung cấp hướng dẫn về Rust / C ++ Interop Sử dụng CXX .

Ghi nhật ký Android

Ví dụ sau đây cho thấy cách bạn có thể ghi nhật ký tin nhắn vào logcat (trên thiết bị) hoặc stdout (trên máy chủ).

Trong mô-đun Android.bp của bạn, hãy thêm libloggerliblog_rust làm phần phụ thuộc:

rust_binary {
    name: "logging_test",
    srcs: ["src/main.rs"],
    rustlibs: [
        "liblogger",
        "liblog_rust",
    ],
}

Tiếp theo, trong nguồn Rust của bạn, hãy thêm mã này:

use log::{debug, error, Level};

fn main() {
    let init_success = logger::init(
        logger::Config::default()
            .with_tag_on_device("mytag")
            .with_min_level(Level::Trace),
    );
    debug!("This is a debug message.");
    error!("Something went wrong!");
}

Nghĩa là, thêm hai phần phụ thuộc được hiển thị ở trên ( libloggerliblog_rust ), gọi phương thức init một lần (bạn có thể gọi nó nhiều lần nếu cần) và ghi nhật ký thông báo bằng các macro được cung cấp. Xem thùng ghi nhật ký để biết danh sách các tùy chọn cấu hình khả thi.

Thùng ghi nhật ký cung cấp một API để xác định những gì bạn muốn ghi nhật ký. Tùy thuộc vào việc mã đang chạy trên thiết bị hay trên máy chủ (chẳng hạn như một phần của kiểm tra phía máy chủ), các thông báo được ghi bằng android_logger hoặc env_logger .

Ví dụ về Rust AIDL

Phần này cung cấp một ví dụ kiểu Hello World về việc sử dụng AIDL với Rust.

Sử dụng phần Tổng quan về AIDL của Hướng dẫn dành cho nhà phát triển Android làm điểm bắt đầu, tạo external/rust/binder_example/aidl/com/example/android/IRemoteService.aidl với nội dung sau trong tệp IRemoteService.aidl :

// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

Sau đó, trong tệp external/rust/binder_example/aidl/Android.bp , hãy xác định mô-đun aidl_interface . Bạn phải bật phụ trợ Rust một cách rõ ràng vì nó không được bật theo mặc định.

aidl_interface {
    name: "com.example.android.remoteservice",
    srcs: [ "aidl/com/example/android/*.aidl", ],
    unstable: true, // Add during development until the interface is stabilized.
    backend: {
        rust: {
            // By default, the Rust backend is not enabled
            enabled: true,
        },
    },
}

Phần phụ trợ AIDL là một trình tạo nguồn Rust, vì vậy nó hoạt động giống như các trình tạo nguồn Rust khác và tạo ra một thư viện Rust. Mô-đun thư viện Rust được sản xuất có thể được sử dụng bởi các mô-đun Rust khác như một phần phụ thuộc. Như một ví dụ về việc sử dụng thư viện được sản xuất làm phụ thuộc, có thể định nghĩa rust_library như sau trong external/rust/binder_example/Android.bp :

rust_library {
    name: "libmyservice",
    srcs: ["src/lib.rs"],
    crate_name: "myservice",
    rustlibs: [
        "com.example.android.remoteservice-rust",
        "libbinder_rs",
    ],
}

Lưu ý rằng định dạng tên mô-đun cho thư viện do AIDL tạo được sử dụng trong rustlibs là tên mô-đun aidl_interface theo sau là -rust ; trong trường hợp này, com.example.android.remoteservice-rust .

Sau đó, giao diện AIDL có thể được tham chiếu trong src/lib.rs như sau:

// Note carefully the AIDL crates structure:
// * the AIDL module name: "com_example_android_remoteservice"
// * next "::aidl"
// * next the AIDL package name "::com::example::android"
// * the interface: "::IRemoteService"
// * finally, the 'BnRemoteService' and 'IRemoteService' submodules

//! This module implements the IRemoteService AIDL interface
use com_example_android_remoteservice::aidl::com::example::android::{
  IRemoteService::{BnRemoteService, IRemoteService}
};
use com_example_android_remoteservice::binder::{
    BinderFeatures, Interface, Result as BinderResult, Strong,
};

/// This struct is defined to implement IRemoteService AIDL interface.
pub struct MyService;

impl Interface for MyService {}

impl IRemoteService for MyService {
    fn getPid(&self) -> BinderResult<i32> {
        Ok(42)
    }

    fn basicTypes(&self, _: i32, _: i64, _: bool, _: f32, _: f64, _: &str) -> BinderResult<()> {
        // Do something interesting...
        Ok(())
    }
}

Cuối cùng, bắt đầu dịch vụ trong một tệp nhị phân Rust như hình dưới đây:

use myservice::MyService;

fn main() {
    // [...]
    let my_service = MyService;
    let my_service_binder = BnRemoteService::new_binder(
        my_service,
        BinderFeatures::default(),
    );
    binder::add_service("myservice", my_service_binder).expect("Failed to register service?");
    // Does not return - spawn or perform any work you mean to do before this call.
    binder::ProcessState::join_thread_pool()
}

Gọi Rust từ C

Ví dụ này cho thấy cách gọi Rust từ C.

Thư viện rỉ sét mẫu

Xác định tệp libsimple_printer trong external/rust/simple_printer/libsimple_printer.rs như sau:

//! A simple hello world example that can be called from C

#[no_mangle]
/// Print "Hello Rust!"
pub extern fn print_c_hello_rust() {
    println!("Hello Rust!");
}

Thư viện Rust phải xác định các tiêu đề mà các mô-đun C phụ thuộc có thể kéo vào, vì vậy hãy xác định tiêu đề external/rust/simple_printer/simple_printer.h như sau:

#ifndef SIMPLE_PRINTER_H
#define SIMPLE_PRINTER_H

void print_c_hello_rust();


#endif

Xác định external/rust/simple_printer/Android.bp như bạn thấy ở đây:

rust_ffi {
    name: "libsimple_c_printer",
    crate_name: "simple_c_printer",
    srcs: ["libsimple_c_printer.rs"],

    // Define include_dirs so cc_binary knows where the headers are.
    include_dirs: ["."],
}

Ví dụ C nhị phân

Xác định external/rust/c_hello_rust/main.c như sau:

#include "simple_printer.h"

int main() {
  print_c_hello_rust();
  return 0;
}

Xác định external/rust/c_hello_rust/Android.bp như sau:

cc_binary {
    name: "c_hello_rust",
    srcs: ["main.c"],
    shared_libs: ["libsimple_c_printer"],
}

Cuối cùng, xây dựng bằng cách gọi m c_hello_rust .

Tương tác Rust – Java

jni cung cấp khả năng tương tác Rust với Java thông qua Java Native Interface (JNI). Nó xác định các định nghĩa kiểu cần thiết cho Rust để tạo ra một thư viện Rust cdylib cắm trực tiếp vào JNI của Java ( JNIEnv , JClass , JString , v.v.). Không giống như các liên kết C ++ thực hiện codegen thông qua cxx , khả năng tương tác của Java thông qua JNI không yêu cầu bước tạo mã trong quá trình xây dựng. Do đó, nó không cần hỗ trợ hệ thống xây dựng đặc biệt. Mã Java tải cdylib Rust cung cấp giống như bất kỳ thư viện gốc nào khác.

Cách sử dụng

Cách sử dụng trong cả mã Rust và Java được đề cập trong tài liệu jni crate . Vui lòng làm theo ví dụ Bắt đầu được cung cấp ở đó. Sau khi bạn viết src/lib.rs , hãy quay lại trang này để tìm hiểu cách xây dựng thư viện với hệ thống xây dựng của Android.

Xây dựng định nghĩa

Java yêu cầu thư viện Rust phải được cung cấp dưới dạng cdylib để nó có thể được tải động. Định nghĩa thư viện Rust trong Soong như sau:

rust_ffi_shared {
    name: "libhello_jni",
    crate_name: "hello_jni",
    srcs: ["src/lib.rs"],

    // The jni crate is required
    rustlibs: ["libjni"],
}

Thư viện Java liệt kê thư viện Rust như một phụ thuộc required ; điều này đảm bảo rằng nó được cài đặt vào thiết bị cùng với thư viện Java mặc dù nó không phải là phần phụ thuộc vào thời gian xây dựng:

java_library {
        name: "libhelloworld",
        [...]
        required: ["libhellorust"]
        [...]
}

Ngoài ra, nếu bạn phải bao gồm thư viện Rust trong tệp AndroidManifest.xml , hãy thêm thư viện vào uses_libs như sau:

java_library {
        name: "libhelloworld",
        [...]
        uses_libs: ["libhellorust"]
        [...]
}

Rust-C ++ Interop bằng CXX

Thùng CXX cung cấp FFI an toàn giữa Rust và một tập hợp con của C ++. Tài liệu CXX đưa ra những ví dụ điển hình về cách nó hoạt động nói chung. Ví dụ sau đây cho thấy cách sử dụng nó trong Android.

Để CXX tạo mã C ++ mà Rust gọi vào, hãy xác định một genrule để gọi CXX và một cc_library_static để nhóm nó vào một thư viện. Nếu bạn dự định có mã Rust trong C ++ hoặc sử dụng các kiểu được chia sẻ giữa C ++ và Rust, hãy xác định kiểu gen thứ hai (để tạo tiêu đề C ++ chứa các ràng buộc Rust).

cc_library_static {
    name: "libcxx_test_cpp",
    srcs: ["cxx_test.cpp"],
    generated_headers: [
        "cxx-bridge-header",
        "libcxx_test_bridge_header"
    ],
    generated_sources: ["libcxx_test_bridge_code"],
}

genrule {
    name: "libcxx_test_bridge_code",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) >> $(out)",
    srcs: ["lib.rs"],
    out: ["libcxx_test_cxx_generated.cc"],
}

// This defines a second genrule to generate a C++ header.
// * The generated header contains the C++ bindings to the Rust exported
// * functions in lib.rs.

genrule {
    name: "libcxx_test_bridge_header",
    tools: ["cxxbridge"],
    cmd: "$(location cxxbridge) $(in) --header >> $(out)",
    srcs: ["lib.rs"],
    out: ["lib.rs.h"],
}

Sau đó, liên kết này vào thư viện Rust hoặc tệp thực thi:

rust_binary {
    name: "cxx_test",
    srcs: ["lib.rs"],
    rustlibs: ["libcxx"],
    static_libs: ["libcxx_test_cpp"],
}

Trong các tệp .cpp.hpp , hãy xác định các hàm C ++ như bạn muốn, sử dụng các loại trình bao bọc CXX như mong muốn. Ví dụ: định nghĩa cxx_test.hpp chứa những điều sau:

#pragma once

#include "rust/cxx.h"

int greet(rust::Str greetee);

Trong khi cxx_test.cpp chứa

#include "cxx_test.hpp"
#include "lib.rs.h"

#include <iostream>

int greet(rust::Str greetee) {
  std::cout << "Hello, " << greetee << std::endl;
  return get_num();
}

Để sử dụng điều này từ Rust, hãy xác định cầu nối CXX như bên dưới trong lib.rs :

#[cxx::bridge]
mod ffi {
    unsafe extern "C++" {
        include!("cxx_test.hpp");
        fn greet(greetee: &str) -> i32;
    }
    extern "Rust" {
        fn get_num() -> i32;
    }
}

fn main() {
    let result = ffi::greet("world");
    println!("C++ returned {}", result);
}

fn get_num() -> i32 {
    return 42;
}