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