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