/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "chre_host/config_util.h" #include "chre_host/daemon_base.h" #include "chre_host/file_stream.h" #include "chre_host/log.h" #include "chre_host/napp_header.h" #ifdef CHRE_DAEMON_METRIC_ENABLED #include #include #include #endif // CHRE_DAEMON_METRIC_ENABLED // Aliased for consistency with the way these symbols are referenced in // CHRE-side code namespace fbs = ::chre::fbs; namespace android { namespace chre { #ifdef CHRE_DAEMON_METRIC_ENABLED using ::aidl::android::frameworks::stats::IStats; using ::aidl::android::frameworks::stats::VendorAtom; using ::aidl::android::frameworks::stats::VendorAtomValue; using ::android::chre::Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED; using ::android::chre::Atoms::CHRE_PAL_OPEN_FAILED; using ::android::chre::Atoms::ChrePalOpenFailed; #endif // CHRE_DAEMON_METRIC_ENABLED namespace { void signalHandler(void *ctx) { auto *daemon = static_cast(ctx); int rc = -1; sigset_t signalMask; sigfillset(&signalMask); sigdelset(&signalMask, SIGINT); sigdelset(&signalMask, SIGTERM); if (sigprocmask(SIG_SETMASK, &signalMask, NULL) != 0) { LOG_ERROR("Couldn't mask all signals except INT/TERM", errno); } while (true) { int signum = 0; if ((rc = sigwait(&signalMask, &signum)) != 0) { LOGE("Sigwait failed: %d", rc); } LOGI("Received signal %d", signum); if (signum == SIGINT || signum == SIGTERM) { daemon->onShutdown(); break; } } } } // anonymous namespace ChreDaemonBase::ChreDaemonBase() : mChreShutdownRequested(false) { mLogger.init(); // TODO(b/297388964): Replace thread with handler installed via std::signal() mSignalHandlerThread = std::thread(signalHandler, this); } void ChreDaemonBase::loadPreloadedNanoapps() { const std::string kPreloadedNanoappsConfigPath = "/vendor/etc/chre/preloaded_nanoapps.json"; std::string directory; std::vector nanoapps; bool success = getPreloadedNanoappsFromConfigFile( kPreloadedNanoappsConfigPath, directory, nanoapps); if (!success) { LOGE("Failed to parse preloaded nanoapps config file"); return; } for (uint32_t i = 0; i < nanoapps.size(); ++i) { loadPreloadedNanoapp(directory, nanoapps[i], i); } } void ChreDaemonBase::loadPreloadedNanoapp(const std::string &directory, const std::string &name, uint32_t transactionId) { std::vector headerBuffer; std::string headerFile = directory + "/" + name + ".napp_header"; // Only create the nanoapp filename as the CHRE framework will load from // within the directory its own binary resides in. std::string nanoappFilename = name + ".so"; if (!readFileContents(headerFile.c_str(), headerBuffer) || !loadNanoapp(headerBuffer, nanoappFilename, transactionId)) { LOGE("Failed to load nanoapp: '%s'", name.c_str()); } } bool ChreDaemonBase::loadNanoapp(const std::vector &header, const std::string &nanoappName, uint32_t transactionId) { bool success = false; if (header.size() != sizeof(NanoAppBinaryHeader)) { LOGE("Header size mismatch"); } else { // The header blob contains the struct above. const auto *appHeader = reinterpret_cast(header.data()); // Build the target API version from major and minor. uint32_t targetApiVersion = (appHeader->targetChreApiMajorVersion << 24) | (appHeader->targetChreApiMinorVersion << 16); success = sendNanoappLoad(appHeader->appId, appHeader->appVersion, targetApiVersion, nanoappName, transactionId); } return success; } bool ChreDaemonBase::sendTimeSyncWithRetry(size_t numRetries, useconds_t retryDelayUs, bool logOnError) { bool success = false; while (!success && (numRetries-- != 0)) { success = sendTimeSync(logOnError); if (!success) { usleep(retryDelayUs); } } return success; } void ChreDaemonBase::handleNanConfigurationRequest( const ::chre::fbs::NanConfigurationRequestT * /*request*/) { LOGE("NAN is unsupported on this platform"); } #ifdef CHRE_DAEMON_METRIC_ENABLED void ChreDaemonBase::handleMetricLog(const ::chre::fbs::MetricLogT *metricMsg) { const std::vector &encodedMetric = metricMsg->encoded_metric; switch (metricMsg->id) { case CHRE_PAL_OPEN_FAILED: { metrics::ChrePalOpenFailed metric; if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) { LOGE("Failed to parse metric data"); } else { ChrePalOpenFailed::ChrePalType pal = static_cast(metric.pal()); ChrePalOpenFailed::Type type = static_cast(metric.type()); if (!mMetricsReporter.logPalOpenFailed(pal, type)) { LOGE("Could not log the PAL open failed metric"); } } break; } case CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED: { metrics::ChreEventQueueSnapshotReported metric; if (!metric.ParseFromArray(encodedMetric.data(), encodedMetric.size())) { LOGE("Failed to parse metric data"); } else if (!mMetricsReporter.logEventQueueSnapshotReported( metric.snapshot_chre_get_time_ms(), metric.max_event_queue_size(), metric.mean_event_queue_size(), metric.num_dropped_events())) { LOGE("Could not log the event queue snapshot metric"); } break; } default: { #ifdef CHRE_LOG_ATOM_EXTENSION_ENABLED handleVendorMetricLog(metricMsg); #else LOGW("Unknown metric ID %" PRIu32, metricMsg->id); #endif // CHRE_LOG_ATOM_EXTENSION_ENABLED } } } void ChreDaemonBase::reportMetric(const VendorAtom &atom) { const std::string statsServiceName = std::string(IStats::descriptor).append("/default"); if (!AServiceManager_isDeclared(statsServiceName.c_str())) { LOGE("Stats service is not declared."); return; } std::shared_ptr stats_client = IStats::fromBinder(ndk::SpAIBinder( AServiceManager_waitForService(statsServiceName.c_str()))); if (stats_client == nullptr) { LOGE("Failed to get IStats service"); return; } const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(atom); if (!ret.isOk()) { LOGE("Failed to report vendor atom"); } } #endif // CHRE_DAEMON_METRIC_ENABLED } // namespace chre } // namespace android