• 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   // Push first bucket onto wakeup bucket queue
41   cycleWakeupBuckets(1);
42 }
43 
start()44 bool Nanoapp::start() {
45   traceRegisterNanoapp(getInstanceId(), getAppName());
46   mIsInNanoappStart = true;
47   bool success = PlatformNanoapp::start();
48   mIsInNanoappStart = false;
49   return success;
50 }
51 
isRegisteredForBroadcastEvent(const Event * event) const52 bool Nanoapp::isRegisteredForBroadcastEvent(const Event *event) const {
53   bool registered = false;
54   uint16_t eventType = event->eventType;
55   uint16_t targetGroupIdMask = event->targetAppGroupMask;
56 
57   // The host endpoint notification is a special case, because it requires
58   // explicit registration using host endpoint IDs rather than masks.
59   if (eventType == CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION) {
60     const auto *data =
61         static_cast<const chreHostEndpointNotification *>(event->eventData);
62     registered = isRegisteredForHostEndpointNotifications(data->hostEndpointId);
63   } else {
64     size_t foundIndex = registrationIndex(eventType);
65     if (foundIndex < mRegisteredEvents.size()) {
66       const EventRegistration &reg = mRegisteredEvents[foundIndex];
67       if (targetGroupIdMask & reg.groupIdMask) {
68         registered = true;
69       }
70     }
71   }
72   return registered;
73 }
74 
registerForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)75 void Nanoapp::registerForBroadcastEvent(uint16_t eventType,
76                                         uint16_t groupIdMask) {
77   size_t foundIndex = registrationIndex(eventType);
78   if (foundIndex < mRegisteredEvents.size()) {
79     mRegisteredEvents[foundIndex].groupIdMask |= groupIdMask;
80   } else if (!mRegisteredEvents.push_back(
81                  EventRegistration(eventType, groupIdMask))) {
82     FATAL_ERROR_OOM();
83   }
84 }
85 
unregisterForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)86 void Nanoapp::unregisterForBroadcastEvent(uint16_t eventType,
87                                           uint16_t groupIdMask) {
88   size_t foundIndex = registrationIndex(eventType);
89   if (foundIndex < mRegisteredEvents.size()) {
90     EventRegistration &reg = mRegisteredEvents[foundIndex];
91     reg.groupIdMask &= ~groupIdMask;
92     if (reg.groupIdMask == 0) {
93       mRegisteredEvents.erase(foundIndex);
94     }
95   }
96 }
97 
configureNanoappInfoEvents(bool enable)98 void Nanoapp::configureNanoappInfoEvents(bool enable) {
99   if (enable) {
100     registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
101     registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
102   } else {
103     unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
104     unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
105   }
106 }
107 
configureHostSleepEvents(bool enable)108 void Nanoapp::configureHostSleepEvents(bool enable) {
109   if (enable) {
110     registerForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
111     registerForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
112   } else {
113     unregisterForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
114     unregisterForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
115   }
116 }
117 
configureDebugDumpEvent(bool enable)118 void Nanoapp::configureDebugDumpEvent(bool enable) {
119   if (enable) {
120     registerForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
121   } else {
122     unregisterForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
123   }
124 }
125 
configureUserSettingEvent(uint8_t setting,bool enable)126 void Nanoapp::configureUserSettingEvent(uint8_t setting, bool enable) {
127   if (enable) {
128     registerForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT + setting);
129   } else {
130     unregisterForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT +
131                                 setting);
132   }
133 }
134 
processEvent(Event * event)135 void Nanoapp::processEvent(Event *event) {
136   Nanoseconds eventStartTime = SystemTime::getMonotonicTime();
137   traceNanoappHandleEventStart(getInstanceId(), event->eventType);
138   if (event->eventType == CHRE_EVENT_GNSS_DATA) {
139     handleGnssMeasurementDataEvent(event);
140   } else {
141     handleEvent(event->senderInstanceId, event->eventType, event->eventData);
142   }
143   traceNanoappHandleEventEnd(getInstanceId());
144   Nanoseconds eventProcessTime =
145       SystemTime::getMonotonicTime() - eventStartTime;
146   if (Milliseconds(eventProcessTime) >= Milliseconds(100)) {
147     LOGE("Nanoapp 0x%" PRIx64 " took %" PRIu64
148          " ms to process event type %" PRIu16,
149          getAppId(), Milliseconds(eventProcessTime).getMilliseconds(),
150          event->eventType);
151   }
152   mEventProcessTime.addValue(Milliseconds(eventProcessTime).getMilliseconds());
153 }
154 
blameHostWakeup()155 void Nanoapp::blameHostWakeup() {
156   if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back();
157   if (mNumWakeupsSinceBoot < UINT32_MAX) ++mNumWakeupsSinceBoot;
158 }
159 
cycleWakeupBuckets(size_t numBuckets)160 void Nanoapp::cycleWakeupBuckets(size_t numBuckets) {
161   numBuckets = std::min(numBuckets, kMaxSizeWakeupBuckets);
162   for (size_t i = 0; i < numBuckets; ++i) {
163     if (mWakeupBuckets.full()) {
164       mWakeupBuckets.erase(0);
165     }
166     mWakeupBuckets.push_back(0);
167   }
168 }
169 
logStateToBuffer(DebugDumpWrapper & debugDump) const170 void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
171   debugDump.print(" Id=%" PRIu16 " 0x%016" PRIx64 " ", getInstanceId(),
172                   getAppId());
173   PlatformNanoapp::logStateToBuffer(debugDump);
174   debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32
175                   ".%" PRIu32 " curAlloc=%zu peakAlloc=%zu",
176                   CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()),
177                   CHRE_EXTRACT_MINOR_VERSION(getAppVersion()),
178                   CHRE_EXTRACT_PATCH_VERSION(getAppVersion()),
179                   CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()),
180                   CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()),
181                   getTotalAllocatedBytes(), getPeakAllocatedBytes());
182   debugDump.print(" hostWakeups=[ cur->");
183   // Get buckets latest -> earliest except last one
184   for (size_t i = mWakeupBuckets.size() - 1; i > 0; --i) {
185     debugDump.print("%" PRIu16 ", ", mWakeupBuckets[i]);
186   }
187   // Earliest bucket gets no comma
188   debugDump.print("%" PRIu16 " ]", mWakeupBuckets.front());
189 
190   // Print total wakeups since boot
191   debugDump.print(" totWakeups=%" PRIu32 " ", mNumWakeupsSinceBoot);
192 
193   // Print mean and max event process time
194   debugDump.print("eventProcessTimeMs: mean=%" PRIu64 ", max=%" PRIu64 "\n",
195                   mEventProcessTime.getMean(), mEventProcessTime.getMax());
196 }
197 
permitPermissionUse(uint32_t permission) const198 bool Nanoapp::permitPermissionUse(uint32_t permission) const {
199   return !supportsAppPermissions() ||
200          ((getAppPermissions() & permission) == permission);
201 }
202 
registrationIndex(uint16_t eventType) const203 size_t Nanoapp::registrationIndex(uint16_t eventType) const {
204   size_t foundIndex = 0;
205   for (; foundIndex < mRegisteredEvents.size(); ++foundIndex) {
206     const EventRegistration &reg = mRegisteredEvents[foundIndex];
207     if (reg.eventType == eventType) {
208       break;
209     }
210   }
211   return foundIndex;
212 }
213 
handleGnssMeasurementDataEvent(const Event * event)214 void Nanoapp::handleGnssMeasurementDataEvent(const Event *event) {
215 #ifdef CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
216   const struct chreGnssDataEvent *data =
217       static_cast<const struct chreGnssDataEvent *>(event->eventData);
218   if (getTargetApiVersion() < CHRE_API_VERSION_1_5 &&
219       data->measurement_count > CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5) {
220     chreGnssDataEvent localEvent;
221     memcpy(&localEvent, data, sizeof(struct chreGnssDataEvent));
222     localEvent.measurement_count = CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5;
223     handleEvent(event->senderInstanceId, event->eventType, &localEvent);
224   } else
225 #endif  // CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
226   {
227     handleEvent(event->senderInstanceId, event->eventType, event->eventData);
228   }
229 }
230 
configureHostEndpointNotifications(uint16_t hostEndpointId,bool enable)231 bool Nanoapp::configureHostEndpointNotifications(uint16_t hostEndpointId,
232                                                  bool enable) {
233   bool success = true;
234   bool registered = isRegisteredForHostEndpointNotifications(hostEndpointId);
235   if (enable && !registered) {
236     success = mRegisteredHostEndpoints.push_back(hostEndpointId);
237     if (!success) {
238       LOG_OOM();
239     }
240   } else if (!enable && registered) {
241     size_t index = mRegisteredHostEndpoints.find(hostEndpointId);
242     mRegisteredHostEndpoints.erase(index);
243   }
244 
245   return success;
246 }
247 
publishRpcServices(struct chreNanoappRpcService * services,size_t numServices)248 bool Nanoapp::publishRpcServices(struct chreNanoappRpcService *services,
249                                  size_t numServices) {
250   if (!mIsInNanoappStart) {
251     LOGE("publishRpcServices must be called from nanoappStart");
252     return false;
253   }
254 
255   const size_t startSize = mRpcServices.size();
256   const size_t endSize = startSize + numServices;
257   if (endSize > kMaxRpcServices) {
258     return false;
259   }
260 
261   mRpcServices.reserve(endSize);
262 
263   bool success = true;
264 
265   for (size_t i = 0; i < numServices; i++) {
266     if (!mRpcServices.push_back(services[i])) {
267       LOG_OOM();
268       success = false;
269       break;
270     }
271   }
272 
273   if (success && mRpcServices.size() > 1) {
274     for (size_t i = 0; i < mRpcServices.size() - 1; i++) {
275       for (size_t j = i + 1; j < mRpcServices.size(); j++) {
276         if (mRpcServices[i].id == mRpcServices[j].id) {
277           LOGE("Service id = 0x%016" PRIx64 " can only be published once",
278                mRpcServices[i].id);
279           success = false;
280         }
281       }
282     }
283   }
284 
285   if (!success) {
286     mRpcServices.resize(startSize);
287   }
288 
289   return success;
290 }
291 
linkHeapBlock(HeapBlockHeader * header)292 void Nanoapp::linkHeapBlock(HeapBlockHeader *header) {
293   header->data.next = mFirstHeader;
294   mFirstHeader = header;
295 }
296 
unlinkHeapBlock(HeapBlockHeader * header)297 void Nanoapp::unlinkHeapBlock(HeapBlockHeader *header) {
298   if (mFirstHeader == nullptr) {
299     // The list is empty.
300     return;
301   }
302 
303   if (header == mFirstHeader) {
304     mFirstHeader = header->data.next;
305     return;
306   }
307 
308   HeapBlockHeader *previous = mFirstHeader;
309   HeapBlockHeader *current = mFirstHeader->data.next;
310 
311   while (current != nullptr) {
312     if (current == header) {
313       previous->data.next = current->data.next;
314       break;
315     }
316     previous = current;
317     current = current->data.next;
318   }
319 }
320 
321 }  // namespace chre
322