1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <inttypes.h>
18 #include <utils/StrongPointer.h>
19 #include <chrono>
20 #include <cstdint>
21 #include <future>
22 #include <thread>
23
24 #include "chre/util/nanoapp/app_id.h"
25 #include "chre_host/host_protocol_host.h"
26 #include "chre_host/log.h"
27 #include "chre_host/pigweed/hal_rpc_client.h"
28 #include "chre_host/socket_client.h"
29 #include "rpc_world.pb.h"
30 #include "rpc_world.rpc.pb.h"
31
32 /**
33 * @file
34 * Test RPC by calling a service provided by the rpc_world nanoapp.
35 *
36 * Usage:
37 * 1. Compile and push the rpc_world nanoapp to the device.
38 *
39 * 2. Load the nanoapp:
40 * adb shell chre_test_client load_with_header \
41 * /vendor/etc/chre/rpc_world.napp_header \
42 * /vendor/etc/chre/rpc_world.so
43 *
44 * 3. Build this test and push it to the device:
45 * m chre_test_rpc
46 * adb push \
47 * out/target/product/<product>/vendor/bin/chre_test_rpc \
48 * /vendor/bin/chre_test_rpc
49 *
50 * 4. Launch the test:
51 * adb shell chre_test_rpc
52 */
53
54 namespace {
55
56 using ::android::sp;
57 using ::android::chre::HalRpcClient;
58 using ::android::chre::HostProtocolHost;
59 using ::android::chre::IChreMessageHandlers;
60 using ::android::chre::SocketClient;
61 using ::flatbuffers::FlatBufferBuilder;
62
63 // Aliased for consistency with the way these symbols are referenced in
64 // CHRE-side code
65 namespace fbs = ::chre::fbs;
66
67 constexpr uint16_t kHostEndpoint = 0x8006;
68
69 constexpr uint32_t kRequestNumber = 10;
70 std::promise<uint32_t> gResponsePromise;
71
72 class SocketCallbacks : public SocketClient::ICallbacks,
73 public IChreMessageHandlers {
74 public:
onMessageReceived(const void * data,size_t length)75 void onMessageReceived(const void *data, size_t length) override {
76 if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
77 LOGE("Failed to decode message");
78 }
79 }
80
handleNanoappListResponse(const fbs::NanoappListResponseT & response)81 void handleNanoappListResponse(
82 const fbs::NanoappListResponseT &response) override {
83 LOGI("Got nanoapp list response with %zu apps", response.nanoapps.size());
84 }
85 };
86
87 } // namespace
88
incrementResponse(const chre_rpc_NumberMessage & response,pw::Status status)89 void incrementResponse(const chre_rpc_NumberMessage &response,
90 pw::Status status) {
91 if (status.ok()) {
92 gResponsePromise.set_value(response.number);
93 } else {
94 LOGE("Increment failed with status %d", static_cast<int>(status.code()));
95 }
96 }
97
main(int argc,char * argv[])98 int main(int argc, char *argv[]) {
99 UNUSED_VAR(argc);
100 UNUSED_VAR(argv);
101
102 SocketClient socketClient;
103
104 auto callbacks = sp<SocketCallbacks>::make();
105
106 std::unique_ptr<HalRpcClient> rpcClient =
107 HalRpcClient::createClient("chre_test_rpc", socketClient, callbacks,
108 kHostEndpoint, chre::kRpcWorldAppId);
109
110 if (rpcClient == nullptr) {
111 LOGE("Failed to create the RPC client");
112 return -1;
113 }
114
115 if (!rpcClient->hasService(/* id= */ 0xca8f7150a3f05847,
116 /* version= */ 0x01020034)) {
117 LOGE("RpcWorld service not found");
118 return -1;
119 }
120
121 auto client =
122 rpcClient->get<chre::rpc::pw_rpc::nanopb::RpcWorldService::Client>();
123
124 chre_rpc_NumberMessage incrementRequest;
125 incrementRequest.number = kRequestNumber;
126
127 pw::rpc::NanopbUnaryReceiver<chre_rpc_NumberMessage> call =
128 client->Increment(incrementRequest, incrementResponse);
129
130 if (!call.active()) {
131 LOGE("Failed to call the service");
132 return -1;
133 }
134
135 std::future<uint32_t> response = gResponsePromise.get_future();
136
137 if (response.wait_for(std::chrono::seconds(2)) != std::future_status::ready) {
138 LOGE("No response received from RPC");
139 } else {
140 const uint32_t value = response.get();
141 LOGI("The RPC service says %" PRIu32 " + 1 = %" PRIu32, kRequestNumber,
142 value);
143 }
144
145 rpcClient->close();
146
147 return 0;
148 }
149