1 /*
2  * Copyright (C) 2017 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/platform/memory_manager.h"
18 
19 #include "chre/util/system/debug_dump.h"
20 
21 namespace chre {
22 
nanoappAlloc(Nanoapp * app,uint32_t bytes)23 void *MemoryManager::nanoappAlloc(Nanoapp *app, uint32_t bytes) {
24   AllocHeader *header = nullptr;
25   if (bytes > 0) {
26     if (mAllocationCount >= kMaxAllocationCount) {
27       LOGE("Failed to allocate memory from Nanoapp ID %" PRIu32
28            ": allocation count exceeded limit.",
29            app->getInstanceId());
30     } else if ((bytes > kMaxAllocationBytes) ||
31                ((mTotalAllocatedBytes + bytes) > kMaxAllocationBytes)) {
32       LOGE("Failed to allocate memory from Nanoapp ID %" PRIu32
33            ": not enough space.",
34            app->getInstanceId());
35     } else {
36       header =
37           static_cast<AllocHeader *>(doAlloc(app, sizeof(AllocHeader) + bytes));
38 
39       if (header != nullptr) {
40         app->setTotalAllocatedBytes(app->getTotalAllocatedBytes() + bytes);
41         mTotalAllocatedBytes += bytes;
42         if (mTotalAllocatedBytes > mPeakAllocatedBytes) {
43           mPeakAllocatedBytes = mTotalAllocatedBytes;
44         }
45         mAllocationCount++;
46         header->data.bytes = bytes;
47         header->data.instanceId = app->getInstanceId();
48         header++;
49       }
50     }
51   }
52   return header;
53 }
54 
nanoappFree(Nanoapp * app,void * ptr)55 void MemoryManager::nanoappFree(Nanoapp *app, void *ptr) {
56   if (ptr != nullptr) {
57     AllocHeader *header = static_cast<AllocHeader *>(ptr);
58     header--;
59 
60     // TODO: Clean up API contract of chreSendEvent to specify nanoapps can't
61     // release ownership of data to other nanoapps so a CHRE_ASSERT_LOG can be
62     // used below and the code can return.
63     if (app->getInstanceId() != header->data.instanceId) {
64       LOGW("Nanoapp ID=%" PRIu32 " tried to free data from nanoapp ID=%" PRIu32,
65            app->getInstanceId(), header->data.instanceId);
66     }
67 
68     size_t nanoAppTotalAllocatedBytes = app->getTotalAllocatedBytes();
69     if (nanoAppTotalAllocatedBytes >= header->data.bytes) {
70       app->setTotalAllocatedBytes(nanoAppTotalAllocatedBytes -
71                                   header->data.bytes);
72     } else {
73       app->setTotalAllocatedBytes(0);
74     }
75 
76     if (mTotalAllocatedBytes >= header->data.bytes) {
77       mTotalAllocatedBytes -= header->data.bytes;
78     } else {
79       mTotalAllocatedBytes = 0;
80     }
81     if (mAllocationCount > 0) {
82       mAllocationCount--;
83     }
84 
85     doFree(app, header);
86   }
87 }
88 
logStateToBuffer(DebugDumpWrapper & debugDump) const89 void MemoryManager::logStateToBuffer(DebugDumpWrapper &debugDump) const {
90   debugDump.print(
91       "\nNanoapp heap usage: %zu bytes allocated, %zu peak bytes"
92       " allocated, count %zu\n",
93       getTotalAllocatedBytes(), getPeakAllocatedBytes(), getAllocationCount());
94 }
95 
96 }  // namespace chre
97