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_