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