Fuchsia 上的軟體透過與驅動程式庫元件公開的互動 在 devfs 中定義。用戶端連線至驅動程式庫的 devfs 項目後, 容器會收到代表該驅動程式庫的 FIDL 服務執行個體。
在本節中,您將建立新的 eductl
執行檔,藉此發現並
會與 qemu_edu
驅動程式庫公開的功能互動。
建立新的工具元件
在 Bazel 工作區中,為新的二進位工具建立新的專案目錄:
mkdir -p fuchsia-codelab/qemu_edu/tools
完成這個部分後,專案應具備下列目錄: 結構:
//fuchsia-codelab/qemu_edu/tools
|- BUILD.bazel
|- eductl.cc
建立 qemu_edu/tools/BUILD.bazel
檔案,並將下列陳述式新增至
包含 Fuchsia SDK 的必要建構規則:
qemu_edu/tools/BUILD.bazel
:
load(
"@fuchsia_sdk//fuchsia:defs.bzl",
"fuchsia_cc_binary",
"fuchsia_component",
"fuchsia_component_manifest",
"fuchsia_driver_tool",
"fuchsia_package",
)
使用下列程式碼建立新的 qemu_edu/tools/eductl.cc
檔案來設定
基本指令列可執行檔:
qemu_edu/tools/eductl.cc
:
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <getopt.h>
#include <lib/fdio/directory.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <filesystem>
int usage(const char* cmd) {
fprintf(stderr,
"\nInteract with the QEMU edu device:\n"
" %s live Performs a card liveness check\n"
" %s fact <n> Computes the factorial of n\n"
" %s help Print this message\n",
cmd, cmd, cmd);
return -1;
}
// Returns "true" if the argument matches the prefix.
// In this case, moves the argument past the prefix.
bool prefix_match(const char** arg, const char* prefix) {
if (!strncmp(*arg, prefix, strlen(prefix))) {
*arg += strlen(prefix);
return true;
}
return false;
}
constexpr long kBadParse = -1;
long parse_positive_long(const char* number) {
char* end;
long result = strtol(number, &end, 10);
if (end == number || *end != '\0' || result < 0) {
return kBadParse;
}
return result;
}
int main(int argc, char* argv[]) {
const char* cmd = basename(argv[0]);
// ...
return usage(cmd);
}
這個執行檔支援兩個子指令,可執行有效性檢查和 。
將下列新規則新增至專案的建構設定底部 將這個新工具建構入 Fuchsia 套件中:
qemu_edu/tools/BUILD.bazel
:
fuchsia_cc_binary(
name = "eductl",
srcs = [
"eductl.cc",
],
deps = [
"@fuchsia_sdk//pkg/component_incoming_cpp",
"@fuchsia_sdk//pkg/fdio",
"@fuchsia_sdk//pkg/fidl_cpp_wire",
],
)
fuchsia_driver_tool(
name = "eductl_tool",
binary = ":eductl",
visibility = ["//visibility:public"],
)
fuchsia_package(
name = "pkg",
package_name = "eductl",
tools = [
":eductl_tool",
],
visibility = ["//visibility:public"],
)
實作用戶端工具
當用戶端開啟 devfs 中某個項目的連線時,用戶端會收到
驅動程式庫提供的 FIDL 通訊協定在 eductl
中加入以下程式碼
使用 devfs 路徑開啟與 edu
裝置的連線:
qemu_edu/tools/eductl.cc
:
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <getopt.h>
#include <lib/fdio/directory.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <filesystem>
#include <fidl/examples.qemuedu/cpp/wire.h>
constexpr char kDevfsRootPath[] = "/dev/sys/platform";
constexpr char kEduDevicePath[] = "qemu-edu";
// Search for the device file entry in devfs
std::optional<std::string> SearchDevicePath() {
for (auto const& dir_entry : std::filesystem::recursive_directory_iterator(kDevfsRootPath)) {
if (dir_entry.path().string().find(kEduDevicePath) != std::string::npos) {
return {dir_entry.path()};
}
}
return {};
}
// Open a FIDL client connection to the examples.qemuedu.Device
fidl::WireSyncClient<examples_qemuedu::Device> OpenDevice() {
auto device_path = SearchDevicePath();
if (!device_path.has_value()) {
fprintf(stderr, "Unable to locate %s device path in search of %s/*/\n", kEduDevicePath,
kDevfsRootPath);
return {};
}
zx::result endpoints = fidl::CreateEndpoints<examples_qemuedu::Device>();
if (endpoints.is_error()) {
fprintf(stderr, "Failed to create endpoints: %s\n", endpoints.status_string());
return {};
}
if (zx_status_t status = fdio_service_connect(device_path.value().c_str(),
endpoints->server.TakeChannel().release());
status != ZX_OK) {
fprintf(stderr, "Failed to connect to device: %s\n", zx_status_get_string(status));
return {};
}
return fidl::WireSyncClient(std::move(endpoints->client));
}
// ...
新增 liveness_check()
和 compute_factorial()
函式,以使用
OpenDevice()
傳回的 examples.qemuedu/Device
FIDL 通訊協定。
最後,更新工具的 main()
函式,呼叫適當的裝置
函式,以用於指令列傳遞的引數:
qemu_edu/tools/eductl.cc
:
// ...
// Run a liveness check on the QEMU edu device.
// Returns 0 on success.
int liveness_check() {
auto client = OpenDevice();
if (!client.is_valid()) {
return -1;
}
auto liveness_check_result = client->LivenessCheck();
if (!liveness_check_result.ok()) {
fprintf(stderr, "Error: failed to get liveness check result: %s\n",
zx_status_get_string(liveness_check_result.status()));
return -1;
}
if (liveness_check_result->value()->result) {
printf("Liveness check passed!\n");
return 0;
} else {
printf("Liveness check failed!\n");
return -1;
}
}
// Compute the factorial of n using the QEMU edu device.
// Returns 0 on success.
int compute_factorial(long n) {
auto client = OpenDevice();
if (!client.is_valid()) {
return -1;
}
if (n >= std::numeric_limits<uint32_t>::max()) {
fprintf(stderr, "N is too large\n");
return -1;
}
uint32_t input = static_cast<uint32_t>(n);
auto compute_factorial_result = client->ComputeFactorial(input);
if (!compute_factorial_result.ok()) {
fprintf(stderr, "Error: failed to call compute factorial result: %s\n",
zx_status_get_string(compute_factorial_result.status()));
return -1;
}
printf("Factorial(%u) = %u\n", input, compute_factorial_result->value()->output);
return 0;
}
int main(int argc, char* argv[]) {
const char* cmd = basename(argv[0]);
// If no arguments passed, bail out after dumping
// usage information.
if (argc < 2) {
return usage(cmd);
}
const char* arg = argv[1];
if (prefix_match(&arg, "live")) {
return liveness_check();
} else if (prefix_match(&arg, "fact")) {
if (argc < 3) {
fprintf(stderr, "Expecting 1 argument\n");
return usage(cmd);
}
long n = parse_positive_long(argv[2]);
return compute_factorial(n);
}
return usage(cmd);
}
更新工具的建構設定,以依附於
examples.qemuedu
程式庫:
qemu_edu/tools/BUILD.bazel
:
fuchsia_cc_binary(
name = "eductl",
srcs = [
"eductl.cc",
],
deps = [
"//fuchsia-codelab/qemu_edu/fidl:examples.qemuedu_cc",
"@fuchsia_sdk//pkg/component_incoming_cpp",
"@fuchsia_sdk//pkg/fdio",
"@fuchsia_sdk//pkg/fidl_cpp_wire",
],
)
重新啟動模擬器
關閉所有現有的模擬器執行個體:
ffx emu stop --all
啟動新的 Fuchsia 模擬器執行個體,並啟用驅動程式庫架構:
ffx emu start core.x64 --headless
重新載入驅動程式庫
請使用 bazel run
指令建構並執行驅動程式庫元件目標:
bazel run //fuchsia-codelab/qemu_edu/drivers:pkg.component
執行該工具
使用 bazel run
指令建構及執行工具,並傳遞引數
fact 12
來計算 12 的階乘:
bazel run //fuchsia-codelab/qemu_edu/tools:pkg.eductl_tool -- fact 12
bazel run
指令會執行下列步驟:
- 建構執行檔和套件。
- 將套件發布至本機套件存放區。
- 向目標裝置註冊套件存放區。
- 使用
ffx driver run-tool
在driver_playground
中執行二進位檔 元件。
這個指令會輸出類似以下的輸出內容,其中包含計算結果 階乘:
Factorial(12) = 479001600
恭喜!你已成功連線至司機外露的服務 流量來自不同的用戶端