• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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