| /* |
| * 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 "chre/core/debug_dump_manager.h" |
| |
| #include <cstring> |
| |
| #include "chre/core/event_loop_manager.h" |
| #include "chre/core/settings.h" |
| |
| namespace chre { |
| |
| void DebugDumpManager::trigger() { |
| auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) { |
| DebugDumpManager &debugDumpManager = |
| EventLoopManagerSingleton::get()->getDebugDumpManager(); |
| debugDumpManager.collectFrameworkDebugDumps(); |
| debugDumpManager.sendFrameworkDebugDumps(); |
| }; |
| |
| // Collect CHRE framework debug dumps. |
| EventLoopManagerSingleton::get()->deferCallback( |
| SystemCallbackType::PerformDebugDump, nullptr /*data*/, callback); |
| |
| auto nappCallback = [](uint16_t /*eventType*/, void * /*eventData*/) { |
| EventLoopManagerSingleton::get() |
| ->getDebugDumpManager() |
| .sendNanoappDebugDumps(); |
| }; |
| |
| // Notify nanoapps to collect debug dumps. |
| EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( |
| CHRE_EVENT_DEBUG_DUMP, nullptr /*eventData*/, nappCallback); |
| } |
| |
| void DebugDumpManager::appendNanoappLog(const Nanoapp &nanoapp, |
| const char *formatStr, va_list args) { |
| uint16_t instanceId = nanoapp.getInstanceId(); |
| |
| // Note this check isn't exact as it's possible that the nanoapp isn't |
| // handling CHRE_EVENT_DEBUG_DUMP. This approximate check is used for its low |
| // complexity as it doesn't introduce any real harms. |
| if (!mCollectingNanoappDebugDumps) { |
| LOGW("Nanoapp instance %" PRIu16 |
| " logging debug data while not in an active debug dump session", |
| instanceId); |
| } else if (formatStr != nullptr) { |
| // Log nanoapp info the first time it adds debug data in this session. |
| if (!mLastNanoappId.has_value() || mLastNanoappId.value() != instanceId) { |
| mLastNanoappId = instanceId; |
| mDebugDump.print("\n\n %s 0x%016" PRIx64 ":\n", nanoapp.getAppName(), |
| nanoapp.getAppId()); |
| } |
| |
| mDebugDump.printVaList(formatStr, args); |
| } |
| } |
| |
| void DebugDumpManager::collectFrameworkDebugDumps() { |
| auto *eventLoopManager = EventLoopManagerSingleton::get(); |
| eventLoopManager->getMemoryManager().logStateToBuffer(mDebugDump); |
| eventLoopManager->getEventLoop().handleNanoappWakeupBuckets(); |
| eventLoopManager->getEventLoop().logStateToBuffer(mDebugDump); |
| #ifdef CHRE_SENSORS_SUPPORT_ENABLED |
| eventLoopManager->getSensorRequestManager().logStateToBuffer(mDebugDump); |
| #endif // CHRE_SENSORS_SUPPORT_ENABLED |
| #ifdef CHRE_GNSS_SUPPORT_ENABLED |
| eventLoopManager->getGnssManager().logStateToBuffer(mDebugDump); |
| #endif // CHRE_GNSS_SUPPORT_ENABLED |
| #ifdef CHRE_WIFI_SUPPORT_ENABLED |
| eventLoopManager->getWifiRequestManager().logStateToBuffer(mDebugDump); |
| #endif // CHRE_WIFI_SUPPORT_ENABLED |
| #ifdef CHRE_WWAN_SUPPORT_ENABLED |
| eventLoopManager->getWwanRequestManager().logStateToBuffer(mDebugDump); |
| #endif // CHRE_WWAN_SUPPORT_ENABLED |
| #ifdef CHRE_AUDIO_SUPPORT_ENABLED |
| eventLoopManager->getAudioRequestManager().logStateToBuffer(mDebugDump); |
| #endif // CHRE_AUDIO_SUPPORT_ENABLED |
| #ifdef CHRE_BLE_SUPPORT_ENABLED |
| eventLoopManager->getBleRequestManager().logStateToBuffer(mDebugDump); |
| #endif // CHRE_BLE_SUPPORT_ENABLED |
| eventLoopManager->getSettingManager().logStateToBuffer(mDebugDump); |
| logStateToBuffer(mDebugDump); |
| } |
| |
| void DebugDumpManager::sendFrameworkDebugDumps() { |
| for (size_t i = 0; i < mDebugDump.getBuffers().size(); i++) { |
| const auto &buff = mDebugDump.getBuffers()[i]; |
| sendDebugDump(buff.get(), false /*complete*/); |
| } |
| |
| // Clear out buffers before nanoapp debug dumps to reduce peak memory usage. |
| mDebugDump.clear(); |
| |
| // Mark the beginning of nanoapp debug dumps |
| mDebugDump.print("\n\nNanoapp debug dumps:"); |
| mCollectingNanoappDebugDumps = true; |
| } |
| |
| void DebugDumpManager::sendNanoappDebugDumps() { |
| // Avoid buffer underflow when mDebugDump failed to allocate buffers. |
| size_t numBuffers = mDebugDump.getBuffers().size(); |
| if (numBuffers > 0) { |
| for (size_t i = 0; i < numBuffers - 1; i++) { |
| const auto &buff = mDebugDump.getBuffers()[i]; |
| sendDebugDump(buff.get(), false /*complete*/); |
| } |
| } |
| |
| const char *debugStr = |
| (numBuffers > 0) ? mDebugDump.getBuffers().back().get() : ""; |
| sendDebugDump(debugStr, true /*complete*/); |
| |
| // Clear current session debug dumps and release memory. |
| mDebugDump.clear(); |
| mLastNanoappId.reset(); |
| mCollectingNanoappDebugDumps = false; |
| } |
| |
| } // namespace chre |