1 /*
2  * Copyright (C) 2017 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 ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H
18 #define ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H
19 
20 #include <condition_variable>
21 #include <functional>
22 #include <mutex>
23 #include <optional>
24 
25 #include <android/hardware/contexthub/1.0/IContexthub.h>
26 #include <hidl/MQDescriptor.h>
27 #include <hidl/Status.h>
28 
29 #include "chre_host/socket_client.h"
30 #include "chre_host/host_protocol_host.h"
31 #include "chre_host/fragmented_load_transaction.h"
32 
33 namespace android {
34 namespace hardware {
35 namespace contexthub {
36 namespace V1_0 {
37 namespace implementation {
38 
39 using ::android::chre::FragmentedLoadRequest;
40 using ::android::chre::FragmentedLoadTransaction;
41 using ::android::hardware::contexthub::V1_0::ContextHub;
42 using ::android::hardware::contexthub::V1_0::ContextHubMsg;
43 using ::android::hardware::contexthub::V1_0::IContexthub;
44 using ::android::hardware::contexthub::V1_0::IContexthubCallback;
45 using ::android::hardware::contexthub::V1_0::NanoAppBinary;
46 using ::android::hardware::contexthub::V1_0::Result;
47 using ::android::hardware::hidl_handle;
48 using ::android::hardware::hidl_string;
49 using ::android::hardware::hidl_vec;
50 using ::android::hardware::Return;
51 using ::android::sp;
52 
53 class GenericContextHub : public IContexthub {
54  public:
55   GenericContextHub();
56 
57   Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
58 
59   // Methods from ::android::hardware::contexthub::V1_0::IContexthub follow.
60   Return<void> getHubs(getHubs_cb _hidl_cb) override;
61   Return<Result> registerCallback(uint32_t hubId, const sp<IContexthubCallback>& cb) override;
62   Return<Result> sendMessageToHub(uint32_t hubId, const ContextHubMsg& msg) override;
63   Return<Result> loadNanoApp(uint32_t hubId, const NanoAppBinary& appBinary, uint32_t transactionId) override;
64   Return<Result> unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
65   Return<Result> enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
66   Return<Result> disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
67   Return<Result> queryApps(uint32_t hubId) override;
68 
69  private:
70   ::android::chre::SocketClient mClient;
71   sp<IContexthubCallback> mCallbacks;
72   std::mutex mCallbacksLock;
73 
74   class SocketCallbacks : public ::android::chre::SocketClient::ICallbacks,
75                           public ::android::chre::IChreMessageHandlers {
76    public:
77     explicit SocketCallbacks(GenericContextHub& parent);
78     void onMessageReceived(const void *data, size_t length) override;
79     void onConnected() override;
80     void onDisconnected() override;
81 
82     void handleNanoappMessage(
83         const ::chre::fbs::NanoappMessageT& message) override;
84 
85     void handleHubInfoResponse(
86         const ::chre::fbs::HubInfoResponseT& response) override;
87 
88     void handleNanoappListResponse(
89         const ::chre::fbs::NanoappListResponseT& response) override;
90 
91     void handleLoadNanoappResponse(
92       const ::chre::fbs::LoadNanoappResponseT& response) override;
93 
94     void handleUnloadNanoappResponse(
95       const ::chre::fbs::UnloadNanoappResponseT& response) override;
96 
97     void handleDebugDumpData(
98       const ::chre::fbs::DebugDumpDataT& data) override;
99 
100     void handleDebugDumpResponse(
101       const ::chre::fbs::DebugDumpResponseT& response) override;
102 
103    private:
104     GenericContextHub& mParent;
105     bool mHaveConnected = false;
106 
107     /**
108      * Acquires mParent.mCallbacksLock and invokes the synchronous callback
109      * argument if mParent.mCallbacks is not null.
110      */
111     void invokeClientCallback(std::function<Return<void>()> callback);
112   };
113 
114   class DeathRecipient : public hidl_death_recipient {
115    public:
116     explicit DeathRecipient(const sp<GenericContextHub> contexthub);
117     void serviceDied(uint64_t cookie,
118                      const wp<::android::hidl::base::V1_0::IBase>& who)
119         override;
120 
121    private:
122     sp<GenericContextHub> mGenericContextHub;
123   };
124 
125   sp<SocketCallbacks> mSocketCallbacks;
126   sp<DeathRecipient> mDeathRecipient;
127 
128   // Cached hub info used for getHubs(), and synchronization primitives to make
129   // that function call synchronous if we need to query it
130   ContextHub mHubInfo;
131   bool mHubInfoValid = false;
132   std::mutex mHubInfoMutex;
133   std::condition_variable mHubInfoCond;
134 
135   static constexpr int kInvalidFd = -1;
136   int mDebugFd = kInvalidFd;
137   bool mDebugDumpPending = false;
138   std::mutex mDebugDumpMutex;
139   std::condition_variable mDebugDumpCond;
140 
141   // The pending fragmented load request
142   uint32_t mCurrentFragmentId = 0;
143   std::optional<FragmentedLoadTransaction> mPendingLoadTransaction;
144   std::mutex mPendingLoadTransactionMutex;
145 
146   // Use 30KB fragment size to fit within 32KB memory fragments at the kernel
147   static constexpr size_t kLoadFragmentSizeBytes = 30 * 1024;
148 
149   // Write a string to mDebugFd
150   void writeToDebugFile(const char *str);
151   void writeToDebugFile(const char *str, size_t len);
152 
153   // Unregisters callback when context hub service dies
154   void handleServiceDeath(uint32_t hubId);
155 
156   /**
157    * Checks to see if a load response matches the currently pending
158    * fragmented load transaction. mPendingLoadTransactionMutex must
159    * be acquired prior to calling this function.
160    *
161    * @param response the received load response
162    *
163    * @return true if the response matches a pending load transaction
164    *         (if any), false otherwise
165    */
166   bool isExpectedLoadResponseLocked(
167       const ::chre::fbs::LoadNanoappResponseT& response);
168 
169   /**
170    * Sends a fragmented load request to CHRE. The caller must ensure that
171    * transaction.isComplete() returns false prior to invoking this method.
172    *
173    * @param transaction the FragmentedLoadTransaction object
174    *
175    * @return the result of the request
176    */
177   Result sendFragmentedLoadNanoAppRequest(
178       FragmentedLoadTransaction& transaction);
179 };
180 
181 extern "C" IContexthub* HIDL_FETCH_IContexthub(const char* name);
182 
183 }  // namespace implementation
184 }  // namespace V1_0
185 }  // namespace contexthub
186 }  // namespace hardware
187 }  // namespace android
188 
189 #endif  // ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H
190