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[]>(kMaxPayloadBytes); 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 // TODO(b/277235389): Adjust max payload size (AP -> SCP and SCP -> AP) 108 // as appropriate. This is a temp/quick fix for b/272311907 and b/270758946 109 // setting max payload allowed to CHRE_MESSAGE_TO_HOST_MAX_SIZE + 128 byte 110 // to account for transport overhead. 111 static constexpr uint32_t kMaxPayloadBytes = 4224; // 4096 + 128 112 113 // Max overhead of the nanoapp binary payload caused by the fbs encapsulation 114 static constexpr uint32_t kMaxPayloadOverheadBytes = 1024; 115 116 // The path to CHRE file descriptor 117 static constexpr char kChreFileDescriptorPath[] = "/dev/scp_chre_manager"; 118 119 // Max queue size for sending messages to CHRE 120 static constexpr size_t kMaxSynchronousMessageQueueSize = 64; 121 122 // Wrapper for a message sent to CHRE 123 struct ChreConnectionMessage { 124 // This magic number is the SCP_CHRE_MAGIC constant defined by kernel 125 // scp_chre_manager service. The value is embedded in the payload as a 126 // security check for proper use of the device node. 127 uint32_t magic = 0x67728269; 128 uint32_t payloadSize = 0; 129 uint8_t payload[kMaxPayloadBytes]; 130 ChreConnectionMessageChreConnectionMessage131 ChreConnectionMessage(void *data, size_t length) { 132 assert(length <= kMaxPayloadBytes); 133 memcpy(payload, data, length); 134 payloadSize = static_cast<uint32_t>(length); 135 } 136 getMessageSizeChreConnectionMessage137 uint32_t getMessageSize() { 138 return sizeof(magic) + sizeof(payloadSize) + payloadSize; 139 } 140 }; 141 142 // A queue suitable for multiple producers and a single consumer. 143 class SynchronousMessageQueue { 144 public: emplace(void * data,size_t length)145 bool emplace(void *data, size_t length) { 146 std::unique_lock<std::mutex> lock(mMutex); 147 if (mQueue.size() >= kMaxSynchronousMessageQueueSize) { 148 LOGE("Message queue from HAL to CHRE is full!"); 149 return false; 150 } 151 mQueue.emplace(data, length); 152 mCv.notify_all(); 153 return true; 154 } 155 pop()156 void pop() { 157 std::unique_lock<std::mutex> lock(mMutex); 158 mQueue.pop(); 159 } 160 front()161 ChreConnectionMessage &front() { 162 std::unique_lock<std::mutex> lock(mMutex); 163 return mQueue.front(); 164 } 165 waitForMessage()166 void waitForMessage() { 167 std::unique_lock<std::mutex> lock(mMutex); 168 mCv.wait(lock, [&]() { return !mQueue.empty(); }); 169 } 170 171 private: 172 std::mutex mMutex; 173 std::condition_variable mCv; 174 std::queue<ChreConnectionMessage> mQueue; 175 }; 176 177 // The task receiving message from CHRE 178 [[noreturn]] static void messageListenerTask( 179 TinysysChreConnection *chreConnection); 180 181 // The task sending message to CHRE 182 [[noreturn]] static void messageSenderTask( 183 TinysysChreConnection *chreConnection); 184 185 // The task receiving CHRE state update 186 [[noreturn]] static void chreStateMonitorTask( 187 TinysysChreConnection *chreConnection); 188 getChreFileDescriptor()189 [[nodiscard]] inline int getChreFileDescriptor() const { 190 return mChreFileDescriptor; 191 } 192 193 // The file descriptor for communication with CHRE 194 int mChreFileDescriptor; 195 196 // The calback function that should be implemented by HAL 197 ChreConnectionCallback *mCallback; 198 199 // the message listener thread that receives messages from CHRE 200 std::thread mMessageListener; 201 // the message sender thread that sends messages to CHRE 202 std::thread mMessageSender; 203 // the status listener thread that hosts chreStateMonitorTask 204 std::thread mStateListener; 205 206 // Payload received from CHRE 207 std::unique_ptr<uint8_t[]> mPayload; 208 209 // The LPMA handler to talk to the ST HAL 210 StHalLpmaHandler mLpmaHandler; 211 212 // For messages sent to CHRE 213 SynchronousMessageQueue mQueue; 214 215 // Mutex and CV are used to get PulseResponse from CHRE synchronously. 216 std::mutex mChrePulseMutex; 217 std::condition_variable mChrePulseCondition; 218 bool mIsChreBackOnline = 219 false; // set to true after CHRE recovers from a restart 220 }; 221 } // namespace aidl::android::hardware::contexthub 222 223 #endif // TINYSYS_CHRE_CONNECTION_H_ 224