• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #include <cstdlib>
18 #include <fstream>
19 
20 #include "chre_host/daemon_base.h"
21 #include "chre_host/log.h"
22 #include "chre_host/napp_header.h"
23 
24 #include <json/json.h>
25 
26 #ifdef CHRE_DAEMON_METRIC_ENABLED
27 #include <aidl/android/frameworks/stats/IStats.h>
28 #include <android/binder_manager.h>
29 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
30 
31 using ::aidl::android::frameworks::stats::IStats;
32 using ::aidl::android::frameworks::stats::VendorAtom;
33 using ::aidl::android::frameworks::stats::VendorAtomValue;
34 namespace PixelAtoms = ::android::hardware::google::pixel::PixelAtoms;
35 #endif  // CHRE_DAEMON_METRIC_ENABLED
36 
37 // Aliased for consistency with the way these symbols are referenced in
38 // CHRE-side code
39 namespace fbs = ::chre::fbs;
40 
41 namespace android {
42 namespace chre {
43 
ChreDaemonBase()44 ChreDaemonBase::ChreDaemonBase() : mChreShutdownRequested(false) {
45   mLogger.init();
46 }
47 
loadPreloadedNanoapps()48 void ChreDaemonBase::loadPreloadedNanoapps() {
49   constexpr char kPreloadedNanoappsConfigPath[] =
50       "/vendor/etc/chre/preloaded_nanoapps.json";
51   std::ifstream configFileStream(kPreloadedNanoappsConfigPath);
52 
53   Json::CharReaderBuilder builder;
54   Json::Value config;
55   if (!configFileStream) {
56     LOGE("Failed to open config file '%s': %d (%s)",
57          kPreloadedNanoappsConfigPath, errno, strerror(errno));
58   } else if (!Json::parseFromStream(builder, configFileStream, &config,
59                                     /* errorMessage = */ nullptr)) {
60     LOGE("Failed to parse nanoapp config file");
61   } else if (!config.isMember("nanoapps") || !config.isMember("source_dir")) {
62     LOGE("Malformed preloaded nanoapps config");
63   } else {
64     const Json::Value &directory = config["source_dir"];
65     for (Json::ArrayIndex i = 0; i < config["nanoapps"].size(); i++) {
66       const Json::Value &nanoapp = config["nanoapps"][i];
67       loadPreloadedNanoapp(directory.asString(), nanoapp.asString(),
68                            static_cast<uint32_t>(i));
69     }
70   }
71 }
72 
loadPreloadedNanoapp(const std::string & directory,const std::string & name,uint32_t transactionId)73 void ChreDaemonBase::loadPreloadedNanoapp(const std::string &directory,
74                                           const std::string &name,
75                                           uint32_t transactionId) {
76   std::vector<uint8_t> headerBuffer;
77 
78   std::string headerFile = directory + "/" + name + ".napp_header";
79 
80   // Only create the nanoapp filename as the CHRE framework will load from
81   // within the directory its own binary resides in.
82   std::string nanoappFilename = name + ".so";
83 
84   if (readFileContents(headerFile.c_str(), &headerBuffer) &&
85       !loadNanoapp(headerBuffer, nanoappFilename, transactionId)) {
86     LOGE("Failed to load nanoapp: '%s'", name.c_str());
87   }
88 }
89 
loadNanoapp(const std::vector<uint8_t> & header,const std::string & nanoappName,uint32_t transactionId)90 bool ChreDaemonBase::loadNanoapp(const std::vector<uint8_t> &header,
91                                  const std::string &nanoappName,
92                                  uint32_t transactionId) {
93   bool success = false;
94   if (header.size() != sizeof(NanoAppBinaryHeader)) {
95     LOGE("Header size mismatch");
96   } else {
97     // The header blob contains the struct above.
98     const auto *appHeader =
99         reinterpret_cast<const NanoAppBinaryHeader *>(header.data());
100 
101     // Build the target API version from major and minor.
102     uint32_t targetApiVersion = (appHeader->targetChreApiMajorVersion << 24) |
103                                 (appHeader->targetChreApiMinorVersion << 16);
104 
105     success = sendNanoappLoad(appHeader->appId, appHeader->appVersion,
106                               targetApiVersion, nanoappName, transactionId);
107   }
108 
109   return success;
110 }
111 
sendNanoappLoad(uint64_t appId,uint32_t appVersion,uint32_t appTargetApiVersion,const std::string & appBinaryName,uint32_t transactionId)112 bool ChreDaemonBase::sendNanoappLoad(uint64_t appId, uint32_t appVersion,
113                                      uint32_t appTargetApiVersion,
114                                      const std::string &appBinaryName,
115                                      uint32_t transactionId) {
116   flatbuffers::FlatBufferBuilder builder;
117   HostProtocolHost::encodeLoadNanoappRequestForFile(
118       builder, transactionId, appId, appVersion, appTargetApiVersion,
119       appBinaryName.c_str());
120 
121   bool success = sendMessageToChre(
122       kHostClientIdDaemon, builder.GetBufferPointer(), builder.GetSize());
123 
124   if (!success) {
125     LOGE("Failed to send nanoapp filename.");
126   } else {
127     Transaction transaction = {
128         .transactionId = transactionId,
129         .nanoappId = appId,
130     };
131     mPreloadedNanoappPendingTransactions.push(transaction);
132   }
133 
134   return success;
135 }
136 
sendTimeSync(bool logOnError)137 bool ChreDaemonBase::sendTimeSync(bool logOnError) {
138   bool success = false;
139   int64_t timeOffset = getTimeOffset(&success);
140 
141   if (success) {
142     flatbuffers::FlatBufferBuilder builder(64);
143     HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset);
144     success = sendMessageToChre(kHostClientIdDaemon, builder.GetBufferPointer(),
145                                 builder.GetSize());
146 
147     if (!success && logOnError) {
148       LOGE("Failed to deliver time sync message from host to CHRE");
149     }
150   }
151 
152   return success;
153 }
154 
sendTimeSyncWithRetry(size_t numRetries,useconds_t retryDelayUs,bool logOnError)155 bool ChreDaemonBase::sendTimeSyncWithRetry(size_t numRetries,
156                                            useconds_t retryDelayUs,
157                                            bool logOnError) {
158   bool success = false;
159   while (!success && (numRetries-- != 0)) {
160     success = sendTimeSync(logOnError);
161     if (!success) {
162       usleep(retryDelayUs);
163     }
164   }
165   return success;
166 }
167 
sendNanConfigurationUpdate(bool nanEnabled)168 bool ChreDaemonBase::sendNanConfigurationUpdate(bool nanEnabled) {
169   flatbuffers::FlatBufferBuilder builder(32);
170   HostProtocolHost::encodeNanconfigurationUpdate(builder, nanEnabled);
171   return sendMessageToChre(kHostClientIdDaemon, builder.GetBufferPointer(),
172                            builder.GetSize());
173 }
174 
sendMessageToChre(uint16_t clientId,void * data,size_t length)175 bool ChreDaemonBase::sendMessageToChre(uint16_t clientId, void *data,
176                                        size_t length) {
177   bool success = false;
178   if (!HostProtocolHost::mutateHostClientId(data, length, clientId)) {
179     LOGE("Couldn't set host client ID in message container!");
180   } else {
181     LOGV("Delivering message from host (size %zu)", length);
182     getLogger().dump(static_cast<const uint8_t *>(data), length);
183     success = doSendMessage(data, length);
184   }
185 
186   return success;
187 }
188 
onMessageReceived(const unsigned char * messageBuffer,size_t messageLen)189 void ChreDaemonBase::onMessageReceived(const unsigned char *messageBuffer,
190                                        size_t messageLen) {
191   getLogger().dump(messageBuffer, messageLen);
192 
193   uint16_t hostClientId;
194   fbs::ChreMessage messageType;
195   if (!HostProtocolHost::extractHostClientIdAndType(
196           messageBuffer, messageLen, &hostClientId, &messageType)) {
197     LOGW("Failed to extract host client ID from message - sending broadcast");
198     hostClientId = ::chre::kHostClientIdUnspecified;
199   }
200 
201   if (messageType == fbs::ChreMessage::LogMessage) {
202     std::unique_ptr<fbs::MessageContainerT> container =
203         fbs::UnPackMessageContainer(messageBuffer);
204     const auto *logMessage = container->message.AsLogMessage();
205     const std::vector<int8_t> &logData = logMessage->buffer;
206 
207     getLogger().log(reinterpret_cast<const uint8_t *>(logData.data()),
208                     logData.size());
209   } else if (messageType == fbs::ChreMessage::LogMessageV2) {
210     std::unique_ptr<fbs::MessageContainerT> container =
211         fbs::UnPackMessageContainer(messageBuffer);
212     const auto *logMessage = container->message.AsLogMessageV2();
213     const std::vector<int8_t> &logDataBuffer = logMessage->buffer;
214     const auto *logData =
215         reinterpret_cast<const uint8_t *>(logDataBuffer.data());
216     uint32_t numLogsDropped = logMessage->num_logs_dropped;
217 
218     getLogger().logV2(logData, logDataBuffer.size(), numLogsDropped);
219   } else if (messageType == fbs::ChreMessage::TimeSyncRequest) {
220     sendTimeSync(true /* logOnError */);
221   } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRequest) {
222     configureLpma(true /* enabled */);
223   } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRelease) {
224     configureLpma(false /* enabled */);
225   } else if (messageType == fbs::ChreMessage::MetricLog) {
226 #ifdef CHRE_DAEMON_METRIC_ENABLED
227     std::unique_ptr<fbs::MessageContainerT> container =
228         fbs::UnPackMessageContainer(messageBuffer);
229     const auto *metricMsg = container->message.AsMetricLog();
230     handleMetricLog(metricMsg);
231 #endif  // CHRE_DAEMON_METRIC_ENABLED
232   } else if (messageType == fbs::ChreMessage::NanConfigurationRequest) {
233     std::unique_ptr<fbs::MessageContainerT> container =
234         fbs::UnPackMessageContainer(messageBuffer);
235     configureNan(container->message.AsNanConfigurationRequest()->enable);
236   } else if (hostClientId == kHostClientIdDaemon) {
237     handleDaemonMessage(messageBuffer);
238   } else if (hostClientId == ::chre::kHostClientIdUnspecified) {
239     mServer.sendToAllClients(messageBuffer, static_cast<size_t>(messageLen));
240   } else {
241     mServer.sendToClientById(messageBuffer, static_cast<size_t>(messageLen),
242                              hostClientId);
243   }
244 }
245 
readFileContents(const char * filename,std::vector<uint8_t> * buffer)246 bool ChreDaemonBase::readFileContents(const char *filename,
247                                       std::vector<uint8_t> *buffer) {
248   bool success = false;
249   std::ifstream file(filename, std::ios::binary | std::ios::ate);
250   if (!file) {
251     LOGE("Couldn't open file '%s': %d (%s)", filename, errno, strerror(errno));
252   } else {
253     ssize_t size = file.tellg();
254     file.seekg(0, std::ios::beg);
255 
256     buffer->resize(size);
257     if (!file.read(reinterpret_cast<char *>(buffer->data()), size)) {
258       LOGE("Couldn't read from file '%s': %d (%s)", filename, errno,
259            strerror(errno));
260     } else {
261       success = true;
262     }
263   }
264 
265   return success;
266 }
267 
handleDaemonMessage(const uint8_t * message)268 void ChreDaemonBase::handleDaemonMessage(const uint8_t *message) {
269   std::unique_ptr<fbs::MessageContainerT> container =
270       fbs::UnPackMessageContainer(message);
271   if (container->message.type != fbs::ChreMessage::LoadNanoappResponse) {
272     LOGE("Invalid message from CHRE directed to daemon");
273   } else {
274     const auto *response = container->message.AsLoadNanoappResponse();
275     if (mPreloadedNanoappPendingTransactions.empty()) {
276       LOGE("Received nanoapp load response with no pending load");
277     } else if (mPreloadedNanoappPendingTransactions.front().transactionId !=
278                response->transaction_id) {
279       LOGE("Received nanoapp load response with ID %" PRIu32
280            " expected transaction id %" PRIu32,
281            response->transaction_id,
282            mPreloadedNanoappPendingTransactions.front().transactionId);
283     } else {
284       if (!response->success) {
285         LOGE("Received unsuccessful nanoapp load response with ID %" PRIu32,
286              mPreloadedNanoappPendingTransactions.front().transactionId);
287 
288 #ifdef CHRE_DAEMON_METRIC_ENABLED
289         std::vector<VendorAtomValue> values(3);
290         values[0].set<VendorAtomValue::longValue>(
291             mPreloadedNanoappPendingTransactions.front().nanoappId);
292         values[1].set<VendorAtomValue::intValue>(
293             PixelAtoms::ChreHalNanoappLoadFailed::TYPE_PRELOADED);
294         values[2].set<VendorAtomValue::intValue>(
295             PixelAtoms::ChreHalNanoappLoadFailed::REASON_ERROR_GENERIC);
296         const VendorAtom atom{
297             .reverseDomainName = "",
298             .atomId = PixelAtoms::Atom::kChreHalNanoappLoadFailed,
299             .values{std::move(values)},
300         };
301         reportMetric(atom);
302 #endif  // CHRE_DAEMON_METRIC_ENABLED
303       }
304       mPreloadedNanoappPendingTransactions.pop();
305     }
306   }
307 }
308 
309 #ifdef CHRE_DAEMON_METRIC_ENABLED
handleMetricLog(const::chre::fbs::MetricLogT * metricMsg)310 void ChreDaemonBase::handleMetricLog(const ::chre::fbs::MetricLogT *metricMsg) {
311   const std::vector<int8_t> &encodedMetric = metricMsg->encoded_metric;
312 
313   switch (metricMsg->id) {
314     case PixelAtoms::Atom::kChrePalOpenFailed: {
315       PixelAtoms::ChrePalOpenFailed metric;
316       if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) {
317         LOGE("Failed to parse metric data");
318       } else {
319         std::vector<VendorAtomValue> values(2);
320         values[0].set<VendorAtomValue::intValue>(metric.pal());
321         values[1].set<VendorAtomValue::intValue>(metric.type());
322         const VendorAtom atom{
323             .reverseDomainName = "",
324             .atomId = PixelAtoms::Atom::kChrePalOpenFailed,
325             .values{std::move(values)},
326         };
327         reportMetric(atom);
328       }
329       break;
330     }
331     case PixelAtoms::Atom::kChreEventQueueSnapshotReported: {
332       PixelAtoms::ChreEventQueueSnapshotReported metric;
333       if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) {
334         LOGE("Failed to parse metric data");
335       } else {
336         std::vector<VendorAtomValue> values(6);
337         values[0].set<VendorAtomValue::intValue>(
338             metric.snapshot_chre_get_time_ms());
339         values[1].set<VendorAtomValue::intValue>(metric.max_event_queue_size());
340         values[2].set<VendorAtomValue::intValue>(
341             metric.mean_event_queue_size());
342         values[3].set<VendorAtomValue::intValue>(metric.num_dropped_events());
343         // Last two values are not currently populated and will be implemented
344         // later. To avoid confusion of the interpretation, we use UINT32_MAX
345         // as a placeholder value.
346         values[4].set<VendorAtomValue::intValue>(
347             UINT32_MAX);  // max_queue_delay_us
348         values[5].set<VendorAtomValue::intValue>(
349             UINT32_MAX);  // mean_queue_delay_us
350         const VendorAtom atom{
351             .reverseDomainName = "",
352             .atomId = PixelAtoms::Atom::kChreEventQueueSnapshotReported,
353             .values{std::move(values)},
354         };
355         reportMetric(atom);
356       }
357       break;
358     }
359     default: {
360 #ifdef CHRE_LOG_ATOM_EXTENSION_ENABLED
361       handleVendorMetricLog(metricMsg);
362 #else
363       LOGW("Unknown metric ID %" PRIu32, metricMsg->id);
364 #endif  // CHRE_LOG_ATOM_EXTENSION_ENABLED
365     }
366   }
367 }
368 
reportMetric(const VendorAtom & atom)369 void ChreDaemonBase::reportMetric(const VendorAtom &atom) {
370   const std::string statsServiceName =
371       std::string(IStats::descriptor).append("/default");
372   if (!AServiceManager_isDeclared(statsServiceName.c_str())) {
373     LOGE("Stats service is not declared.");
374     return;
375   }
376 
377   std::shared_ptr<IStats> stats_client = IStats::fromBinder(ndk::SpAIBinder(
378       AServiceManager_waitForService(statsServiceName.c_str())));
379   if (stats_client == nullptr) {
380     LOGE("Failed to get IStats service");
381     return;
382   }
383 
384   const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(atom);
385   if (!ret.isOk()) {
386     LOGE("Failed to report vendor atom");
387   }
388 }
389 #endif  // CHRE_DAEMON_METRIC_ENABLED
390 
configureNan(bool)391 void ChreDaemonBase::configureNan(bool /*enabled*/) {
392   LOGE("NAN not supported");
393 }
394 
395 }  // namespace chre
396 }  // namespace android
397