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 ® = 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 ® = 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 ® = 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