• 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 // Aliased for consistency with the way these symbols are referenced in
27 // CHRE-side code
28 namespace fbs = ::chre::fbs;
29 
30 namespace android {
31 namespace chre {
32 
loadPreloadedNanoapps()33 void ChreDaemonBase::loadPreloadedNanoapps() {
34   constexpr char kPreloadedNanoappsConfigPath[] =
35       "/vendor/etc/chre/preloaded_nanoapps.json";
36   std::ifstream configFileStream(kPreloadedNanoappsConfigPath);
37 
38   Json::CharReaderBuilder builder;
39   Json::Value config;
40   if (!configFileStream) {
41     LOGE("Failed to open config file '%s': %d (%s)",
42          kPreloadedNanoappsConfigPath, errno, strerror(errno));
43   } else if (!Json::parseFromStream(builder, configFileStream, &config,
44                                     /* errorMessage = */ nullptr)) {
45     LOGE("Failed to parse nanoapp config file");
46   } else if (!config.isMember("nanoapps") || !config.isMember("source_dir")) {
47     LOGE("Malformed preloaded nanoapps config");
48   } else {
49     const Json::Value &directory = config["source_dir"];
50     for (Json::ArrayIndex i = 0; i < config["nanoapps"].size(); i++) {
51       const Json::Value &nanoapp = config["nanoapps"][i];
52       loadPreloadedNanoapp(directory.asString(), nanoapp.asString(),
53                            static_cast<uint32_t>(i));
54     }
55   }
56 }
57 
loadPreloadedNanoapp(const std::string & directory,const std::string & name,uint32_t transactionId)58 void ChreDaemonBase::loadPreloadedNanoapp(const std::string &directory,
59                                           const std::string &name,
60                                           uint32_t transactionId) {
61   std::vector<uint8_t> headerBuffer;
62 
63   std::string headerFile = directory + "/" + name + ".napp_header";
64 
65   // Only create the nanoapp filename as the CHRE framework will load from
66   // within the directory its own binary resides in.
67   std::string nanoappFilename = name + ".so";
68 
69   if (readFileContents(headerFile.c_str(), &headerBuffer) &&
70       !loadNanoapp(headerBuffer, nanoappFilename, transactionId)) {
71     LOGE("Failed to load nanoapp: '%s'", name.c_str());
72   }
73 }
74 
loadNanoapp(const std::vector<uint8_t> & header,const std::string & nanoappName,uint32_t transactionId)75 bool ChreDaemonBase::loadNanoapp(const std::vector<uint8_t> &header,
76                                  const std::string &nanoappName,
77                                  uint32_t transactionId) {
78   bool success = false;
79   if (header.size() != sizeof(NanoAppBinaryHeader)) {
80     LOGE("Header size mismatch");
81   } else {
82     // The header blob contains the struct above.
83     const auto *appHeader =
84         reinterpret_cast<const NanoAppBinaryHeader *>(header.data());
85 
86     // Build the target API version from major and minor.
87     uint32_t targetApiVersion = (appHeader->targetChreApiMajorVersion << 24) |
88                                 (appHeader->targetChreApiMinorVersion << 16);
89 
90     success = sendNanoappLoad(appHeader->appId, appHeader->appVersion,
91                               targetApiVersion, nanoappName, transactionId);
92   }
93 
94   return success;
95 }
96 
sendNanoappLoad(uint64_t appId,uint32_t appVersion,uint32_t appTargetApiVersion,const std::string & appBinaryName,uint32_t transactionId)97 bool ChreDaemonBase::sendNanoappLoad(uint64_t appId, uint32_t appVersion,
98                                      uint32_t appTargetApiVersion,
99                                      const std::string &appBinaryName,
100                                      uint32_t transactionId) {
101   flatbuffers::FlatBufferBuilder builder;
102   HostProtocolHost::encodeLoadNanoappRequestForFile(
103       builder, transactionId, appId, appVersion, appTargetApiVersion,
104       appBinaryName.c_str());
105 
106   bool success = sendMessageToChre(
107       kHostClientIdDaemon, builder.GetBufferPointer(), builder.GetSize());
108 
109   if (!success) {
110     LOGE("Failed to send nanoapp filename.");
111   } else {
112     mPreloadedNanoappPendingTransactionIds.push(transactionId);
113   }
114 
115   return success;
116 }
117 
sendTimeSync(bool logOnError)118 bool ChreDaemonBase::sendTimeSync(bool logOnError) {
119   bool success = false;
120   int64_t timeOffset = getTimeOffset(&success);
121 
122   if (success) {
123     flatbuffers::FlatBufferBuilder builder(64);
124     HostProtocolHost::encodeTimeSyncMessage(builder, timeOffset);
125     success = sendMessageToChre(kHostClientIdDaemon, builder.GetBufferPointer(),
126                                 builder.GetSize());
127 
128     if (!success && logOnError) {
129       LOGE("Failed to deliver time sync message from host to CHRE");
130     }
131   }
132 
133   return success;
134 }
135 
sendTimeSyncWithRetry(size_t numRetries,useconds_t retryDelayUs,bool logOnError)136 bool ChreDaemonBase::sendTimeSyncWithRetry(size_t numRetries,
137                                            useconds_t retryDelayUs,
138                                            bool logOnError) {
139   bool success = false;
140   while (!success && (numRetries-- != 0)) {
141     success = sendTimeSync(logOnError);
142     if (!success) {
143       usleep(retryDelayUs);
144     }
145   }
146   return success;
147 }
148 
sendMessageToChre(uint16_t clientId,void * data,size_t length)149 bool ChreDaemonBase::sendMessageToChre(uint16_t clientId, void *data,
150                                        size_t length) {
151   bool success = false;
152   if (!HostProtocolHost::mutateHostClientId(data, length, clientId)) {
153     LOGE("Couldn't set host client ID in message container!");
154   } else {
155     LOGV("Delivering message from host (size %zu)", length);
156     getLogger()->dump(static_cast<const uint8_t *>(data), length);
157     success = doSendMessage(data, length);
158   }
159 
160   return success;
161 }
162 
onMessageReceived(const unsigned char * messageBuffer,size_t messageLen)163 void ChreDaemonBase::onMessageReceived(const unsigned char *messageBuffer,
164                                        size_t messageLen) {
165   getLogger()->dump(messageBuffer, messageLen);
166 
167   uint16_t hostClientId;
168   fbs::ChreMessage messageType;
169   if (!HostProtocolHost::extractHostClientIdAndType(
170           messageBuffer, messageLen, &hostClientId, &messageType)) {
171     LOGW("Failed to extract host client ID from message - sending broadcast");
172     hostClientId = ::chre::kHostClientIdUnspecified;
173   }
174 
175   if (messageType == fbs::ChreMessage::LogMessage) {
176     std::unique_ptr<fbs::MessageContainerT> container =
177         fbs::UnPackMessageContainer(messageBuffer);
178     const auto *logMessage = container->message.AsLogMessage();
179     const std::vector<int8_t> &logData = logMessage->buffer;
180 
181     getLogger()->log(reinterpret_cast<const uint8_t *>(logData.data()),
182                      logData.size());
183   } else if (messageType == fbs::ChreMessage::LogMessageV2) {
184     std::unique_ptr<fbs::MessageContainerT> container =
185         fbs::UnPackMessageContainer(messageBuffer);
186     const auto *logMessage = container->message.AsLogMessageV2();
187     const std::vector<int8_t> &logData = logMessage->buffer;
188     uint32_t numLogsDropped = logMessage->num_logs_dropped;
189 
190     getLogger()->logV2(reinterpret_cast<const uint8_t *>(logData.data()),
191                        logData.size(), numLogsDropped);
192   } else if (messageType == fbs::ChreMessage::TimeSyncRequest) {
193     sendTimeSync(true /* logOnError */);
194   } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRequest) {
195     configureLpma(true /* enabled */);
196   } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRelease) {
197     configureLpma(false /* enabled */);
198   } else if (hostClientId == kHostClientIdDaemon) {
199     handleDaemonMessage(messageBuffer);
200   } else if (hostClientId == ::chre::kHostClientIdUnspecified) {
201     mServer.sendToAllClients(messageBuffer, static_cast<size_t>(messageLen));
202   } else {
203     mServer.sendToClientById(messageBuffer, static_cast<size_t>(messageLen),
204                              hostClientId);
205   }
206 }
207 
readFileContents(const char * filename,std::vector<uint8_t> * buffer)208 bool ChreDaemonBase::readFileContents(const char *filename,
209                                       std::vector<uint8_t> *buffer) {
210   bool success = false;
211   std::ifstream file(filename, std::ios::binary | std::ios::ate);
212   if (!file) {
213     LOGE("Couldn't open file '%s': %d (%s)", filename, errno, strerror(errno));
214   } else {
215     ssize_t size = file.tellg();
216     file.seekg(0, std::ios::beg);
217 
218     buffer->resize(size);
219     if (!file.read(reinterpret_cast<char *>(buffer->data()), size)) {
220       LOGE("Couldn't read from file '%s': %d (%s)", filename, errno,
221            strerror(errno));
222     } else {
223       success = true;
224     }
225   }
226 
227   return success;
228 }
229 
handleDaemonMessage(const uint8_t * message)230 void ChreDaemonBase::handleDaemonMessage(const uint8_t *message) {
231   std::unique_ptr<fbs::MessageContainerT> container =
232       fbs::UnPackMessageContainer(message);
233   if (container->message.type != fbs::ChreMessage::LoadNanoappResponse) {
234     LOGE("Invalid message from CHRE directed to daemon");
235   } else {
236     const auto *response = container->message.AsLoadNanoappResponse();
237     if (mPreloadedNanoappPendingTransactionIds.empty()) {
238       LOGE("Received nanoapp load response with no pending load");
239     } else if (mPreloadedNanoappPendingTransactionIds.front() !=
240                response->transaction_id) {
241       LOGE("Received nanoapp load response with ID %" PRIu32
242            " expected transaction id %" PRIu32,
243            response->transaction_id,
244            mPreloadedNanoappPendingTransactionIds.front());
245     } else {
246       if (!response->success) {
247         LOGE("Received unsuccessful nanoapp load response with ID %" PRIu32,
248              mPreloadedNanoappPendingTransactionIds.front());
249       }
250       mPreloadedNanoappPendingTransactionIds.pop();
251     }
252   }
253 }
254 
255 }  // namespace chre
256 }  // namespace android
257