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 #ifndef CHRE_PIGWEED_HAL_RPC_CLIENT_H_
18 #define CHRE_PIGWEED_HAL_RPC_CLIENT_H_
19
20 #include <chrono>
21 #include <condition_variable>
22 #include <cstdint>
23 #include <memory>
24 #include <mutex>
25 #include <optional>
26 #include <string_view>
27
28 #include <android-base/thread_annotations.h>
29
30 #include "chre/util/pigweed/rpc_common.h"
31 #include "chre_host/pigweed/hal_channel_output.h"
32
33 #include "chre/util/macros.h"
34 #include "chre/util/non_copyable.h"
35 #include "chre_host/host_protocol_host.h"
36 #include "chre_host/log.h"
37 #include "chre_host/pigweed/hal_channel_output.h"
38 #include "chre_host/socket_client.h"
39 #include "pw_rpc/client.h"
40
41 namespace android::chre {
42
43 /**
44 * RPC client helper to use with native vendor processes.
45 */
46 class HalRpcClient : public ::chre::NonCopyable {
47 public:
48 /**
49 * Creates a RPC client helper.
50 *
51 * This method connects to the socket blocks until the initialization is
52 * complete.
53 *
54 # @param appName Name of the app.
55 * @param client A SocketClient that must not be already connected.
56 * @param socketCallbacks The callbacks to call on SocketClient events.
57 * @param hostEndpointId The host endpoint ID for the app.
58 * @param serverNanoappId The ID of the nanoapp providing the service.
59 * @return A pointer to a HalRpcClient. nullptr on error.
60 */
61 static std::unique_ptr<HalRpcClient> createClient(
62 std::string_view appName, SocketClient &client,
63 sp<SocketClient::ICallbacks> socketCallbacks, uint16_t hostEndpointId,
64 uint64_t serverNanoappId);
65
~HalRpcClient()66 ~HalRpcClient() {
67 close();
68 }
69
70 /**
71 * Closes the RPC client and de-allocate resources.
72 *
73 * Note: This method is called from the destructor. However it can also be
74 * called explicitly.
75 */
76 void close();
77
78 /**
79 * Returns a service client.
80 *
81 * NOTE: The template parameter must be set to the Pigweed client type,
82 * i.e. pw::rpc::pw_rpc::nanopb::<ServiceName>::Client
83
84 * @return The service client. It has no value on errors.
85 */
86 template <typename T>
87 std::optional<T> get();
88
89 /**
90 * Returns whether the server nanoapp supports the service.
91 *
92 * Also returns false when the nanoapp is not loaded.
93 *
94 * @return whether the service is published by the server.
95 */
96 bool hasService(uint64_t id, uint32_t version);
97
98 private:
99 /** Timeout for the requests to the daemon */
100 static constexpr auto kRequestTimeout = std::chrono::milliseconds(2000);
101
102 class Callbacks : public SocketClient::ICallbacks,
103 public IChreMessageHandlers {
104 public:
Callbacks(HalRpcClient * client,sp<SocketClient::ICallbacks> socketCallbacks)105 Callbacks(HalRpcClient *client,
106 sp<SocketClient::ICallbacks> socketCallbacks)
107 : mClient(client), mSocketCallbacks(socketCallbacks) {}
108
109 /** Socket callbacks. */
110 void onMessageReceived(const void *data, size_t length) override;
111 void onConnected() override;
112 void onConnectionAborted() override;
113 void onDisconnected() override;
114
115 /** Message handlers. */
116 void handleNanoappMessage(
117 const ::chre::fbs::NanoappMessageT &message) override;
118 void handleHubInfoResponse(
119 const ::chre::fbs::HubInfoResponseT &response) override;
120 void handleNanoappListResponse(
121 const ::chre::fbs::NanoappListResponseT &response) override;
122
123 private:
124 HalRpcClient *mClient;
125 sp<SocketClient::ICallbacks> mSocketCallbacks;
126 };
127
HalRpcClient(std::string_view appName,SocketClient & client,uint16_t hostEndpointId,uint64_t serverNanoappId)128 HalRpcClient(std::string_view appName, SocketClient &client,
129 uint16_t hostEndpointId, uint64_t serverNanoappId)
130 : mServerNanoappId(serverNanoappId),
131 mHostEndpointId(hostEndpointId),
132 mAppName(appName),
133 mSocketClient(client) {}
134
135 /**
136 * Initializes the RPC client helper.
137 *
138 * @param socketCallbacks The callbacks to call on SocketClient events.
139 * @return Whether the initialization was successful.
140 */
141 bool init(sp<SocketClient::ICallbacks> socketCallbacks);
142
143 /** @return the Pigweed RPC channel ID */
GetChannelId()144 uint32_t GetChannelId() {
145 return ::chre::kChannelIdHostClient | mHostEndpointId;
146 }
147
148 /**
149 * Notifies CHRE that the host endpoint has connected.
150 *
151 * Needed as the RPC Server helper will retrieve the host endpoint metadata
152 * when servicing a request.
153 */
154 bool notifyEndpointConnected();
155
156 /** Notifies CHRE that the host endpoint has disconnected. */
157 bool notifyEndpointDisconnected();
158
159 /** Query CHRE to retrieve the maximum message length. */
160 bool retrieveMaxMessageLen();
161
162 /** Query CHRE to retrieve the services published by the server nanoapp. */
163 bool retrieveServices();
164
165 const uint64_t mServerNanoappId;
166 const uint16_t mHostEndpointId;
167 const std::string mAppName;
168 SocketClient &mSocketClient;
169 std::unique_ptr<HalChannelOutput> mChannelOutput;
170 pw::rpc::Client mRpcClient;
171 bool mIsChannelOpened = false;
172
173 /** Request Hub Info. */
174 std::mutex mHubInfoMutex;
175 size_t mMaxMessageLen GUARDED_BY(mHubInfoMutex);
176 std::condition_variable mHubInfoCond;
177
178 /** Request Nanoapps. */
179 std::mutex mNanoappMutex;
180 std::vector<::chre::fbs::NanoappRpcServiceT> mServices
181 GUARDED_BY(mNanoappMutex);
182 std::condition_variable mNanoappCond;
183 };
184
185 template <typename T>
get()186 std::optional<T> HalRpcClient::get() {
187 if (mChannelOutput == nullptr) {
188 LOGE("No channel output");
189 return {};
190 }
191
192 if (!mIsChannelOpened) {
193 mRpcClient.OpenChannel(GetChannelId(), *mChannelOutput);
194 mIsChannelOpened = true;
195 }
196
197 return T(mRpcClient, GetChannelId());
198 }
199
200 } // namespace android::chre
201
202 #endif // CHRE_PIGWEED_HAL_RPC_CLIENT_H_