• 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 #include "chre/core/nanoapp.h"
18 
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/assert.h"
21 #include "chre/platform/fatal_error.h"
22 #include "chre/platform/log.h"
23 #include "chre/platform/tracing.h"
24 #include "chre/util/system/debug_dump.h"
25 #include "chre_api/chre/gnss.h"
26 #include "chre_api/chre/version.h"
27 
28 #include <algorithm>
29 #include <cstdint>
30 
31 #if CHRE_FIRST_SUPPORTED_API_VERSION < CHRE_API_VERSION_1_5
32 #define CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
33 #endif
34 
35 namespace chre {
36 
37 constexpr size_t Nanoapp::kMaxSizeWakeupBuckets;
38 
Nanoapp()39 Nanoapp::Nanoapp()
40     : Nanoapp(EventLoopManagerSingleton::get()->getNextInstanceId()) {}
41 
Nanoapp(uint16_t instanceId)42 Nanoapp::Nanoapp(uint16_t instanceId) {
43   // Push first bucket onto wakeup bucket queue
44   cycleWakeupBuckets(SystemTime::getMonotonicTime());
45   mInstanceId = instanceId;
46 }
47 
start()48 bool Nanoapp::start() {
49   // TODO(b/294116163): update trace with nanoapp instance id and nanoapp name
50   CHRE_TRACE_INSTANT("Nanoapp start");
51   mIsInNanoappStart = true;
52   bool success = PlatformNanoapp::start();
53   mIsInNanoappStart = false;
54   return success;
55 }
56 
isRegisteredForBroadcastEvent(const Event * event) const57 bool Nanoapp::isRegisteredForBroadcastEvent(const Event *event) const {
58   bool registered = false;
59   uint16_t eventType = event->eventType;
60   uint16_t targetGroupIdMask = event->targetAppGroupMask;
61 
62   // The host endpoint notification is a special case, because it requires
63   // explicit registration using host endpoint IDs rather than masks.
64   if (eventType == CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION) {
65     const auto *data =
66         static_cast<const chreHostEndpointNotification *>(event->eventData);
67     registered = isRegisteredForHostEndpointNotifications(data->hostEndpointId);
68   } else {
69     size_t foundIndex = registrationIndex(eventType);
70     if (foundIndex < mRegisteredEvents.size()) {
71       const EventRegistration &reg = mRegisteredEvents[foundIndex];
72       if (targetGroupIdMask & reg.groupIdMask) {
73         registered = true;
74       }
75     }
76   }
77   return registered;
78 }
79 
registerForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)80 void Nanoapp::registerForBroadcastEvent(uint16_t eventType,
81                                         uint16_t groupIdMask) {
82   size_t foundIndex = registrationIndex(eventType);
83   if (foundIndex < mRegisteredEvents.size()) {
84     mRegisteredEvents[foundIndex].groupIdMask |= groupIdMask;
85   } else if (!mRegisteredEvents.push_back(
86                  EventRegistration(eventType, groupIdMask))) {
87     FATAL_ERROR_OOM();
88   }
89 }
90 
unregisterForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)91 void Nanoapp::unregisterForBroadcastEvent(uint16_t eventType,
92                                           uint16_t groupIdMask) {
93   size_t foundIndex = registrationIndex(eventType);
94   if (foundIndex < mRegisteredEvents.size()) {
95     EventRegistration &reg = mRegisteredEvents[foundIndex];
96     reg.groupIdMask &= ~groupIdMask;
97     if (reg.groupIdMask == 0) {
98       mRegisteredEvents.erase(foundIndex);
99     }
100   }
101 }
102 
configureNanoappInfoEvents(bool enable)103 void Nanoapp::configureNanoappInfoEvents(bool enable) {
104   if (enable) {
105     registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
106     registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
107   } else {
108     unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
109     unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
110   }
111 }
112 
configureHostSleepEvents(bool enable)113 void Nanoapp::configureHostSleepEvents(bool enable) {
114   if (enable) {
115     registerForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
116     registerForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
117   } else {
118     unregisterForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
119     unregisterForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
120   }
121 }
122 
configureDebugDumpEvent(bool enable)123 void Nanoapp::configureDebugDumpEvent(bool enable) {
124   if (enable) {
125     registerForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
126   } else {
127     unregisterForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
128   }
129 }
130 
configureUserSettingEvent(uint8_t setting,bool enable)131 void Nanoapp::configureUserSettingEvent(uint8_t setting, bool enable) {
132   if (enable) {
133     registerForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT + setting);
134   } else {
135     unregisterForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT +
136                                 setting);
137   }
138 }
139 
processEvent(Event * event)140 void Nanoapp::processEvent(Event *event) {
141   Nanoseconds eventStartTime = SystemTime::getMonotonicTime();
142   // TODO(b/294116163): update trace with event type and nanoapp name so it can
143   //                    be differentiated from other events
144   CHRE_TRACE_START("Handle event", "nanoapp", getInstanceId());
145   if (event->eventType == CHRE_EVENT_GNSS_DATA) {
146     handleGnssMeasurementDataEvent(event);
147   } else {
148     handleEvent(event->senderInstanceId, event->eventType, event->eventData);
149   }
150   // TODO(b/294116163): update trace with nanoapp name
151   CHRE_TRACE_END("Handle event", "nanoapp", getInstanceId());
152   Nanoseconds eventProcessTime =
153       SystemTime::getMonotonicTime() - eventStartTime;
154   uint64_t eventTimeMs = Milliseconds(eventProcessTime).getMilliseconds();
155   if (Milliseconds(eventProcessTime) >= Milliseconds(100)) {
156     LOGE("Nanoapp 0x%" PRIx64 " took %" PRIu64
157          " ms to process event type 0x%" PRIx16,
158          getAppId(), eventTimeMs, event->eventType);
159   }
160   mEventProcessTime.addValue(eventTimeMs);
161   mEventProcessTimeSinceBoot += eventTimeMs;
162   mWakeupBuckets.back().eventProcessTime += eventTimeMs;
163 }
164 
blameHostWakeup()165 void Nanoapp::blameHostWakeup() {
166   if (mWakeupBuckets.back().wakeupCount < UINT16_MAX) {
167     ++mWakeupBuckets.back().wakeupCount;
168   }
169   if (mNumWakeupsSinceBoot < UINT32_MAX) ++mNumWakeupsSinceBoot;
170 }
171 
blameHostMessageSent()172 void Nanoapp::blameHostMessageSent() {
173   if (mWakeupBuckets.back().hostMessageCount < UINT16_MAX) {
174     ++mWakeupBuckets.back().hostMessageCount;
175   }
176   if (mNumMessagesSentSinceBoot < UINT32_MAX) ++mNumMessagesSentSinceBoot;
177 }
178 
cycleWakeupBuckets(Nanoseconds timestamp)179 void Nanoapp::cycleWakeupBuckets(Nanoseconds timestamp) {
180   if (mWakeupBuckets.full()) {
181     mWakeupBuckets.erase(0);
182   }
183   mWakeupBuckets.push_back(
184       BucketedStats(0, 0, 0, timestamp.toRawNanoseconds()));
185 }
186 
logStateToBuffer(DebugDumpWrapper & debugDump) const187 void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
188   debugDump.print(" Id=%" PRIu16 " 0x%016" PRIx64 " ", getInstanceId(),
189                   getAppId());
190   PlatformNanoapp::logStateToBuffer(debugDump);
191   debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32
192                   ".%" PRIu32 "\n",
193                   CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()),
194                   CHRE_EXTRACT_MINOR_VERSION(getAppVersion()),
195                   CHRE_EXTRACT_PATCH_VERSION(getAppVersion()),
196                   CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()),
197                   CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()));
198 }
199 
logMemAndComputeHeader(DebugDumpWrapper & debugDump) const200 void Nanoapp::logMemAndComputeHeader(DebugDumpWrapper &debugDump) const {
201   // Print table header
202   // Nanoapp column sized to accommodate largest known name
203   debugDump.print("\n%10sNanoapp%9s| Mem Alloc (Bytes) |%7sEvent Time (Ms)\n",
204                   "", "", "");
205   debugDump.print("%26s| Current |     Max |    Mean |     Max |   Total\n",
206                   "");
207 }
208 
logMemAndComputeEntry(DebugDumpWrapper & debugDump) const209 void Nanoapp::logMemAndComputeEntry(DebugDumpWrapper &debugDump) const {
210   debugDump.print("%25s |", getAppName());
211   debugDump.print(" %7zu |", getTotalAllocatedBytes());
212   debugDump.print(" %7zu |", getPeakAllocatedBytes());
213   debugDump.print(" %7" PRIu64 " |", mEventProcessTime.getMean());
214   debugDump.print(" %7" PRIu64 " |", mEventProcessTime.getMax());
215   debugDump.print(" %7" PRIu64 "\n", mEventProcessTimeSinceBoot);
216 }
217 
logMessageHistoryHeader(DebugDumpWrapper & debugDump) const218 void Nanoapp::logMessageHistoryHeader(DebugDumpWrapper &debugDump) const {
219   // Print time ranges for buckets
220   Nanoseconds now = SystemTime::getMonotonicTime();
221   uint64_t currentTimeMins = 0;
222   uint64_t nextTimeMins = 0;
223   uint64_t nanosecondsSince = 0;
224   char bucketLabel = 'A';
225 
226   char bucketTags[kMaxSizeWakeupBuckets][4];
227   for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
228     bucketTags[i][0] = '[';
229     bucketTags[i][1] = bucketLabel++;
230     bucketTags[i][2] = ']';
231     bucketTags[i][3] = '\0';
232   }
233 
234   debugDump.print(
235       "\nHistogram stat buckets cover the following time ranges:\n");
236 
237   for (int32_t i = kMaxSizeWakeupBuckets - 1;
238        i > static_cast<int32_t>(mWakeupBuckets.size() - 1); --i) {
239     debugDump.print(" Bucket%s: N/A (unused)\n", bucketTags[i]);
240   }
241 
242   for (int32_t i = static_cast<int32_t>(mWakeupBuckets.size() - 1); i >= 0;
243        --i) {
244     size_t idx = static_cast<size_t>(i);
245     nanosecondsSince =
246         now.toRawNanoseconds() - mWakeupBuckets[idx].creationTimestamp;
247     currentTimeMins = (nanosecondsSince / kOneMinuteInNanoseconds);
248 
249     debugDump.print(" Bucket%s:", bucketTags[idx]);
250     debugDump.print(" %3" PRIu64 "", nextTimeMins);
251     debugDump.print(" - %3" PRIu64 " mins ago\n", currentTimeMins);
252     nextTimeMins = currentTimeMins;
253   }
254 
255   // Precompute column widths for Wakeup Histogram, Message Histogram, and Event
256   // Time Histogram (ms). This allows the column width to be known and optimized
257   // at compile time, and avoids use of inconsistently supported "%*" in printf
258   //
259   // A static_assert is used to ensure these calculations are updated whenever
260   // the value of kMaxSizeWakeupBuckets changes
261   static_assert(kMaxSizeWakeupBuckets == 5,
262                 "Update of nanoapp debug dump column widths requrired");
263 
264   // Print table header
265   debugDump.print("\n%26s|", " Nanoapp ");
266   debugDump.print("%11s|", " Total w/u ");
267   // Wakeup Histogram = 2 + (4 * kMaxSizeWakeupBuckets);
268   debugDump.print("%22s|", " Wakeup Histogram ");
269   debugDump.print("%12s|", " Total Msgs ");
270   // Message Histogram = 2 + (4 * kMaxSizeWakeupBuckets);
271   debugDump.print("%22s|", " Message Histogram ");
272   debugDump.print("%12s|", " Event Time ");
273   // Event Time Histogram (ms) = 2 + (7 * kMaxSizeWakeupBuckets);
274   debugDump.print("%37s", " Event Time Histogram (ms) ");
275 
276   debugDump.print("\n%26s|%11s|", "", "");
277   for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
278     debugDump.print(" %3s", bucketTags[i]);
279   }
280   debugDump.print("  |%12s|", "");
281   for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
282     debugDump.print(" %3s", bucketTags[i]);
283   }
284   debugDump.print("  |%12s|", "");
285   for (int32_t i = kMaxSizeWakeupBuckets - 1; i >= 0; --i) {
286     debugDump.print(" %7s", bucketTags[i]);
287   }
288   debugDump.print("\n");
289 }
290 
logMessageHistoryEntry(DebugDumpWrapper & debugDump) const291 void Nanoapp::logMessageHistoryEntry(DebugDumpWrapper &debugDump) const {
292   debugDump.print("%25s |", getAppName());
293 
294   // Print wakeupCount and histogram
295   debugDump.print(" %9" PRIu32 " | ", mNumWakeupsSinceBoot);
296   for (size_t i = kMaxSizeWakeupBuckets - 1; i > 0; --i) {
297     if (i >= mWakeupBuckets.size()) {
298       debugDump.print(" --,");
299     } else {
300       debugDump.print(" %2" PRIu16 ",", mWakeupBuckets[i].wakeupCount);
301     }
302   }
303   debugDump.print(" %2" PRIu16 "  |", mWakeupBuckets.front().wakeupCount);
304 
305   // Print hostMessage count and histogram
306   debugDump.print(" %10" PRIu32 " | ", mNumMessagesSentSinceBoot);
307   for (size_t i = kMaxSizeWakeupBuckets - 1; i > 0; --i) {
308     if (i >= mWakeupBuckets.size()) {
309       debugDump.print(" --,");
310     } else {
311       debugDump.print(" %2" PRIu16 ",", mWakeupBuckets[i].hostMessageCount);
312     }
313   }
314   debugDump.print(" %2" PRIu16 "  |", mWakeupBuckets.front().hostMessageCount);
315 
316   // Print eventProcessingTime count and histogram
317   debugDump.print(" %10" PRIu64 " | ", mEventProcessTimeSinceBoot);
318   for (size_t i = kMaxSizeWakeupBuckets - 1; i > 0; --i) {
319     if (i >= mWakeupBuckets.size()) {
320       debugDump.print("     --,");
321     } else {
322       debugDump.print(" %6" PRIu64 ",", mWakeupBuckets[i].eventProcessTime);
323     }
324   }
325   debugDump.print(" %6" PRIu64 "\n", mWakeupBuckets.front().eventProcessTime);
326 }
327 
permitPermissionUse(uint32_t permission) const328 bool Nanoapp::permitPermissionUse(uint32_t permission) const {
329   return !supportsAppPermissions() ||
330          ((getAppPermissions() & permission) == permission);
331 }
332 
registrationIndex(uint16_t eventType) const333 size_t Nanoapp::registrationIndex(uint16_t eventType) const {
334   size_t foundIndex = 0;
335   for (; foundIndex < mRegisteredEvents.size(); ++foundIndex) {
336     const EventRegistration &reg = mRegisteredEvents[foundIndex];
337     if (reg.eventType == eventType) {
338       break;
339     }
340   }
341   return foundIndex;
342 }
343 
handleGnssMeasurementDataEvent(const Event * event)344 void Nanoapp::handleGnssMeasurementDataEvent(const Event *event) {
345 #ifdef CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
346   const struct chreGnssDataEvent *data =
347       static_cast<const struct chreGnssDataEvent *>(event->eventData);
348   if (getTargetApiVersion() < CHRE_API_VERSION_1_5 &&
349       data->measurement_count > CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5) {
350     chreGnssDataEvent localEvent;
351     memcpy(&localEvent, data, sizeof(struct chreGnssDataEvent));
352     localEvent.measurement_count = CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5;
353     handleEvent(event->senderInstanceId, event->eventType, &localEvent);
354   } else
355 #endif  // CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
356   {
357     handleEvent(event->senderInstanceId, event->eventType, event->eventData);
358   }
359 }
360 
configureHostEndpointNotifications(uint16_t hostEndpointId,bool enable)361 bool Nanoapp::configureHostEndpointNotifications(uint16_t hostEndpointId,
362                                                  bool enable) {
363   bool success = true;
364   bool registered = isRegisteredForHostEndpointNotifications(hostEndpointId);
365   if (enable && !registered) {
366     success = mRegisteredHostEndpoints.push_back(hostEndpointId);
367     if (!success) {
368       LOG_OOM();
369     }
370   } else if (!enable && registered) {
371     size_t index = mRegisteredHostEndpoints.find(hostEndpointId);
372     mRegisteredHostEndpoints.erase(index);
373   }
374 
375   return success;
376 }
377 
publishRpcServices(struct chreNanoappRpcService * services,size_t numServices)378 bool Nanoapp::publishRpcServices(struct chreNanoappRpcService *services,
379                                  size_t numServices) {
380   if (!mIsInNanoappStart) {
381     LOGE("publishRpcServices must be called from nanoappStart");
382     return false;
383   }
384 
385   const size_t startSize = mRpcServices.size();
386   const size_t endSize = startSize + numServices;
387   if (endSize > kMaxRpcServices) {
388     return false;
389   }
390 
391   mRpcServices.reserve(endSize);
392 
393   bool success = true;
394 
395   for (size_t i = 0; i < numServices; i++) {
396     if (!mRpcServices.push_back(services[i])) {
397       LOG_OOM();
398       success = false;
399       break;
400     }
401   }
402 
403   if (success && mRpcServices.size() > 1) {
404     for (size_t i = 0; i < mRpcServices.size() - 1; i++) {
405       for (size_t j = i + 1; j < mRpcServices.size(); j++) {
406         if (mRpcServices[i].id == mRpcServices[j].id) {
407           LOGE("Service id = 0x%016" PRIx64 " can only be published once",
408                mRpcServices[i].id);
409           success = false;
410         }
411       }
412     }
413   }
414 
415   if (!success) {
416     mRpcServices.resize(startSize);
417   }
418 
419   return success;
420 }
421 
linkHeapBlock(HeapBlockHeader * header)422 void Nanoapp::linkHeapBlock(HeapBlockHeader *header) {
423   header->data.next = mFirstHeader;
424   mFirstHeader = header;
425 }
426 
unlinkHeapBlock(HeapBlockHeader * header)427 void Nanoapp::unlinkHeapBlock(HeapBlockHeader *header) {
428   if (mFirstHeader == nullptr) {
429     // The list is empty.
430     return;
431   }
432 
433   if (header == mFirstHeader) {
434     mFirstHeader = header->data.next;
435     return;
436   }
437 
438   HeapBlockHeader *previous = mFirstHeader;
439   HeapBlockHeader *current = mFirstHeader->data.next;
440 
441   while (current != nullptr) {
442     if (current == header) {
443       previous->data.next = current->data.next;
444       break;
445     }
446     previous = current;
447     current = current->data.next;
448   }
449 }
450 
451 }  // namespace chre
452