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 "chre/core/debug_dump_manager.h"
18 
19 #include <cstring>
20 
21 #include "chre/core/event_loop_manager.h"
22 #include "chre/core/settings.h"
23 
24 namespace chre {
25 
trigger()26 void DebugDumpManager::trigger() {
27   auto callback = [](uint16_t /*type*/, void * /*data*/, void * /*extraData*/) {
28     DebugDumpManager &debugDumpManager =
29         EventLoopManagerSingleton::get()->getDebugDumpManager();
30     debugDumpManager.collectFrameworkDebugDumps();
31     debugDumpManager.sendFrameworkDebugDumps();
32   };
33 
34   // Collect CHRE framework debug dumps.
35   EventLoopManagerSingleton::get()->deferCallback(
36       SystemCallbackType::PerformDebugDump, nullptr /*data*/, callback);
37 
38   auto nappCallback = [](uint16_t /*eventType*/, void * /*eventData*/) {
39     EventLoopManagerSingleton::get()
40         ->getDebugDumpManager()
41         .sendNanoappDebugDumps();
42   };
43 
44   // Notify nanoapps to collect debug dumps.
45   EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
46       CHRE_EVENT_DEBUG_DUMP, nullptr /*eventData*/, nappCallback);
47 }
48 
appendNanoappLog(const Nanoapp & nanoapp,const char * formatStr,va_list args)49 void DebugDumpManager::appendNanoappLog(const Nanoapp &nanoapp,
50                                         const char *formatStr, va_list args) {
51   uint32_t instanceId = nanoapp.getInstanceId();
52 
53   // Note this check isn't exact as it's possible that the nanoapp isn't
54   // handling CHRE_EVENT_DEBUG_DUMP. This approximate check is used for its low
55   // complexity as it doesn't introduce any real harms.
56   if (!mCollectingNanoappDebugDumps) {
57     LOGW("Nanoapp instance %" PRIu32
58          " logging debug data while not in an active debug dump session",
59          instanceId);
60   } else if (formatStr != nullptr) {
61     // Log nanoapp info the first time it adds debug data in this session.
62     if (!mLastNanoappId.has_value() || mLastNanoappId.value() != instanceId) {
63       mLastNanoappId = instanceId;
64       mDebugDump.print("\n\n %s 0x%016" PRIx64 ":\n", nanoapp.getAppName(),
65                        nanoapp.getAppId());
66     }
67 
68     mDebugDump.printVaList(formatStr, args);
69   }
70 }
71 
collectFrameworkDebugDumps()72 void DebugDumpManager::collectFrameworkDebugDumps() {
73   auto *eventLoopManager = EventLoopManagerSingleton::get();
74   eventLoopManager->getMemoryManager().logStateToBuffer(mDebugDump);
75   eventLoopManager->getEventLoop().handleNanoappWakeupBuckets();
76   eventLoopManager->getEventLoop().logStateToBuffer(mDebugDump);
77 #ifdef CHRE_SENSORS_SUPPORT_ENABLED
78   eventLoopManager->getSensorRequestManager().logStateToBuffer(mDebugDump);
79 #endif  // CHRE_SENSORS_SUPPORT_ENABLED
80 #ifdef CHRE_GNSS_SUPPORT_ENABLED
81   eventLoopManager->getGnssManager().logStateToBuffer(mDebugDump);
82 #endif  // CHRE_GNSS_SUPPORT_ENABLED
83 #ifdef CHRE_WIFI_SUPPORT_ENABLED
84   eventLoopManager->getWifiRequestManager().logStateToBuffer(mDebugDump);
85 #endif  // CHRE_WIFI_SUPPORT_ENABLED
86 #ifdef CHRE_WWAN_SUPPORT_ENABLED
87   eventLoopManager->getWwanRequestManager().logStateToBuffer(mDebugDump);
88 #endif  // CHRE_WWAN_SUPPORT_ENABLED
89 #ifdef CHRE_AUDIO_SUPPORT_ENABLED
90   eventLoopManager->getAudioRequestManager().logStateToBuffer(mDebugDump);
91 #endif  // CHRE_AUDIO_SUPPORT_ENABLED
92   logSettingStateToBuffer(mDebugDump);
93   logStateToBuffer(mDebugDump);
94 }
95 
sendFrameworkDebugDumps()96 void DebugDumpManager::sendFrameworkDebugDumps() {
97   for (size_t i = 0; i < mDebugDump.getBuffers().size(); i++) {
98     const auto &buff = mDebugDump.getBuffers()[i];
99     sendDebugDump(buff.get(), false /*complete*/);
100   }
101 
102   // Clear out buffers before nanoapp debug dumps to reduce peak memory usage.
103   mDebugDump.clear();
104 
105   // Mark the beginning of nanoapp debug dumps
106   mDebugDump.print("\n\nNanoapp debug dumps:");
107   mCollectingNanoappDebugDumps = true;
108 }
109 
sendNanoappDebugDumps()110 void DebugDumpManager::sendNanoappDebugDumps() {
111   // Avoid buffer underflow when mDebugDump failed to allocate buffers.
112   size_t numBuffers = mDebugDump.getBuffers().size();
113   if (numBuffers > 0) {
114     for (size_t i = 0; i < numBuffers - 1; i++) {
115       const auto &buff = mDebugDump.getBuffers()[i];
116       sendDebugDump(buff.get(), false /*complete*/);
117     }
118   }
119 
120   const char *debugStr =
121       (numBuffers > 0) ? mDebugDump.getBuffers().back().get() : "";
122   sendDebugDump(debugStr, true /*complete*/);
123 
124   // Clear current session debug dumps and release memory.
125   mDebugDump.clear();
126   mLastNanoappId.reset();
127   mCollectingNanoappDebugDumps = false;
128 }
129 
130 }  // namespace chre
131