1 /*
2  * Copyright (C) 2022 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_UTIL_PIGWEED_RPC_CLIENT_H_
18 #define CHRE_UTIL_PIGWEED_RPC_CLIENT_H_
19 
20 #include <cstdint>
21 
22 #include "chre/util/non_copyable.h"
23 #include "chre/util/optional.h"
24 #include "chre/util/pigweed/chre_channel_output.h"
25 #include "chre/util/unique_ptr.h"
26 #include "chre_api/chre.h"
27 #include "pw_rpc/client.h"
28 #include "pw_span/span.h"
29 #include "rpc_helper.h"
30 
31 namespace chre {
32 
33 /**
34  * RPC Client wrapping a Pigweed RPC client.
35  *
36  * This helper class handles Pigweed RPC calls on the client side.
37  *
38  * The `handleEvent` method must be called at the beginning of the
39  * `nanoappHandleEvent` function to handle RPC responses from the server.
40  */
41 class RpcClient : public NonCopyable {
42  public:
43   /**
44    * @param serverNanoappId Nanoapp ID of the server.
45    */
RpcClient(uint64_t serverNanoappId)46   explicit RpcClient(uint64_t serverNanoappId)
47       : mServerNanoappId((serverNanoappId)) {}
48 
49   /**
50    * Handles events related to RPC services.
51    *
52    * Handles the following events:
53    * - CHRE_EVENT_RPC_RESPONSE: handle the server responses,
54    * - CHRE_EVENT_NANOAPP_STOPPED: close the channel when the server nanoapp
55    *   terminates.
56    *
57    * @param senderInstanceId The Instance ID for the source of this event.
58    * @param eventType The event type.
59    * @param eventData The associated data, if any, for this specific type of
60    *                  event.
61    * @return whether any event was handled successfully.
62    */
63   bool handleEvent(uint32_t senderInstanceId, uint16_t eventType,
64                    const void *eventData);
65 
66   /**
67    * Returns a service client.
68    *
69    * NOTE: The template parameter must be set to the Pigweed client type,
70    *       i.e. pw::rpc::pw_rpc::nanopb::<ServiceName>::Client
71 
72    * @return The service client. It has no value on errors.
73    */
74   template <typename T>
75   Optional<T> get();
76 
77   /**
78    * Returns whether the server nanoapp supports the service.
79    *
80    * Also returns false when the nanoapp is not loaded.
81    *
82    * @return whether the service is published by the server.
83    */
84   bool hasService(uint64_t id, uint32_t version);
85 
86   /**
87    * Must be called from nanoapp end.
88    */
89   void close();
90 
91  private:
92   /**
93    * Handles responses from the server.
94    *
95    * This method must be called when nanoapps receive a CHRE_EVENT_RPC_RESPONSE
96    * event.
97    *
98    * @param senderInstanceId The Instance ID for the source of this event.
99    * @param eventData  The associated data, if any.
100    * @return whether the RPC was handled successfully.
101    */
102   bool handleMessageFromServer(uint32_t senderInstanceId,
103                                const void *eventData);
104 
105   /**
106    * Closes the Pigweed channel when the server terminates.
107    *
108    * @param notification The eventData associated to a
109    *    CHRE_EVENT_NANOAPP_STOPPED event.
110    */
111   void handleNanoappStopped(const void *eventData);
112 
113   ChreClientNanoappChannelOutput mChannelOutput;
114   pw::rpc::Client mRpcClient;
115   uint64_t mServerNanoappId;
116   uint32_t mChannelId = 0;
117 };
118 
119 template <typename T>
get()120 Optional<T> RpcClient::get() {
121   if (mChannelId == 0) {
122     struct chreNanoappInfo info;
123 
124     if (!chreGetNanoappInfoByAppId(mServerNanoappId, &info) ||
125         info.instanceId > kRpcNanoappMaxId) {
126       return Optional<T>();
127     }
128 
129     mChannelId = chreGetInstanceId();
130     mChannelOutput.setServer(info.instanceId);
131     mRpcClient.OpenChannel(mChannelId, mChannelOutput);
132   }
133 
134   chreConfigureNanoappInfoEvents(true);
135   return T(mRpcClient, mChannelId);
136 }
137 
138 }  // namespace chre
139 
140 #endif  // CHRE_UTIL_PIGWEED_RPC_SERVER_H_