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 #ifndef CHRE_PLATFORM_LOG_BUFFER_MANAGER_BUFFER_H_
18 #define CHRE_PLATFORM_LOG_BUFFER_MANAGER_BUFFER_H_
19 
20 #include "chre/platform/assert.h"
21 #include "chre/platform/condition_variable.h"
22 #include "chre/platform/mutex.h"
23 #include "chre/platform/shared/bt_snoop_log.h"
24 #include "chre/platform/shared/generated/host_messages_generated.h"
25 #include "chre/platform/shared/log_buffer.h"
26 #include "chre/util/singleton.h"
27 #include "chre_api/chre/re.h"
28 
29 #ifndef CHRE_LOG_BUFFER_DATA_SIZE
30 #define CHRE_LOG_BUFFER_DATA_SIZE CHRE_MESSAGE_TO_HOST_MAX_SIZE
31 #endif
32 
33 namespace chre {
34 
35 using LogType = fbs::LogType;
36 
37 /**
38  * A log buffer manager that platform code can use to buffer logs when the host
39  * is not available and then send them off when the host becomes available. Uses
40  * the LogBuffer API to buffer the logs in memory.
41  *
42  * The manager uses two LogBuffer objects to handle flushing logs to the host at
43  * the same time as handling more incoming logs. Incoming logs are always put
44  * into the primary buffer first. The secondary buffer takes all the logs
45  * currently in the primary buffer before the logs are sent off to the host
46  * because the secondary buffer is the memory location passed to the
47  * HostLink::sendLogs API. Logs are also flushed to the secondary buffer from
48  * the primary buffer when the primary buffer fills up.
49  *
50  * When implementing this class in platform code. Use the singleton defined
51  * after this class and pass logs to the log or logVa methods. Initialize the
52  * singleton before using it. Call the onLogsSentToHost callback immediately
53  * after sending logs to the host.
54  */
55 class LogBufferManager : public LogBufferCallbackInterface {
56  public:
LogBufferManager(uint8_t * primaryBufferData,uint8_t * secondaryBufferData,size_t bufferSize)57   LogBufferManager(uint8_t *primaryBufferData, uint8_t *secondaryBufferData,
58                    size_t bufferSize)
59       : mPrimaryLogBuffer(this, primaryBufferData, bufferSize),
60         mSecondaryLogBuffer(nullptr /* callback */, secondaryBufferData,
61                             bufferSize) {}
62 
63   ~LogBufferManager() = default;
64 
65   /**
66    * Logs message with printf-style arguments. No trailing newline is required
67    * for this method.
68    */
69   void log(chreLogLevel logLevel, const char *formatStr, ...);
70 
71   /**
72    * Similar as log() but with a log buffer and a log size argument instead
73    * of a printf-style arguments.
74    *
75    * @param logs Pointer to the buffer containing the encoded log message.
76    * @param logSize Size of the encoded logs.
77    */
78   void logEncoded(chreLogLevel logLevel, const uint8_t *encodedLog,
79                   size_t encodedLogSize);
80 
81   /**
82    * Log via the pigweed tokenized logging format for nanoapps. The log message
83    * message is tokenized and will be decoded into printf style strings at the
84    * receiver.
85    *
86    * @param level Logging level.
87    * @param instanceId The instance ID of the nanoapp which sends the log.
88    * @param msg A byte buffer containing the tokenized log message.
89    * @param msgSize Size of the tokenized log message buffer.
90    */
91   void logNanoappTokenized(chreLogLevel logLevel, uint16_t instanceID,
92                            const uint8_t *msg, size_t msgSize);
93 
94   /**
95    * Logs message with printf-style arguments. No trailing newline is required
96    * for this method. Uses va_list parameter instead of ...
97    */
98   void logVa(chreLogLevel logLevel, const char *formatStr, va_list args);
99 
100   /**
101    * Logs BT commands and events. These logs will not be displayed on logcat.
102    * The BT events will be handled with a bt snoop log parser.
103    */
104   void logBtSnoop(BtSnoopDirection direction, const uint8_t *buffer,
105                   size_t size);
106 
107   /**
108    * Overrides required method from LogBufferCallbackInterface.
109    */
110   void onLogsReady() final;
111 
112   /**
113    * Flush any logs that might be in the default log buffer.
114    */
115   void flushLogs();
116 
117   /**
118    * The platform code should call this method after the logs have been sent to
119    * the host to signal that more logs can be sent to the host when ready. The
120    * caller must indicate whether the platform could successfully deliver the
121    * logs as well.
122    *
123    * @param success true if the logs were sent through to host successfully.
124    */
125   void onLogsSentToHost(bool success);
126 
127   /**
128    * Loop that waits on the conditions for sending logs to host to be met and
129    * sends the logs to the host if so. This method never exits. Should be called
130    * by a platform thread.
131    */
132   void startSendLogsToHostLoop();
133 
134  private:
135   /*
136    * @return The LogBuffer log level for the given CHRE log level.
137    */
138   LogBufferLogLevel chreToLogBufferLogLevel(chreLogLevel chreLogLevel);
139 
140   /**
141    * Perform any setup needed by the plaform before the secondary buffer is
142    * used.
143    *
144    * Implemented by the platform.
145    */
146   void preSecondaryBufferUse() const;
147 
148   /**
149    * Same as onLogsSentToHost, but without locking. The calling code should have
150    * the flush logs mutex locked before calling this method.
151    *
152    * @param success true if the logs were successfully delivered to the host.
153    */
154   void onLogsSentToHostLocked(bool success);
155 
156   uint32_t getTimestampMs();
157 
158   void bufferOverflowGuard(size_t logSize, LogType type);
159 
160   LogBuffer mPrimaryLogBuffer;
161   LogBuffer mSecondaryLogBuffer;
162 
163   size_t mNumLogsDroppedTotal = 0;
164 
165   ConditionVariable mSendLogsToHostCondition;
166   bool mLogFlushToHostPending = false;
167   bool mLogsBecameReadyWhileFlushPending = false;
168   Mutex mFlushLogsMutex;
169 };
170 
171 //! Provides an alias to the LogBufferManager singleton.
172 typedef Singleton<LogBufferManager> LogBufferManagerSingleton;
173 
174 //! Extern the explicit LogBufferManagerSingleton to force non-inline calls.
175 //! This reduces codesize considerably.
176 extern template class Singleton<LogBufferManager>;
177 
178 }  // namespace chre
179 
180 #endif  // CHRE_PLATFORM_LOG_BUFFER_MANAGER_H_
181