• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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_CORE_NANOAPP_H_
18 #define CHRE_CORE_NANOAPP_H_
19 
20 #include <cinttypes>
21 #include <cstdint>
22 #include <limits>
23 
24 #include "chre/core/event.h"
25 #include "chre/core/event_ref_queue.h"
26 #include "chre/platform/heap_block_header.h"
27 #include "chre/platform/platform_nanoapp.h"
28 #include "chre/platform/system_time.h"
29 #include "chre/util/dynamic_vector.h"
30 #include "chre/util/fixed_size_vector.h"
31 #include "chre/util/system/debug_dump.h"
32 #include "chre/util/system/napp_permissions.h"
33 #include "chre/util/system/stats_container.h"
34 #include "chre_api/chre/event.h"
35 
36 namespace chre {
37 
38 /**
39  * A class that tracks the state of a Nanoapp including incoming events and
40  * event registrations.
41  *
42  * Inheritance is used to separate the common interface with common
43  * implementation part (chre::Nanoapp) from the common interface with
44  * platform-specific implementation part (chre::PlatformNanoapp) from the purely
45  * platform-specific part (chre::PlatformNanoappBase). However, this inheritance
46  * relationship does *not* imply polymorphism, and this object must only be
47  * referred to via the most-derived type, i.e. chre::Nanoapp.
48  */
49 class Nanoapp : public PlatformNanoapp {
50  public:
51   /** @see chrePublishRpcServices */
52   static constexpr size_t kMaxRpcServices = UINT8_MAX;
53   static_assert(
54       std::numeric_limits<decltype(chreNanoappInfo::rpcServiceCount)>::max() >=
55           kMaxRpcServices,
56       "Revisit the constant");
57 
58   Nanoapp();
59 
60   // The nanoapp instance ID should only come from the event loop manager. This
61   // constructor should never be called except for use in unit tests.
62   Nanoapp(uint16_t instanceId);
63 
64   /**
65    * Calls the start function of the nanoapp. For dynamically loaded nanoapps,
66    * this must also result in calling through to any of the nanoapp's static
67    * global constructors/init functions, etc., prior to invoking the
68    * nanoappStart.
69    *
70    * @return true if the app was able to start successfully
71    *
72    * @see nanoappStart
73    */
74   bool start();
75 
76   /**
77    * @return The unique identifier for this Nanoapp instance
78    */
getInstanceId()79   uint16_t getInstanceId() const {
80     return mInstanceId;
81   }
82 
83   /**
84    * @return The current total number of bytes the nanoapp has allocated.
85    */
getTotalAllocatedBytes()86   size_t getTotalAllocatedBytes() const {
87     return mTotalAllocatedBytes;
88   }
89 
90   /**
91    * @return The peak total number of bytes the nanoapp has allocated.
92    */
getPeakAllocatedBytes()93   size_t getPeakAllocatedBytes() const {
94     return mPeakAllocatedBytes;
95   }
96 
97   /**
98    * Sets the total number of bytes the nanoapp has allocated. Also, modifies
99    * the peak allocated bytes if the current total is higher than the peak.
100    *
101    * @param The total number of bytes the nanoapp has allocated.
102    */
setTotalAllocatedBytes(size_t totalAllocatedBytes)103   void setTotalAllocatedBytes(size_t totalAllocatedBytes) {
104     mTotalAllocatedBytes = totalAllocatedBytes;
105     if (mTotalAllocatedBytes > mPeakAllocatedBytes) {
106       mPeakAllocatedBytes = mTotalAllocatedBytes;
107     }
108   }
109 
110   /**
111    * @return true if the nanoapp should receive broadcast event
112    */
113   bool isRegisteredForBroadcastEvent(const Event *event) const;
114 
115   /**
116    * Updates the Nanoapp's registration so that it will receive broadcast events
117    * with the given event type.
118    *
119    * @param eventType The event type that the nanoapp will now be registered to
120    *     receive
121    * @param groupIdMask A mask of group IDs to register the nanoapp for. If an
122    *     event is sent that targets any of the group IDs in the mask, it will
123    *     be delivered to the nanoapp.
124    */
125   void registerForBroadcastEvent(
126       uint16_t eventType, uint16_t groupIdMask = kDefaultTargetGroupMask);
127 
128   /**
129    * Updates the Nanoapp's registration so that it will not receive broadcast
130    * events with the given event type.
131    *
132    * @param eventType The event type that the nanoapp will be unregistered from
133    *    assuming the group ID also matches a valid entry.
134    * @param groupIdMask The mask of group IDs that will be unregistered from.
135    */
136   void unregisterForBroadcastEvent(
137       uint16_t eventType, uint16_t groupIdMask = kDefaultTargetGroupMask);
138 
139   /**
140    * Configures whether nanoapp info events will be sent to the nanoapp.
141    * Nanoapps are not sent nanoapp start/stop events by default.
142    *
143    * @param enable true if events are to be sent, false otherwise.
144    */
145   void configureNanoappInfoEvents(bool enable);
146 
147   /**
148    * Configures whether host sleep events will be sent to the nanoapp. Nanoapps
149    * are not sent sleep/awake events by default.
150    *
151    * @param enable true if events are to be sent, false otherwise.
152    */
153   void configureHostSleepEvents(bool enable);
154 
155   /**
156    * Configures whether debug dump events will be sent to the nanoapp. Nanoapps
157    * are not sent debug dump events by default.
158    *
159    * @param enable true if events are to be sent, false otherwise.
160    */
161   void configureDebugDumpEvent(bool enable);
162 
163   /**
164    * Configures whether a user settings event will be sent to the nanoapp
165    * for a specified setting (@see CHRE_USER_SETTINGS)
166    * Nanoapps are not sent user settings events by default.
167    *
168    * @param setting The user setting that the nanoapp wishes to configure
169    * events for.
170    *
171    * @param enable true if events are to be sent, false otherwise.
172    */
173   void configureUserSettingEvent(uint8_t setting, bool enable);
174 
175   /**
176    * Sends an event to the nanoapp to be processed.
177    *
178    * @param event A pointer to the event to be processed
179    */
180   void processEvent(Event *event);
181 
182   /**
183    * Log info about a single host wakeup that this nanoapp triggered by storing
184    * the count of wakeups in mWakeupBuckets.
185    */
186   void blameHostWakeup();
187 
188   /**
189    * Log info about a single message sent to the host that this nanoapp
190    * triggered by storing the count of messages in mNumMessagesSentSinceBoot.
191    */
192   void blameHostMessageSent();
193 
194   /*
195    * If buckets not full, then just pushes a 0 to back of buckets. If full, then
196    * shifts down all buckets from back to front and sets back to 0, losing the
197    * latest bucket value that was in front.
198    *
199    * With nanoapps tracking their cycling time, there is no reason to ever
200    * cycle more than one bucket at a time. Doing more wastes valuable data
201    *
202    * @param timestamp the current time when this bucket was created
203    */
204   void cycleWakeupBuckets(Nanoseconds timestamp);
205 
206   /**
207    * Prints state in a string buffer. Must only be called from the context of
208    * the main CHRE thread.
209    *
210    * @param debugDump The object that is printed into for debug dump logs.
211    */
212   void logStateToBuffer(DebugDumpWrapper &debugDump) const;
213 
214   /**
215    * Prints header for memory allocation and event processing time stats table
216    * in a string buffer. Must only be called from the context of the main CHRE
217    * thread.
218    *
219    * @param debugDump The object that is printed into for debug dump logs.
220    */
221   void logMemAndComputeHeader(DebugDumpWrapper &debugDump) const;
222 
223   /**
224    * Prints memory allocation and event processing time stats in a string
225    * buffer. Must only be called from the context of the main CHRE thread.
226    *
227    * @param debugDump The object that is printed into for debug dump logs.
228    */
229   void logMemAndComputeEntry(DebugDumpWrapper &debugDump) const;
230 
231   /**
232    * Prints header for wakeup and host message stats table in a string buffer.
233    * Must only be called from the context of the main CHRE thread.
234    *
235    * @param debugDump The object that is printed into for debug dump logs.
236    */
237   void logMessageHistoryHeader(DebugDumpWrapper &debugDump) const;
238 
239   /**
240    * Prints wakeup and host message stats in a string buffer. Must only be
241    * called from the context of the main CHRE thread.
242    *
243    * @param debugDump The object that is printed into for debug dump logs.
244    */
245   void logMessageHistoryEntry(DebugDumpWrapper &debugDump) const;
246 
247   /**
248    * @return true if the nanoapp is permitted to use the provided permission.
249    */
250   bool permitPermissionUse(uint32_t permission) const;
251 
252   /**
253    * Configures notification updates for a given host endpoint.
254    *
255    * @param hostEndpointId The ID of the host endpoint.
256    * @param enable true to enable notifications.
257    *
258    * @return true if the configuration is successful.
259    */
260   bool configureHostEndpointNotifications(uint16_t hostEndpointId, bool enable);
261 
262   /**
263    * Publishes RPC services for this nanoapp.
264    *
265    * @param services A pointer to the list of RPC services to publish.
266    *   Can be null if numServices is 0.
267    * @param numServices The number of services to publish, i.e. the length of
268    * the services array.
269    *
270    * @return true if the publishing is successful.
271    */
272   bool publishRpcServices(struct chreNanoappRpcService *services,
273                           size_t numServices);
274 
275   /**
276    * @return The list of RPC services published by this nanoapp.
277    */
getRpcServices()278   const DynamicVector<struct chreNanoappRpcService> &getRpcServices() const {
279     return mRpcServices;
280   }
281 
282   /**
283    * Adds a block of memory to the linked list of headers.
284    *
285    * @see getFirstHeapBlock
286    * @see chreHeapAlloc
287    */
288   void linkHeapBlock(HeapBlockHeader *header);
289 
290   /**
291    * Removes a block of memory from the linked list of headers.
292    *
293    * @see getFirstHeapBlock
294    * @see chreHeapFree
295    */
296   void unlinkHeapBlock(HeapBlockHeader *header);
297 
298   /**
299    * @return A pointer to the first allocated heap block.
300    */
getFirstHeapBlock()301   HeapBlockHeader *getFirstHeapBlock() {
302     return mFirstHeader;
303   }
304 
305  private:
306   uint16_t mInstanceId = kInvalidInstanceId;
307 
308   //! The total number of wakeup counts for a nanoapp.
309   uint32_t mNumWakeupsSinceBoot = 0;
310 
311   //! The total number of messages sent to host by this nanoapp.
312   uint32_t mNumMessagesSentSinceBoot = 0;
313 
314   //! The total time in ms spend processing events by this nanoapp.
315   uint64_t mEventProcessTimeSinceBoot = 0;
316 
317   /**
318    * Head of the singly linked list of heap block headers.
319    *
320    * The list is used to free all the memory allocated by the nanoapp.
321    *
322    * @see MemoryManager
323    */
324   HeapBlockHeader *mFirstHeader = nullptr;
325 
326   //! The total memory allocated by the nanoapp in bytes.
327   size_t mTotalAllocatedBytes = 0;
328 
329   //! The peak total number of bytes allocated by the nanoapp.
330   size_t mPeakAllocatedBytes = 0;
331 
332   //! Container for "bucketed" stats associated with wakeup logging
333   struct BucketedStats {
BucketedStatsBucketedStats334     BucketedStats(uint16_t wakeupCount_, uint16_t hostMessageCount_,
335                   uint64_t eventProcessTime_, uint64_t creationTimestamp_)
336         : wakeupCount(wakeupCount_),
337           hostMessageCount(hostMessageCount_),
338           eventProcessTime(eventProcessTime_),
339           creationTimestamp(creationTimestamp_) {}
340 
341     uint16_t wakeupCount = 0;
342     uint16_t hostMessageCount = 0;
343     uint64_t eventProcessTime = 0;
344     uint64_t creationTimestamp = 0;
345   };
346 
347   //! The number of buckets for wakeup logging, adjust along with
348   //! EventLoop::kIntervalWakeupBucket.
349   static constexpr size_t kMaxSizeWakeupBuckets = 5;
350 
351   //! A fixed size buffer of buckets that keeps track of the number of host
352   //! wakeups over time intervals.
353   FixedSizeVector<BucketedStats, kMaxSizeWakeupBuckets> mWakeupBuckets;
354 
355   //! Collects process time in nanoseconds of each event
356   StatsContainer<uint64_t> mEventProcessTime;
357 
358   //! Metadata needed for keeping track of the registered events for this
359   //! nanoapp.
360   struct EventRegistration {
EventRegistrationEventRegistration361     EventRegistration(uint16_t eventType_, uint16_t groupIdMask_)
362         : eventType(eventType_), groupIdMask(groupIdMask_) {}
363 
364     uint16_t eventType;
365     uint16_t groupIdMask;
366   };
367 
368   //! The set of broadcast events that this app is registered for.
369   // TODO: Implement a set container and replace DynamicVector here. There may
370   // also be a better way of handling this (perhaps we map event type to apps
371   // who care about them).
372   DynamicVector<EventRegistration> mRegisteredEvents;
373 
374   //! The registered host endpoints to receive notifications for.
375   DynamicVector<uint16_t> mRegisteredHostEndpoints;
376 
377   //! The list of RPC services for this nanoapp.
378   DynamicVector<struct chreNanoappRpcService> mRpcServices;
379 
380   //! Whether nanoappStart is being executed.
381   bool mIsInNanoappStart = false;
382 
383   //! @return index of event registration if found. mRegisteredEvents.size() if
384   //!     not.
385   size_t registrationIndex(uint16_t eventType) const;
386 
387   /**
388    * A special function to deliver GNSS measurement events to nanoapps and
389    * handles version compatibility.
390    *
391    * @param event The pointer to the event
392    */
393   void handleGnssMeasurementDataEvent(const Event *event);
394 
isRegisteredForHostEndpointNotifications(uint16_t hostEndpointId)395   bool isRegisteredForHostEndpointNotifications(uint16_t hostEndpointId) const {
396     return mRegisteredHostEndpoints.find(hostEndpointId) !=
397            mRegisteredHostEndpoints.size();
398   }
399 };
400 
401 }  // namespace chre
402 
403 #endif  // CHRE_CORE_NANOAPP_H_
404