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