Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

안드로이드 러스트 패턴

이 페이지에 대한 정보가 들어 안드로이드 로깅을 하는 제공 녹 AIDL의 예를 , 다음 방법을 설명 C에서 녹 전화 및 지침 제공 녹 / C ++ 상호 운용성이 CXX를 사용하여 .

안드로이드 로깅

당신이 메시지를 기록 할 수있는 방법 다음 예제 프로그램 logcat (온 - 디바이스) 또는 stdout (온 호스트).

당신에 Android.bp 모듈 추가 libloggerliblog_rust 의존성과 같이

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

다음으로, Rust 소스에 다음 코드를 추가하세요:

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!");
}

즉, (위에 표시된 두 개의 종속 추가 libloggerliblog_rust ) 호출 init 방법을 한 번 (당신이 필요한 경우 한 번 이상 호출 할 수 있습니다), 그리고 제공하는 매크로를 사용하여 메시지를 기록합니다. 참고 항목 로거 상자 구성 옵션의 목록을.

로거 크레이트는 기록하려는 항목을 정의하기 위한 API를 제공합니다. 코드 장치 또는 호스트에서 실행 여부 (호스트 측의 테스트와 같은 일부)에 따라 메시지는 하나하여 로그온 android_logger 또는 env_logger .

Rust AIDL 예제

이 섹션에서는 Rust와 함께 AIDL을 사용하는 Hello World 스타일의 예를 제공합니다.

안드로이드 개발자 가이드 사용 AIDL 개요 , 시작 지점으로 섹션을 만들 external/rust/binder_example/aidl/com/example/android/IRemoteService.aidl 에서 다음 내용을 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);
}

그리고, 내 external/rust/binder_example/aidl/Android.bp 파일의 정의 aidl_interface 모듈. 그것은 기본적으로 사용되지 않기 때문에 명시 적으로 녹 백엔드를 사용하도록 설정해야합니다.

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,
        },
    },
}

AIDL 백엔드는 Rust 소스 생성기이므로 다른 Rust 소스 생성기처럼 작동하고 Rust 라이브러리를 생성합니다. 생성된 Rust 라이브러리 모듈은 다른 Rust 모듈에서 종속성으로 사용할 수 있습니다. 종속성으로 제조 된 라이브러리를 사용하는 예로서, rust_library 다음과 같이 정의 될 수 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",
    ],
}

사용되는 AIDL 생성 라이브러리 모듈 이름 형식 유의 rustlibs 는 IS aidl_interface 다음 모듈 이름 -rust ; 이 경우에 com.example.android.remoteservice-rust .

AIDL 인터페이스는 다음에서 참조 할 수있다 src/lib.rs 다음과 같다 :

// 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(())
    }
}

마지막으로 아래와 같이 Rust 바이너리에서 서비스를 시작합니다.

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()
}

C에서 Rust 호출하기

이 예제는 C에서 Rust를 호출하는 방법을 보여줍니다.

Rust 라이브러리의 예

정의 libsimple_printer 에서 파일을 external/rust/simple_printer/libsimple_printer.rs 다음과 같이 :

//! 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!");
}

녹 라이브러리 그렇게 정의 종속 C 모듈에서 뽑을 수 헤더를 정의해야 external/rust/simple_printer/simple_printer.h 헤더를 다음과 같이

#ifndef SIMPLE_PRINTER_H
#define SIMPLE_PRINTER_H

void print_c_hello_rust();


#endif

정의 external/rust/simple_printer/Android.bp 당신이 여기에서 보는 바와 같이 :

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: ["."],
}

예제 C 바이너리

정의 external/rust/c_hello_rust/main.c 다음과 같이 :

#include "simple_printer.h"

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

정의 external/rust/c_hello_rust/Android.bp 다음과 같이 :

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

마지막으로 호출하여 빌드 m c_hello_rust .

러스트-자바 상호 운용성

jni 상자는 자바 네이티브 인터페이스 (JNI)를 통해 자바 녹 상호 운용성을 제공합니다. 녹는 녹 생성하는 것이 필요한 유형 정의를 정의 cdylib 이 직접 자바의 JNI에 플러그 (라이브러리 JNIEnv , JClass , JString , 등). 를 통해 CODEGEN 실시합니다 C ++ 바인딩과는 달리 cxx , JNI를 통해 자바 상호 운용성은 빌드시 코드 생성 단계를 필요로하지 않는다. 따라서 특별한 빌드 시스템 지원이 필요하지 않습니다. 자바 코드로드 녹 제공 cdylib 다른 네이티브 라이브러리있다.

용법

모두 녹 및 Java 코드의 사용은에 덮여 jni 상자 문서 . 추적하십시오 시작 이 제공 예. 당신이 쓰는 후 src/lib.rs ,이 페이지로 돌아 안드로이드의 빌드 시스템 라이브러리를 구축하는 방법을 배울 수 있습니다.

빌드 정의

자바가 제공 될 녹 라이브러리가 필요 cdylib 가 동적으로로드 할 수 있도록합니다. Soong의 Rust 라이브러리 정의는 다음과 같습니다.

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

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

자바 라이브러리 나열로 녹 라이브러리 required 의존성; 이렇게 하면 빌드 타임 종속성이 아니더라도 Java 라이브러리와 함께 장치에 설치됩니다.

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

당신이에서 녹 라이브러리를 포함해야하는 경우 또는 AndroidManifest.xml 파일에 라이브러리를 추가 uses_libs 다음과 같다 :

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

CXX를 사용한 Rust–C++ Interop

CXX의 상자는 녹 및 C ++의 부분 집합 사이의 안전 FFI을 제공합니다. CXX 설명서 는 일반적으로 작동하는 방법의 좋은 예를 제공합니다. 다음 예제는 Android에서 사용하는 방법을 보여줍니다.

CXX이 녹를 호출하는 C ++ 코드를 생성해야하기 위해, 정의 genrule CXX하고 호출에 cc_library_static 라이브러리로 그 번들 할 수 있습니다. C++에서 Rust 코드를 호출하거나 C++와 Rust 간에 공유되는 유형을 사용하려는 경우 두 번째 일반 규칙을 정의하십시오(Rust 바인딩을 포함하는 C++ 헤더를 생성하기 위해).

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"],
}

그런 다음 이것을 Rust 라이브러리나 실행 파일에 연결하세요:

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

에서 .cpp.hpp 당신이 원하는대로 파일의 사용하여 C ++ 함수를 정의 유형의 래퍼 CXX을 원하는대로. 예를 들어, cxx_test.hpp 정의는 다음을 포함합니다

#pragma once

#include "rust/cxx.h"

int greet(rust::Str greetee);

하지만 cxx_test.cpp 포함

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

#include <iostream>

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

녹에서이를 사용하려면에서 아래로 CXX 브리지를 정의 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;
}