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 TINYSYS_CHRE_CONNECTION_H_ 18 #define TINYSYS_CHRE_CONNECTION_H_ 19 20 #include "chre_connection.h" 21 #include "chre_connection_callback.h" 22 #include "chre_host/fragmented_load_transaction.h" 23 #include "chre_host/host_protocol_host.h" 24 #include "chre_host/log.h" 25 #include "chre_host/log_message_parser.h" 26 #include "chre_host/st_hal_lpma_handler.h" 27 28 #include <unistd.h> 29 #include <cassert> 30 #include <future> 31 #include <queue> 32 #include <thread> 33 34 using ::android::chre::StHalLpmaHandler; 35 36 namespace aidl::android::hardware::contexthub { 37 38 using namespace ::android::hardware::contexthub::common::implementation; 39 using ::android::chre::HostProtocolHost; 40 41 /** A class handling message transmission between context hub HAL and CHRE. */ 42 // TODO(b/267188769): We should add comments explaining how IPI works. 43 class TinysysChreConnection : public ChreConnection { 44 public: TinysysChreConnection(ChreConnectionCallback * callback)45 TinysysChreConnection(ChreConnectionCallback *callback) 46 : mCallback(callback), mLpmaHandler(/* allowed= */ true) { 47 mPayload = std::make_unique<uint8_t[]>(kMaxReceivingPayloadBytes); 48 }; 49 ~TinysysChreConnection()50 ~TinysysChreConnection() override { 51 // TODO(b/264308286): Need a decent way to terminate the listener thread. 52 close(mChreFileDescriptor); 53 if (mMessageListener.joinable()) { 54 mMessageListener.join(); 55 } 56 if (mMessageSender.joinable()) { 57 mMessageSender.join(); 58 } 59 if (mStateListener.joinable()) { 60 mStateListener.join(); 61 } 62 } 63 64 static void handleMessageFromChre(TinysysChreConnection *chreConnection, 65 const unsigned char *messageBuffer, 66 size_t messageLen); 67 68 bool init() override; 69 70 bool sendMessage(void *data, size_t length) override; 71 waitChreBackOnline(std::chrono::milliseconds timeoutMs)72 void waitChreBackOnline(std::chrono::milliseconds timeoutMs) { 73 flatbuffers::FlatBufferBuilder builder(48); 74 HostProtocolHost::encodePulseRequest(builder); 75 76 std::unique_lock<std::mutex> lock(mChrePulseMutex); 77 // reset mIsChreRecovered before sending a PulseRequest message 78 mIsChreBackOnline = false; 79 sendMessage(builder.GetBufferPointer(), builder.GetSize()); 80 mChrePulseCondition.wait_for( 81 lock, timeoutMs, 82 [&isChreBackOnline = mIsChreBackOnline] { return isChreBackOnline; }); 83 } 84 notifyChreBackOnline()85 void notifyChreBackOnline() { 86 { 87 std::unique_lock<std::mutex> lock(mChrePulseMutex); 88 mIsChreBackOnline = true; 89 } 90 mChrePulseCondition.notify_all(); 91 } 92 getCallback()93 inline ChreConnectionCallback *getCallback() { 94 return mCallback; 95 } 96 getLpmaHandler()97 inline StHalLpmaHandler *getLpmaHandler() { 98 return &mLpmaHandler; 99 } 100 101 private: 102 // The wakelock used to keep device awake while handleUsfMsgAsync() is being 103 // called. 104 static constexpr char kWakeLock[] = "tinysys_chre_hal_wakelock"; 105 106 // Max payload size that can be sent to CHRE 107 static constexpr uint32_t kMaxSendingPayloadBytes = 0x8000; // 32K 108 109 // Max payload size that can be received from CHRE 110 static constexpr uint32_t kMaxReceivingPayloadBytes = 0x8000; // 32K 111 112 // Max overhead of the nanoapp binary payload caused by the fbs encapsulation 113 static constexpr uint32_t kMaxPayloadOverheadBytes = 1024; 114 115 // The path to CHRE file descriptor 116 static constexpr char kChreFileDescriptorPath[] = "/dev/scp_chre_manager"; 117 118 // Max queue size for sending messages to CHRE 119 static constexpr size_t kMaxSynchronousMessageQueueSize = 64; 120 121 // Wrapper for a message sent to CHRE 122 struct ChreConnectionMessage { 123 // This magic number is the SCP_CHRE_MAGIC constant defined by kernel 124 // scp_chre_manager service. The value is embedded in the payload as a 125 // security check for proper use of the device node. 126 uint32_t magic = 0x67728269; 127 uint32_t payloadSize = 0; 128 uint8_t payload[kMaxSendingPayloadBytes]; 129 ChreConnectionMessageChreConnectionMessage130 ChreConnectionMessage(void *data, size_t length) { 131 assert(length <= kMaxSendingPayloadBytes); 132 memcpy(payload, data, length); 133 payloadSize = static_cast<uint32_t>(length); 134 } 135 getMessageSizeChreConnectionMessage136 uint32_t getMessageSize() { 137 return sizeof(magic) + sizeof(payloadSize) + payloadSize; 138 } 139 }; 140 141 // A queue suitable for multiple producers and a single consumer. 142 class SynchronousMessageQueue { 143 public: emplace(void * data,size_t length)144 bool emplace(void *data, size_t length) { 145 std::unique_lock<std::mutex> lock(mMutex); 146 if (mQueue.size() >= kMaxSynchronousMessageQueueSize) { 147 LOGE("Message queue from HAL to CHRE is full!"); 148 return false; 149 } 150 mQueue.emplace(data, length); 151 mCv.notify_all(); 152 return true; 153 } 154 pop()155 void pop() { 156 std::unique_lock<std::mutex> lock(mMutex); 157 mQueue.pop(); 158 } 159 front()160 ChreConnectionMessage &front() { 161 std::unique_lock<std::mutex> lock(mMutex); 162 return mQueue.front(); 163 } 164 waitForMessage()165 void waitForMessage() { 166 std::unique_lock<std::mutex> lock(mMutex); 167 mCv.wait(lock, [&]() { return !mQueue.empty(); }); 168 } 169 170 private: 171 std::mutex mMutex; 172 std::condition_variable mCv; 173 std::queue<ChreConnectionMessage> mQueue; 174 }; 175 176 // The task receiving message from CHRE 177 [[noreturn]] static void messageListenerTask( 178 TinysysChreConnection *chreConnection); 179 180 // The task sending message to CHRE 181 [[noreturn]] static void messageSenderTask( 182 TinysysChreConnection *chreConnection); 183 184 // The task receiving CHRE state update 185 [[noreturn]] static void chreStateMonitorTask( 186 TinysysChreConnection *chreConnection); 187 getChreFileDescriptor()188 [[nodiscard]] inline int getChreFileDescriptor() const { 189 return mChreFileDescriptor; 190 } 191 192 // The file descriptor for communication with CHRE 193 int mChreFileDescriptor; 194 195 // The calback function that should be implemented by HAL 196 ChreConnectionCallback *mCallback; 197 198 // the message listener thread that receives messages from CHRE 199 std::thread mMessageListener; 200 // the message sender thread that sends messages to CHRE 201 std::thread mMessageSender; 202 // the status listener thread that hosts chreStateMonitorTask 203 std::thread mStateListener; 204 205 // Payload received from CHRE 206 std::unique_ptr<uint8_t[]> mPayload; 207 208 // The LPMA handler to talk to the ST HAL 209 StHalLpmaHandler mLpmaHandler; 210 211 // For messages sent to CHRE 212 SynchronousMessageQueue mQueue; 213 214 // Mutex and CV are used to get PulseResponse from CHRE synchronously. 215 std::mutex mChrePulseMutex; 216 std::condition_variable mChrePulseCondition; 217 bool mIsChreBackOnline = 218 false; // set to true after CHRE recovers from a restart 219 }; 220 } // namespace aidl::android::hardware::contexthub 221 222 #endif // TINYSYS_CHRE_CONNECTION_H_ 223