xref: /aosp_15_r20/system/chre/host/hal_generic/common/hal_chre_socket_connection.cc (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2021 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 #define LOG_TAG "ContextHubHal"
18 #define LOG_NDEBUG 1
19 
20 #include "hal_chre_socket_connection.h"
21 
22 #include <log/log.h>
23 
24 #ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
25 #include <chre_atoms_log.h>
26 #include <utils/SystemClock.h>
27 #endif  // CHRE_HAL_SOCKET_METRICS_ENABLED
28 
29 namespace android {
30 namespace hardware {
31 namespace contexthub {
32 namespace common {
33 namespace implementation {
34 
35 using ::android::chre::FragmentedLoadRequest;
36 using ::android::chre::FragmentedLoadTransaction;
37 using ::android::chre::HostProtocolHost;
38 using ::flatbuffers::FlatBufferBuilder;
39 
40 #ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
41 using ::android::chre::MetricsReporter;
42 using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
43 #endif  // CHRE_HAL_SOCKET_METRICS_ENABLED
44 
HalChreSocketConnection(IChreSocketCallback * callback)45 HalChreSocketConnection::HalChreSocketConnection(
46     IChreSocketCallback *callback) {
47   constexpr char kChreSocketName[] = "chre";
48 
49   mSocketCallbacks = sp<SocketCallbacks>::make(*this, callback);
50   if (!mClient.connectInBackground(kChreSocketName, mSocketCallbacks)) {
51     ALOGE("Couldn't start socket client");
52   }
53 }
54 
getContextHubs(::chre::fbs::HubInfoResponseT * response)55 bool HalChreSocketConnection::getContextHubs(
56     ::chre::fbs::HubInfoResponseT *response) {
57   constexpr auto kHubInfoQueryTimeout = std::chrono::seconds(5);
58   ALOGV("%s", __func__);
59 
60   // If we're not connected yet, give it some time
61   // TODO refactor from polling into conditional wait
62   int maxSleepIterations = 250;
63   while (!mHubInfoValid && !mClient.isConnected() && --maxSleepIterations > 0) {
64     std::this_thread::sleep_for(std::chrono::milliseconds(20));
65   }
66 
67   if (!mClient.isConnected()) {
68     ALOGE("Couldn't connect to hub daemon");
69   } else if (!mHubInfoValid) {
70     // We haven't cached the hub details yet, so send a request and block
71     // waiting on a response
72     std::unique_lock<std::mutex> lock(mHubInfoMutex);
73     FlatBufferBuilder builder;
74     HostProtocolHost::encodeHubInfoRequest(builder);
75 
76     ALOGD("Sending hub info request");
77     if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
78       ALOGE("Couldn't send hub info request");
79     } else {
80       mHubInfoCond.wait_for(lock, kHubInfoQueryTimeout,
81                             [this]() { return mHubInfoValid; });
82     }
83   }
84 
85   if (mHubInfoValid) {
86     *response = mHubInfoResponse;
87   } else {
88     ALOGE("Unable to get hub info from CHRE");
89   }
90 
91   return mHubInfoValid;
92 }
93 
sendDebugConfiguration()94 bool HalChreSocketConnection::sendDebugConfiguration() {
95   FlatBufferBuilder builder;
96   HostProtocolHost::encodeDebugConfiguration(builder);
97   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
98 }
99 
sendMessageToHub(uint64_t nanoappId,uint32_t messageType,uint16_t hostEndpointId,const unsigned char * payload,size_t payloadLength)100 bool HalChreSocketConnection::sendMessageToHub(uint64_t nanoappId,
101                                                uint32_t messageType,
102                                                uint16_t hostEndpointId,
103                                                const unsigned char *payload,
104                                                size_t payloadLength) {
105   FlatBufferBuilder builder(1024);
106   HostProtocolHost::encodeNanoappMessage(
107       builder, nanoappId, messageType, hostEndpointId, payload, payloadLength);
108   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
109 }
110 
loadNanoapp(FragmentedLoadTransaction & transaction)111 bool HalChreSocketConnection::loadNanoapp(
112     FragmentedLoadTransaction &transaction) {
113   bool success = false;
114   std::lock_guard<std::mutex> lock(mPendingLoadTransactionMutex);
115 
116   if (mPendingLoadTransaction.has_value()) {
117     ALOGE("Pending load transaction exists. Overriding pending request");
118   }
119 
120   mPendingLoadTransaction = transaction;
121   success = sendFragmentedLoadNanoAppRequest(mPendingLoadTransaction.value());
122   if (!success) {
123     mPendingLoadTransaction.reset();
124   }
125 
126   return success;
127 }
128 
unloadNanoapp(uint64_t appId,uint32_t transactionId)129 bool HalChreSocketConnection::unloadNanoapp(uint64_t appId,
130                                             uint32_t transactionId) {
131   FlatBufferBuilder builder(64);
132   HostProtocolHost::encodeUnloadNanoappRequest(
133       builder, transactionId, appId, false /* allowSystemNanoappUnload */);
134   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
135 }
136 
queryNanoapps()137 bool HalChreSocketConnection::queryNanoapps() {
138   FlatBufferBuilder builder(64);
139   HostProtocolHost::encodeNanoappListRequest(builder);
140   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
141 }
142 
requestDebugDump()143 bool HalChreSocketConnection::requestDebugDump() {
144   FlatBufferBuilder builder;
145   HostProtocolHost::encodeDebugDumpRequest(builder);
146   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
147 }
148 
sendRawMessage(uint8_t * data,size_t size)149 bool HalChreSocketConnection::sendRawMessage(uint8_t *data, size_t size) {
150   return mClient.sendMessage(data, size);
151 }
152 
sendSettingChangedNotification(::chre::fbs::Setting fbsSetting,::chre::fbs::SettingState fbsState)153 bool HalChreSocketConnection::sendSettingChangedNotification(
154     ::chre::fbs::Setting fbsSetting, ::chre::fbs::SettingState fbsState) {
155   FlatBufferBuilder builder(64);
156   HostProtocolHost::encodeSettingChangeNotification(builder, fbsSetting,
157                                                     fbsState);
158   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
159 }
160 
onHostEndpointConnected(uint16_t hostEndpointId,uint8_t type,const std::string & package_name,const std::string & attribution_tag)161 bool HalChreSocketConnection::onHostEndpointConnected(
162     uint16_t hostEndpointId, uint8_t type, const std::string &package_name,
163     const std::string &attribution_tag) {
164   FlatBufferBuilder builder(64);
165   HostProtocolHost::encodeHostEndpointConnected(builder, hostEndpointId, type,
166                                                 package_name, attribution_tag);
167   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
168 }
169 
onHostEndpointDisconnected(uint16_t hostEndpointId)170 bool HalChreSocketConnection::onHostEndpointDisconnected(
171     uint16_t hostEndpointId) {
172   FlatBufferBuilder builder(64);
173   HostProtocolHost::encodeHostEndpointDisconnected(builder, hostEndpointId);
174   return mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize());
175 }
176 
isLoadTransactionPending()177 bool HalChreSocketConnection::isLoadTransactionPending() {
178   std::lock_guard<std::mutex> lock(mPendingLoadTransactionMutex);
179   return mPendingLoadTransaction.has_value();
180 }
181 
SocketCallbacks(HalChreSocketConnection & parent,IChreSocketCallback * callback)182 HalChreSocketConnection::SocketCallbacks::SocketCallbacks(
183     HalChreSocketConnection &parent, IChreSocketCallback *callback)
184     : mParent(parent), mCallback(callback) {}
185 
onMessageReceived(const void * data,size_t length)186 void HalChreSocketConnection::SocketCallbacks::onMessageReceived(
187     const void *data, size_t length) {
188   if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
189     ALOGE("Failed to decode message");
190   }
191 }
192 
onConnected()193 void HalChreSocketConnection::SocketCallbacks::onConnected() {
194   ALOGI("Reconnected to CHRE daemon");
195   if (mHaveConnected) {
196     ALOGI("Reconnected to CHRE daemon");
197     mCallback->onContextHubRestarted();
198   }
199   mParent.sendDebugConfiguration();
200   mHaveConnected = true;
201 }
202 
onDisconnected()203 void HalChreSocketConnection::SocketCallbacks::onDisconnected() {
204   ALOGW("Lost connection to CHRE daemon");
205 }
206 
handleNanoappMessage(const::chre::fbs::NanoappMessageT & message)207 void HalChreSocketConnection::SocketCallbacks::handleNanoappMessage(
208     const ::chre::fbs::NanoappMessageT &message) {
209   ALOGD("Got message from nanoapp: ID 0x%" PRIx64, message.app_id);
210   mCallback->onNanoappMessage(message);
211 
212 #ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
213   if (message.woke_host) {
214     // check and update the 24hour timer
215     long nanoappId = message.app_id;
216 
217     if (!mParent.mMetricsReporter.logApWakeupOccurred(nanoappId)) {
218       ALOGE("Could not log AP Wakeup metric");
219     }
220   }
221 #endif  // CHRE_HAL_SOCKET_METRICS_ENABLED
222 }
223 
handleHubInfoResponse(const::chre::fbs::HubInfoResponseT & response)224 void HalChreSocketConnection::SocketCallbacks::handleHubInfoResponse(
225     const ::chre::fbs::HubInfoResponseT &response) {
226   ALOGD("Got hub info response");
227 
228   std::lock_guard<std::mutex> lock(mParent.mHubInfoMutex);
229   if (mParent.mHubInfoValid) {
230     ALOGI("Ignoring duplicate/unsolicited hub info response");
231   } else {
232     mParent.mHubInfoResponse = response;
233     mParent.mHubInfoValid = true;
234     mParent.mHubInfoCond.notify_all();
235   }
236 }
237 
handleNanoappListResponse(const::chre::fbs::NanoappListResponseT & response)238 void HalChreSocketConnection::SocketCallbacks::handleNanoappListResponse(
239     const ::chre::fbs::NanoappListResponseT &response) {
240   ALOGD("Got nanoapp list response with %zu apps", response.nanoapps.size());
241   mCallback->onNanoappListResponse(response);
242 }
243 
handleLoadNanoappResponse(const::chre::fbs::LoadNanoappResponseT & response)244 void HalChreSocketConnection::SocketCallbacks::handleLoadNanoappResponse(
245     const ::chre::fbs::LoadNanoappResponseT &response) {
246   ALOGD("Got load nanoapp response for transaction %" PRIu32
247         " fragment %" PRIu32 " with result %d",
248         response.transaction_id, response.fragment_id, response.success);
249   std::unique_lock<std::mutex> lock(mParent.mPendingLoadTransactionMutex);
250 
251   // TODO: Handle timeout in receiving load response
252   if (!mParent.mPendingLoadTransaction.has_value()) {
253     ALOGE(
254         "Dropping unexpected load response (no pending transaction "
255         "exists)");
256   } else {
257     FragmentedLoadTransaction &transaction =
258         mParent.mPendingLoadTransaction.value();
259 
260     if (!mParent.isExpectedLoadResponseLocked(response)) {
261       ALOGE("Dropping unexpected load response, expected transaction %" PRIu32
262             " fragment %" PRIu32 ", received transaction %" PRIu32
263             " fragment %" PRIu32,
264             transaction.getTransactionId(), mParent.mCurrentFragmentId,
265             response.transaction_id, response.fragment_id);
266     } else {
267       bool success = false;
268       bool continueLoadRequest = false;
269       if (response.success && !transaction.isComplete()) {
270         if (mParent.sendFragmentedLoadNanoAppRequest(transaction)) {
271           continueLoadRequest = true;
272           success = true;
273         }
274       } else {
275         success = response.success;
276 
277 #ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
278         if (!success) {
279           if (!mParent.mMetricsReporter.logNanoappLoadFailed(
280                   transaction.getNanoappId(),
281                   ChreHalNanoappLoadFailed::TYPE_DYNAMIC,
282                   ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC)) {
283             ALOGE("Could not log the nanoapp load failed metric");
284           }
285         }
286 #endif  // CHRE_HAL_SOCKET_METRICS_ENABLED
287       }
288 
289       if (!continueLoadRequest) {
290         mParent.mPendingLoadTransaction.reset();
291         lock.unlock();
292         mCallback->onTransactionResult(response.transaction_id, success);
293       }
294     }
295   }
296 }
297 
handleUnloadNanoappResponse(const::chre::fbs::UnloadNanoappResponseT & response)298 void HalChreSocketConnection::SocketCallbacks::handleUnloadNanoappResponse(
299     const ::chre::fbs::UnloadNanoappResponseT &response) {
300   ALOGV("Got unload nanoapp response for transaction %" PRIu32
301         " with result %d",
302         response.transaction_id, response.success);
303   mCallback->onTransactionResult(response.transaction_id, response.success);
304 }
305 
handleDebugDumpData(const::chre::fbs::DebugDumpDataT & data)306 void HalChreSocketConnection::SocketCallbacks::handleDebugDumpData(
307     const ::chre::fbs::DebugDumpDataT &data) {
308   ALOGV("Got debug dump data, size %zu", data.debug_str.size());
309   mCallback->onDebugDumpData(data);
310 }
311 
handleDebugDumpResponse(const::chre::fbs::DebugDumpResponseT & response)312 void HalChreSocketConnection::SocketCallbacks::handleDebugDumpResponse(
313     const ::chre::fbs::DebugDumpResponseT &response) {
314   ALOGV("Got debug dump response, success %d, data count %" PRIu32,
315         response.success, response.data_count);
316   mCallback->onDebugDumpComplete(response);
317 }
318 
handleContextHubV4Message(const::chre::fbs::ChreMessageUnion & message)319 bool HalChreSocketConnection::SocketCallbacks::handleContextHubV4Message(
320     const ::chre::fbs::ChreMessageUnion &message) {
321   return mCallback->onContextHubV4Message(message);
322 }
323 
isExpectedLoadResponseLocked(const::chre::fbs::LoadNanoappResponseT & response)324 bool HalChreSocketConnection::isExpectedLoadResponseLocked(
325     const ::chre::fbs::LoadNanoappResponseT &response) {
326   return mPendingLoadTransaction.has_value() &&
327          (mPendingLoadTransaction->getTransactionId() ==
328           response.transaction_id) &&
329          (response.fragment_id == 0 ||
330           mCurrentFragmentId == response.fragment_id);
331 }
332 
sendFragmentedLoadNanoAppRequest(FragmentedLoadTransaction & transaction)333 bool HalChreSocketConnection::sendFragmentedLoadNanoAppRequest(
334     FragmentedLoadTransaction &transaction) {
335   bool success = false;
336   const FragmentedLoadRequest &request = transaction.getNextRequest();
337 
338   FlatBufferBuilder builder(128 + request.binary.size());
339   HostProtocolHost::encodeFragmentedLoadNanoappRequest(builder, request);
340 
341   if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
342     ALOGE("Failed to send load request message (fragment ID = %zu)",
343           request.fragmentId);
344 
345 #ifdef CHRE_HAL_SOCKET_METRICS_ENABLED
346     if (!mMetricsReporter.logNanoappLoadFailed(
347             request.appId, ChreHalNanoappLoadFailed::TYPE_DYNAMIC,
348             ChreHalNanoappLoadFailed::REASON_CONNECTION_ERROR)) {
349       ALOGE("Could not log the nanoapp load failed metric");
350     }
351 #endif  // CHRE_HAL_SOCKET_METRICS_ENABLED
352 
353   } else {
354     mCurrentFragmentId = request.fragmentId;
355     success = true;
356   }
357 
358   return success;
359 }
360 
361 }  // namespace implementation
362 }  // namespace common
363 }  // namespace contexthub
364 }  // namespace hardware
365 }  // namespace android
366