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/version.h"
25
26 #include <algorithm>
27
28 namespace chre {
29
30 constexpr size_t Nanoapp::kMaxSizeWakeupBuckets;
31
Nanoapp()32 Nanoapp::Nanoapp() {
33 // Push first bucket onto wakeup bucket queue
34 cycleWakeupBuckets(1);
35 }
36
~Nanoapp()37 Nanoapp::~Nanoapp() {
38 const size_t totalAllocatedBytes = getTotalAllocatedBytes();
39
40 if (totalAllocatedBytes > 0) {
41 // TODO: Consider asserting here
42 LOGE("Nanoapp ID=0x%016" PRIx64 " still has %zu allocated bytes!",
43 getAppId(), totalAllocatedBytes);
44 }
45 }
46
isRegisteredForBroadcastEvent(uint16_t eventType) const47 bool Nanoapp::isRegisteredForBroadcastEvent(uint16_t eventType) const {
48 return (mRegisteredEvents.find(eventType) != mRegisteredEvents.size());
49 }
50
registerForBroadcastEvent(uint16_t eventId)51 bool Nanoapp::registerForBroadcastEvent(uint16_t eventId) {
52 if (isRegisteredForBroadcastEvent(eventId)) {
53 return false;
54 }
55
56 if (!mRegisteredEvents.push_back(eventId)) {
57 FATAL_ERROR_OOM();
58 }
59
60 return true;
61 }
62
unregisterForBroadcastEvent(uint16_t eventId)63 bool Nanoapp::unregisterForBroadcastEvent(uint16_t eventId) {
64 size_t registeredEventIndex = mRegisteredEvents.find(eventId);
65 if (registeredEventIndex == mRegisteredEvents.size()) {
66 return false;
67 }
68
69 mRegisteredEvents.erase(registeredEventIndex);
70 return true;
71 }
72
configureNanoappInfoEvents(bool enable)73 void Nanoapp::configureNanoappInfoEvents(bool enable) {
74 if (enable) {
75 registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
76 registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
77 } else {
78 unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
79 unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
80 }
81 }
82
configureHostSleepEvents(bool enable)83 void Nanoapp::configureHostSleepEvents(bool enable) {
84 if (enable) {
85 registerForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
86 registerForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
87 } else {
88 unregisterForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
89 unregisterForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
90 }
91 }
92
configureDebugDumpEvent(bool enable)93 void Nanoapp::configureDebugDumpEvent(bool enable) {
94 if (enable) {
95 registerForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
96 } else {
97 unregisterForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
98 }
99 }
100
processNextEvent()101 Event *Nanoapp::processNextEvent() {
102 Event *event = mEventQueue.pop();
103
104 CHRE_ASSERT_LOG(event != nullptr, "Tried delivering event, but queue empty");
105 if (event != nullptr) {
106 handleEvent(event->senderInstanceId, event->eventType, event->eventData);
107 }
108
109 return event;
110 }
111
blameHostWakeup()112 void Nanoapp::blameHostWakeup() {
113 if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back();
114 }
115
cycleWakeupBuckets(size_t numBuckets)116 void Nanoapp::cycleWakeupBuckets(size_t numBuckets) {
117 numBuckets = std::min(numBuckets, kMaxSizeWakeupBuckets);
118 for (size_t i = 0; i < numBuckets; ++i) {
119 if (mWakeupBuckets.full()) {
120 mWakeupBuckets.erase(0);
121 }
122 mWakeupBuckets.push_back(0);
123 }
124 }
125
logStateToBuffer(DebugDumpWrapper & debugDump) const126 void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
127 debugDump.print(" Id=%" PRIu32 " 0x%016" PRIx64 " ", getInstanceId(),
128 getAppId());
129 PlatformNanoapp::logStateToBuffer(debugDump);
130 debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32
131 ".%" PRIu32 " curAlloc=%zu peakAlloc=%zu",
132 CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()),
133 CHRE_EXTRACT_MINOR_VERSION(getAppVersion()),
134 CHRE_EXTRACT_PATCH_VERSION(getAppVersion()),
135 CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()),
136 CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()),
137 getTotalAllocatedBytes(), getPeakAllocatedBytes());
138 debugDump.print(" hostWakeups=[ cur->");
139 // Get buckets latest -> earliest except last one
140 for (size_t i = mWakeupBuckets.size() - 1; i > 0; --i) {
141 debugDump.print("%" PRIu16 ", ", mWakeupBuckets[i]);
142 }
143 // Earliest bucket gets no comma
144 debugDump.print("%" PRIu16 " ]\n", mWakeupBuckets.front());
145 }
146
147 } // namespace chre
148