1 /*
2  * Copyright (C) 2017 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 // Disable verbose logging
18 // TODO: use property_get_bool to make verbose logging runtime configurable
19 // #define LOG_NDEBUG 0
20 
21 #include "fastrpc_daemon.h"
22 
23 #include "generated/chre_slpi.h"
24 
25 // TODO: The following conditional compilation needs to be removed, and done
26 // for all platforms after verifying that it works on older devices where
27 // we're currently not defining this macro
28 #ifdef CHRE_DAEMON_LOAD_INTO_SENSORSPD
29 #include "remote.h"
30 
31 #define ITRANSPORT_PREFIX "'\":;./\\"
32 #endif  // CHRE_DAEMON_LOAD_INTO_SENSORSPD
33 
34 // Aliased for consistency with the way these symbols are referenced in
35 // CHRE-side code
36 namespace fbs = ::chre::fbs;
37 
38 namespace android {
39 namespace chre {
40 
41 namespace {
42 
43 #ifdef CHRE_DAEMON_LPMA_ENABLED
44 constexpr bool kLpmaAllowed = true;
45 #else
46 constexpr bool kLpmaAllowed = false;
47 #endif  // CHRE_DAEMON_LPMA_ENABLED
48 
49 }  // namespace
50 
FastRpcChreDaemon()51 FastRpcChreDaemon::FastRpcChreDaemon() : mLpmaHandler(kLpmaAllowed) {}
52 
init()53 bool FastRpcChreDaemon::init() {
54   constexpr size_t kMaxTimeSyncRetries = 5;
55   constexpr useconds_t kTimeSyncRetryDelayUs = 50000;  // 50 ms
56 
57   int rc = -1;
58 
59 #ifdef CHRE_DAEMON_LOAD_INTO_SENSORSPD
60   remote_handle remote_handle_fd = 0xFFFFFFFF;
61   if (remote_handle_open(ITRANSPORT_PREFIX "createstaticpd:sensorspd",
62                          &remote_handle_fd)) {
63     LOGE("Failed to open remote handle for sensorspd");
64   } else {
65     LOGD("Successfully opened remote handle for sensorspd");
66   }
67 #endif  // CHRE_DAEMON_LOAD_INTO_SENSORSPD
68 
69   mLpmaHandler.init();
70 
71   if (!sendTimeSyncWithRetry(kMaxTimeSyncRetries, kTimeSyncRetryDelayUs,
72                              true /* logOnError */)) {
73     LOGE("Failed to send initial time sync message");
74   } else if ((rc = chre_slpi_initialize_reverse_monitor()) !=
75              CHRE_FASTRPC_SUCCESS) {
76     LOGE("Failed to initialize reverse monitor: (err) %d", rc);
77   } else if ((rc = chre_slpi_start_thread()) != CHRE_FASTRPC_SUCCESS) {
78     LOGE("Failed to start CHRE: (err) %d", rc);
79   } else {
80     mMonitorThread = std::thread(&FastRpcChreDaemon::monitorThreadEntry, this);
81     mMsgToHostThread =
82         std::thread(&FastRpcChreDaemon::msgToHostThreadEntry, this);
83     loadPreloadedNanoapps();
84     LOGI("CHRE started");
85   }
86 
87   return (rc == CHRE_FASTRPC_SUCCESS);
88 }
89 
deinit()90 void FastRpcChreDaemon::deinit() {
91   int rc;
92 
93   setShutdownRequested(true);
94 
95   if ((rc = chre_slpi_stop_thread()) != CHRE_FASTRPC_SUCCESS) {
96     LOGE("Failed to stop CHRE: (err) %d", rc);
97   }
98 
99   if (mMonitorThread.has_value()) {
100     mMonitorThread->join();
101   }
102   if (mMsgToHostThread.has_value()) {
103     mMsgToHostThread->join();
104   }
105 }
106 
run()107 void FastRpcChreDaemon::run() {
108   constexpr char kChreSocketName[] = "chre";
109   auto serverCb = [&](uint16_t clientId, void *data, size_t len) {
110     if (mCrashDetected) {
111       LOGW("Dropping data, CHRE restart in process...");
112     } else {
113       sendMessageToChre(clientId, data, len);
114     }
115   };
116 
117   // TODO: take 2nd argument as command-line parameter
118   mServer.run(kChreSocketName, true /* allowSocketCreation */, serverCb);
119 }
120 
doSendMessage(void * data,size_t length)121 bool FastRpcChreDaemon::doSendMessage(void *data, size_t length) {
122   // This limitation is due to FastRPC, but there's no case
123   // where we should come close to this limit
124   constexpr size_t kMaxPayloadSize = 1024 * 1024;  // 1 MiB
125   static_assert(kMaxPayloadSize <= INT32_MAX,
126                 "DSP uses 32-bit signed integers to represent message size");
127 
128   bool success = false;
129   if (length > kMaxPayloadSize) {
130     LOGE("Message too large (got %zu, max %zu bytes)", length, kMaxPayloadSize);
131   } else {
132     int ret = chre_slpi_deliver_message_from_host(
133         static_cast<const unsigned char *>(data), static_cast<int>(length));
134     if (ret != CHRE_FASTRPC_SUCCESS) {
135       LOGE("Failed to deliver message from host to CHRE: %d", ret);
136     } else {
137       success = true;
138     }
139   }
140 
141   return success;
142 }
143 
monitorThreadEntry()144 void FastRpcChreDaemon::monitorThreadEntry() {
145   LOGD("Monitor thread started");
146 
147   int ret = chre_slpi_wait_on_thread_exit();
148   if (!wasShutdownRequested()) {
149     LOGE("Monitor detected unexpected CHRE thread exit (%d)", ret);
150     onRemoteCrashDetected();
151   }
152   LOGD("Monitor thread exited");
153 }
154 
msgToHostThreadEntry()155 void FastRpcChreDaemon::msgToHostThreadEntry() {
156   unsigned char messageBuffer[4096];
157   unsigned int messageLen;
158   int result = 0;
159 
160   LOGD("MsgToHost thread started");
161 
162   while (true) {
163     messageLen = 0;
164     LOGV("Calling into chre_slpi_get_message_to_host");
165     result = chre_slpi_get_message_to_host(messageBuffer, sizeof(messageBuffer),
166                                            &messageLen);
167     LOGV("Got message from CHRE with size %u (result %d)", messageLen, result);
168 
169     if (result == CHRE_FASTRPC_ERROR_SHUTTING_DOWN) {
170       LOGD("CHRE shutting down, exiting CHRE->Host message thread");
171       break;
172     } else if (result == CHRE_FASTRPC_SUCCESS && messageLen > 0) {
173       onMessageReceived(messageBuffer, messageLen);
174     } else if (!wasShutdownRequested()) {
175       LOGE("get_message_to_host returned unexpected error (%d)", result);
176       onRemoteCrashDetected();
177     } else {
178       // Received an unknown result but a shutdown was requested. Break from
179       // the loop to allow the daemon to cleanup.
180       break;
181     }
182   }
183   LOGD("Message to host thread exited");
184 }
185 
getTimeOffset(bool * success)186 int64_t FastRpcChreDaemon::getTimeOffset(bool *success) {
187   int64_t timeOffset = 0;
188 
189 #if defined(__aarch64__)
190   // Reads the system time counter (CNTVCT) and its frequency (CNTFRQ)
191   // CNTVCT is used in the sensors HAL for time synchronization.
192   // More information can be found in the ARM reference manual
193   // (http://infocenter.arm.com/help/index.jsp?topic=
194   // /com.arm.doc.100048_0002_05_en/jfa1406793266982.html)
195   // Use uint64_t to store since the MRS instruction uses 64 bit (X) registers
196   // (http://infocenter.arm.com/help/topic/
197   // com.arm.doc.den0024a/ch06s05s02.html)
198   uint64_t qTimerCount = 0, qTimerFreq = 0;
199   uint64_t hostTimeNano = elapsedRealtimeNano();
200   asm volatile("mrs %0, cntvct_el0" : "=r"(qTimerCount));
201   asm volatile("mrs %0, cntfrq_el0" : "=r"(qTimerFreq));
202 
203   constexpr uint64_t kOneSecondInNanoseconds = 1000000000;
204   if (qTimerFreq != 0) {
205     // Get the seconds part first, then convert the remainder to prevent
206     // overflow
207     uint64_t qTimerNanos = (qTimerCount / qTimerFreq);
208     if (qTimerNanos > UINT64_MAX / kOneSecondInNanoseconds) {
209       LOGE(
210           "CNTVCT_EL0 conversion to nanoseconds overflowed during time sync. "
211           "Aborting time sync.");
212       *success = false;
213     } else {
214       qTimerNanos *= kOneSecondInNanoseconds;
215 
216       // Round the remainder portion to the nearest nanosecond
217       uint64_t remainder = (qTimerCount % qTimerFreq);
218       qTimerNanos +=
219           (remainder * kOneSecondInNanoseconds + qTimerFreq / 2) / qTimerFreq;
220 
221       timeOffset = hostTimeNano - qTimerNanos;
222       *success = true;
223     }
224   } else {
225     LOGE("CNTFRQ_EL0 had 0 value. Aborting time sync.");
226     *success = false;
227   }
228 #else
229 #error "Unsupported CPU architecture type"
230 #endif
231 
232   return timeOffset;
233 }
234 
onRemoteCrashDetected()235 void FastRpcChreDaemon::onRemoteCrashDetected() {
236   // After a DSP crash, we delay a short period of time before exiting. This is
237   // primarily to avoid any potential race conditions arising from trying to
238   // initialize CHRE very early in the DSP boot flow. Normally the firmware is
239   // reloaded within a second or so, but we use a longer time here to have some
240   // padding to handle cases where the system is slower than usual, etc.
241   constexpr auto kDelayAfterCrash = std::chrono::seconds(3);
242 
243   // It's technically fine if multiple threads race here, but to avoid duplicate
244   // logs, give the first one to reach this point a shorter delay than others
245   bool firstDetection = !mCrashDetected.exchange(true);
246   auto delay = (firstDetection) ? kDelayAfterCrash : kDelayAfterCrash * 2;
247   std::this_thread::sleep_for(delay);
248   LOGE("Exiting daemon");
249   std::exit(EXIT_FAILURE);
250 }
251 
252 }  // namespace chre
253 }  // namespace android
254