• 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/util/system/debug_dump.h"
24 #include "chre_api/chre/gnss.h"
25 #include "chre_api/chre/version.h"
26 
27 #include <algorithm>
28 
29 #if CHRE_FIRST_SUPPORTED_API_VERSION < CHRE_API_VERSION_1_5
30 #define CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
31 #endif
32 
33 namespace chre {
34 
35 constexpr size_t Nanoapp::kMaxSizeWakeupBuckets;
36 
Nanoapp()37 Nanoapp::Nanoapp() {
38   // Push first bucket onto wakeup bucket queue
39   cycleWakeupBuckets(1);
40 }
41 
isRegisteredForBroadcastEvent(const Event * event) const42 bool Nanoapp::isRegisteredForBroadcastEvent(const Event *event) const {
43   bool registered = false;
44   uint16_t eventType = event->eventType;
45   uint16_t targetGroupIdMask = event->targetAppGroupMask;
46 
47   // The host endpoint notification is a special case, because it requires
48   // explicit registration using host endpoint IDs rather than masks.
49   if (eventType == CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION) {
50     const auto *data =
51         static_cast<const chreHostEndpointNotification *>(event->eventData);
52     registered = isRegisteredForHostEndpointNotifications(data->hostEndpointId);
53   } else {
54     size_t foundIndex = registrationIndex(eventType);
55     if (foundIndex < mRegisteredEvents.size()) {
56       const EventRegistration &reg = mRegisteredEvents[foundIndex];
57       if (targetGroupIdMask & reg.groupIdMask) {
58         registered = true;
59       }
60     }
61   }
62   return registered;
63 }
64 
registerForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)65 void Nanoapp::registerForBroadcastEvent(uint16_t eventType,
66                                         uint16_t groupIdMask) {
67   size_t foundIndex = registrationIndex(eventType);
68   if (foundIndex < mRegisteredEvents.size()) {
69     mRegisteredEvents[foundIndex].groupIdMask |= groupIdMask;
70   } else if (!mRegisteredEvents.push_back(
71                  EventRegistration(eventType, groupIdMask))) {
72     FATAL_ERROR_OOM();
73   }
74 }
75 
unregisterForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)76 void Nanoapp::unregisterForBroadcastEvent(uint16_t eventType,
77                                           uint16_t groupIdMask) {
78   size_t foundIndex = registrationIndex(eventType);
79   if (foundIndex < mRegisteredEvents.size()) {
80     EventRegistration &reg = mRegisteredEvents[foundIndex];
81     reg.groupIdMask &= ~groupIdMask;
82     if (reg.groupIdMask == 0) {
83       mRegisteredEvents.erase(foundIndex);
84     }
85   }
86 }
87 
configureNanoappInfoEvents(bool enable)88 void Nanoapp::configureNanoappInfoEvents(bool enable) {
89   if (enable) {
90     registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
91     registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
92   } else {
93     unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
94     unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
95   }
96 }
97 
configureHostSleepEvents(bool enable)98 void Nanoapp::configureHostSleepEvents(bool enable) {
99   if (enable) {
100     registerForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
101     registerForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
102   } else {
103     unregisterForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
104     unregisterForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
105   }
106 }
107 
configureDebugDumpEvent(bool enable)108 void Nanoapp::configureDebugDumpEvent(bool enable) {
109   if (enable) {
110     registerForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
111   } else {
112     unregisterForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
113   }
114 }
115 
configureUserSettingEvent(uint8_t setting,bool enable)116 void Nanoapp::configureUserSettingEvent(uint8_t setting, bool enable) {
117   if (enable) {
118     registerForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT + setting);
119   } else {
120     unregisterForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT +
121                                 setting);
122   }
123 }
124 
processEvent(Event * event)125 void Nanoapp::processEvent(Event *event) {
126   if (event->eventType == CHRE_EVENT_GNSS_DATA) {
127     handleGnssMeasurementDataEvent(event);
128   } else {
129     handleEvent(event->senderInstanceId, event->eventType, event->eventData);
130   }
131 }
132 
blameHostWakeup()133 void Nanoapp::blameHostWakeup() {
134   if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back();
135   if (mNumWakeupsSinceBoot < UINT32_MAX) ++mNumWakeupsSinceBoot;
136 }
137 
cycleWakeupBuckets(size_t numBuckets)138 void Nanoapp::cycleWakeupBuckets(size_t numBuckets) {
139   numBuckets = std::min(numBuckets, kMaxSizeWakeupBuckets);
140   for (size_t i = 0; i < numBuckets; ++i) {
141     if (mWakeupBuckets.full()) {
142       mWakeupBuckets.erase(0);
143     }
144     mWakeupBuckets.push_back(0);
145   }
146 }
147 
logStateToBuffer(DebugDumpWrapper & debugDump) const148 void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
149   debugDump.print(" Id=%" PRIu16 " 0x%016" PRIx64 " ", getInstanceId(),
150                   getAppId());
151   PlatformNanoapp::logStateToBuffer(debugDump);
152   debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32
153                   ".%" PRIu32 " curAlloc=%zu peakAlloc=%zu",
154                   CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()),
155                   CHRE_EXTRACT_MINOR_VERSION(getAppVersion()),
156                   CHRE_EXTRACT_PATCH_VERSION(getAppVersion()),
157                   CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()),
158                   CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()),
159                   getTotalAllocatedBytes(), getPeakAllocatedBytes());
160   debugDump.print(" hostWakeups=[ cur->");
161   // Get buckets latest -> earliest except last one
162   for (size_t i = mWakeupBuckets.size() - 1; i > 0; --i) {
163     debugDump.print("%" PRIu16 ", ", mWakeupBuckets[i]);
164   }
165   // Earliest bucket gets no comma
166   debugDump.print("%" PRIu16 " ]", mWakeupBuckets.front());
167 
168   // Print total wakeups since boot
169   debugDump.print(" totWakeups=%" PRIu32 " ]\n", mNumWakeupsSinceBoot);
170 }
171 
permitPermissionUse(uint32_t permission) const172 bool Nanoapp::permitPermissionUse(uint32_t permission) const {
173   return !supportsAppPermissions() ||
174          ((getAppPermissions() & permission) == permission);
175 }
176 
registrationIndex(uint16_t eventType) const177 size_t Nanoapp::registrationIndex(uint16_t eventType) const {
178   size_t foundIndex = 0;
179   for (; foundIndex < mRegisteredEvents.size(); ++foundIndex) {
180     const EventRegistration &reg = mRegisteredEvents[foundIndex];
181     if (reg.eventType == eventType) {
182       break;
183     }
184   }
185   return foundIndex;
186 }
187 
handleGnssMeasurementDataEvent(const Event * event)188 void Nanoapp::handleGnssMeasurementDataEvent(const Event *event) {
189 #ifdef CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
190   const struct chreGnssDataEvent *data =
191       static_cast<const struct chreGnssDataEvent *>(event->eventData);
192   if (getTargetApiVersion() < CHRE_API_VERSION_1_5 &&
193       data->measurement_count > CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5) {
194     chreGnssDataEvent localEvent;
195     memcpy(&localEvent, data, sizeof(struct chreGnssDataEvent));
196     localEvent.measurement_count = CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5;
197     handleEvent(event->senderInstanceId, event->eventType, &localEvent);
198   } else
199 #endif  // CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
200   {
201     handleEvent(event->senderInstanceId, event->eventType, event->eventData);
202   }
203 }
204 
configureHostEndpointNotifications(uint16_t hostEndpointId,bool enable)205 bool Nanoapp::configureHostEndpointNotifications(uint16_t hostEndpointId,
206                                                  bool enable) {
207   bool success = true;
208   bool registered = isRegisteredForHostEndpointNotifications(hostEndpointId);
209   if (enable && !registered) {
210     success = mRegisteredHostEndpoints.push_back(hostEndpointId);
211     if (!success) {
212       LOG_OOM();
213     }
214   } else if (!enable && registered) {
215     size_t index = mRegisteredHostEndpoints.find(hostEndpointId);
216     mRegisteredHostEndpoints.erase(index);
217   }
218 
219   return success;
220 }
221 
publishRpcServices(struct chreNanoappRpcService * services,size_t numServices)222 bool Nanoapp::publishRpcServices(struct chreNanoappRpcService *services,
223                                  size_t numServices) {
224   // TODO(b/204426460): Validate this code is only called from nanoappStart().
225   bool success = true;
226   for (size_t i = 0; i < numServices; i++) {
227     if (!mRpcServices.push_back(services[i])) {
228       LOG_OOM();
229       success = false;
230     }
231   }
232 
233   return success;
234 }
235 
linkHeapBlock(HeapBlockHeader * header)236 void Nanoapp::linkHeapBlock(HeapBlockHeader *header) {
237   header->data.next = mFirstHeader;
238   mFirstHeader = header;
239 }
240 
unlinkHeapBlock(HeapBlockHeader * header)241 void Nanoapp::unlinkHeapBlock(HeapBlockHeader *header) {
242   if (mFirstHeader == nullptr) {
243     // The list is empty.
244     return;
245   }
246 
247   if (header == mFirstHeader) {
248     mFirstHeader = header->data.next;
249     return;
250   }
251 
252   HeapBlockHeader *previous = mFirstHeader;
253   HeapBlockHeader *current = mFirstHeader->data.next;
254 
255   while (current != nullptr) {
256     if (current == header) {
257       previous->data.next = current->data.next;
258       break;
259     }
260     previous = current;
261     current = current->data.next;
262   }
263 }
264 
265 }  // namespace chre
266