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 37 Nanoapp::Nanoapp() { 38 // Push first bucket onto wakeup bucket queue 39 cycleWakeupBuckets(1); 40 } 41 42 Nanoapp::~Nanoapp() { 43 const size_t totalAllocatedBytes = getTotalAllocatedBytes(); 44 45 if (totalAllocatedBytes > 0) { 46 // TODO: Consider asserting here 47 LOGE("Nanoapp ID=0x%016" PRIx64 " still has %zu allocated bytes!", 48 getAppId(), totalAllocatedBytes); 49 } 50 } 51 52 bool Nanoapp::isRegisteredForBroadcastEvent(uint16_t eventType, 53 uint16_t targetGroupIdMask) const { 54 bool registered = false; 55 size_t foundIndex = registrationIndex(eventType); 56 if (foundIndex < mRegisteredEvents.size()) { 57 const EventRegistration ® = mRegisteredEvents[foundIndex]; 58 if (targetGroupIdMask & reg.groupIdMask) { 59 registered = true; 60 } 61 } 62 return registered; 63 } 64 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 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 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 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 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 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 125 Event *Nanoapp::processNextEvent() { 126 Event *event = mEventQueue.pop(); 127 128 CHRE_ASSERT_LOG(event != nullptr, "Tried delivering event, but queue empty"); 129 if (event != nullptr) { 130 if (event->eventType == CHRE_EVENT_GNSS_DATA) { 131 handleGnssMeasurementDataEvent(event); 132 } else { 133 handleEvent(event->senderInstanceId, event->eventType, event->eventData); 134 } 135 } 136 137 return event; 138 } 139 140 void Nanoapp::blameHostWakeup() { 141 if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back(); 142 } 143 144 void Nanoapp::cycleWakeupBuckets(size_t numBuckets) { 145 numBuckets = std::min(numBuckets, kMaxSizeWakeupBuckets); 146 for (size_t i = 0; i < numBuckets; ++i) { 147 if (mWakeupBuckets.full()) { 148 mWakeupBuckets.erase(0); 149 } 150 mWakeupBuckets.push_back(0); 151 } 152 } 153 154 void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const { 155 debugDump.print(" Id=%" PRIu32 " 0x%016" PRIx64 " ", getInstanceId(), 156 getAppId()); 157 PlatformNanoapp::logStateToBuffer(debugDump); 158 debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32 159 ".%" PRIu32 " curAlloc=%zu peakAlloc=%zu", 160 CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()), 161 CHRE_EXTRACT_MINOR_VERSION(getAppVersion()), 162 CHRE_EXTRACT_PATCH_VERSION(getAppVersion()), 163 CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()), 164 CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()), 165 getTotalAllocatedBytes(), getPeakAllocatedBytes()); 166 debugDump.print(" hostWakeups=[ cur->"); 167 // Get buckets latest -> earliest except last one 168 for (size_t i = mWakeupBuckets.size() - 1; i > 0; --i) { 169 debugDump.print("%" PRIu16 ", ", mWakeupBuckets[i]); 170 } 171 // Earliest bucket gets no comma 172 debugDump.print("%" PRIu16 " ]\n", mWakeupBuckets.front()); 173 } 174 175 bool Nanoapp::permitPermissionUse(uint32_t permission) const { 176 return !supportsAppPermissions() || 177 ((getAppPermissions() & permission) == permission); 178 } 179 180 size_t Nanoapp::registrationIndex(uint16_t eventType) const { 181 size_t foundIndex = 0; 182 for (; foundIndex < mRegisteredEvents.size(); ++foundIndex) { 183 const EventRegistration ® = mRegisteredEvents[foundIndex]; 184 if (reg.eventType == eventType) { 185 break; 186 } 187 } 188 return foundIndex; 189 } 190 191 void Nanoapp::handleGnssMeasurementDataEvent(const Event *event) { 192 #ifdef CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED 193 const struct chreGnssDataEvent *data = 194 static_cast<const struct chreGnssDataEvent *>(event->eventData); 195 if (getTargetApiVersion() < CHRE_API_VERSION_1_5 && 196 data->measurement_count > CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5) { 197 chreGnssDataEvent localEvent; 198 memcpy(&localEvent, data, sizeof(struct chreGnssDataEvent)); 199 localEvent.measurement_count = CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5; 200 handleEvent(event->senderInstanceId, event->eventType, &localEvent); 201 } else 202 #endif // CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED 203 { 204 handleEvent(event->senderInstanceId, event->eventType, event->eventData); 205 } 206 } 207 208 } // namespace chre 209