• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/platform_nanoapp.h"
18 
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/assert.h"
21 #include "chre/platform/log.h"
22 #include "chre/platform/memory.h"
23 #include "chre/platform/shared/nanoapp_dso_util.h"
24 #include "chre/platform/shared/nanoapp_support_lib_dso.h"
25 #include "chre/platform/slpi/memory.h"
26 #include "chre/platform/slpi/power_control_util.h"
27 #include "chre/util/system/debug_dump.h"
28 #include "chre_api/chre/version.h"
29 
30 #include "dlfcn.h"
31 
32 #include <inttypes.h>
33 #include <string.h>
34 
35 namespace chre {
36 
~PlatformNanoapp()37 PlatformNanoapp::~PlatformNanoapp() {
38   closeNanoapp();
39   if (mAppBinary != nullptr) {
40     memoryFreeBigImage(mAppBinary);
41   }
42 }
43 
start()44 bool PlatformNanoapp::start() {
45   // Invoke the start entry point after successfully opening the app
46   if (!isUimgApp()) {
47     slpiForceBigImage();
48   }
49 
50   return openNanoapp() && mAppInfo->entryPoints.start();
51 }
52 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)53 void PlatformNanoapp::handleEvent(uint32_t senderInstanceId,
54                                   uint16_t eventType,
55                                   const void *eventData) {
56   if (!isUimgApp()) {
57     slpiForceBigImage();
58   }
59 
60   mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData);
61 }
62 
end()63 void PlatformNanoapp::end() {
64   if (!isUimgApp()) {
65     slpiForceBigImage();
66   }
67 
68   mAppInfo->entryPoints.end();
69   closeNanoapp();
70 }
71 
reserveBuffer(uint64_t appId,uint32_t appVersion,size_t appBinaryLen)72 bool PlatformNanoappBase::reserveBuffer(
73     uint64_t appId, uint32_t appVersion, size_t appBinaryLen) {
74   CHRE_ASSERT(!isLoaded());
75   bool success = false;
76   constexpr size_t kMaxAppSize = 2 * 1024 * 1024;  // 2 MiB
77 
78   if (appBinaryLen > kMaxAppSize) {
79     LOGE("Rejecting app size %zu above limit %zu", appBinaryLen, kMaxAppSize);
80   } else {
81     mAppBinary = memoryAllocBigImage(appBinaryLen);
82     if (mAppBinary == nullptr) {
83       LOGE("Couldn't allocate %zu byte buffer for nanoapp 0x%016" PRIx64,
84            appBinaryLen, appId);
85     } else {
86       mExpectedAppId = appId;
87       mExpectedAppVersion = appVersion;
88       mAppBinaryLen = appBinaryLen;
89       success = true;
90     }
91   }
92 
93   return success;
94 }
95 
copyNanoappFragment(const void * buffer,size_t bufferLen)96 bool PlatformNanoappBase::copyNanoappFragment(
97     const void *buffer, size_t bufferLen) {
98   CHRE_ASSERT(!isLoaded());
99 
100   bool success = true;
101   if (mBytesLoaded + bufferLen > mAppBinaryLen) {
102     LOGE("Overflow: cannot load %zu bytes to %zu/%zu nanoapp binary buffer",
103          bufferLen, mBytesLoaded, mAppBinaryLen);
104     success = false;
105   } else {
106     uint8_t *binaryBuffer = static_cast<uint8_t *>(mAppBinary) + mBytesLoaded;
107     memcpy(binaryBuffer, buffer, bufferLen);
108     mBytesLoaded += bufferLen;
109   }
110 
111   return success;
112 }
113 
loadFromFile(uint64_t appId,const char * filename)114 void PlatformNanoappBase::loadFromFile(uint64_t appId, const char *filename) {
115   CHRE_ASSERT(!isLoaded());
116   mExpectedAppId = appId;
117   mFilename = filename;
118 }
119 
loadStatic(const struct chreNslNanoappInfo * appInfo)120 void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
121   CHRE_ASSERT(!isLoaded());
122   mIsStatic = true;
123   mAppInfo = appInfo;
124 }
125 
isLoaded() const126 bool PlatformNanoappBase::isLoaded() const {
127   return (mIsStatic || (mAppBinary != nullptr && mBytesLoaded == mAppBinaryLen)
128           || mDsoHandle != nullptr);
129 }
130 
isUimgApp() const131 bool PlatformNanoappBase::isUimgApp() const {
132   return mIsUimgApp;
133 }
134 
closeNanoapp()135 void PlatformNanoappBase::closeNanoapp() {
136   if (mDsoHandle != nullptr) {
137     if (dlclose(mDsoHandle) != 0) {
138       LOGE("dlclose failed: %s", dlerror());
139     }
140     mDsoHandle = nullptr;
141   }
142 }
143 
openNanoapp()144 bool PlatformNanoappBase::openNanoapp() {
145   bool success = false;
146 
147   if (mIsStatic) {
148     success = true;
149   } else if (mFilename != nullptr) {
150     success = openNanoappFromFile();
151   } else if (mAppBinary != nullptr) {
152     success = openNanoappFromBuffer();
153   } else {
154     CHRE_ASSERT(false);
155   }
156 
157   // Save this flag locally since it may be referenced while the system is in
158   // micro-image
159   if (mAppInfo != nullptr) {
160     mIsUimgApp = mAppInfo->isTcmNanoapp;
161   }
162 
163   return success;
164 }
165 
openNanoappFromBuffer()166 bool PlatformNanoappBase::openNanoappFromBuffer() {
167   CHRE_ASSERT(mAppBinary != nullptr);
168   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
169   bool success = false;
170 
171   // Populate a filename string (just a requirement of the dlopenbuf API)
172   constexpr size_t kMaxFilenameLen = 17;
173   char filename[kMaxFilenameLen];
174   snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId);
175 
176   mDsoHandle = dlopenbuf(
177       filename, static_cast<const char *>(mAppBinary),
178       static_cast<int>(mAppBinaryLen), RTLD_NOW);
179   if (mDsoHandle == nullptr) {
180     LOGE("Failed to load nanoapp: %s", dlerror());
181   } else {
182     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
183         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
184     if (mAppInfo == nullptr) {
185       LOGE("Failed to find app info symbol: %s", dlerror());
186     } else {
187       success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo);
188       if (!success) {
189         mAppInfo = nullptr;
190       } else {
191         LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64 ") version 0x%"
192              PRIx32 " uimg %d system %d", mAppInfo->name, mAppInfo->appId,
193              mAppInfo->appVersion, mAppInfo->isTcmNanoapp,
194              mAppInfo->isSystemNanoapp);
195         memoryFreeBigImage(mAppBinary);
196         mAppBinary = nullptr;
197       }
198     }
199   }
200 
201   return success;
202 }
203 
openNanoappFromFile()204 bool PlatformNanoappBase::openNanoappFromFile() {
205   CHRE_ASSERT(mFilename != nullptr);
206   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
207   bool success = false;
208 
209   mDsoHandle = dlopen(mFilename, RTLD_NOW);
210   if (mDsoHandle == nullptr) {
211     LOGE("Failed to load nanoapp from file %s: %s", mFilename, dlerror());
212   } else {
213     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
214         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
215     if (mAppInfo == nullptr) {
216       LOGE("Failed to find app info symbol in %s: %s", mFilename, dlerror());
217     } else {
218       success = validateAppInfo(mExpectedAppId, 0, mAppInfo,
219                                 true /* ignoreAppVersion */);
220       if (!success) {
221         mAppInfo = nullptr;
222       } else {
223         LOGI("Successfully loaded nanoapp %s (0x%016" PRIx64 ") version 0x%"
224              PRIx32 " uimg %d system %d from file %s", mAppInfo->name,
225              mAppInfo->appId, mAppInfo->appVersion, mAppInfo->isTcmNanoapp,
226              mAppInfo->isSystemNanoapp, mFilename);
227         // Save the app version field in case this app gets disabled and we
228         // still get a query request for the version later on. We are OK not
229         // knowing the version prior to the first load because we assume that
230         // nanoapps loaded via file are done at CHRE initialization time.
231         mExpectedAppVersion = mAppInfo->appVersion;
232       }
233     }
234   }
235 
236   return success;
237 }
238 
getAppId() const239 uint64_t PlatformNanoapp::getAppId() const {
240   return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId;
241 }
242 
getAppVersion() const243 uint32_t PlatformNanoapp::getAppVersion() const {
244   return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion;
245 }
246 
getTargetApiVersion() const247 uint32_t PlatformNanoapp::getTargetApiVersion() const {
248   return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0;
249 }
250 
isSystemNanoapp() const251 bool PlatformNanoapp::isSystemNanoapp() const {
252   // Right now, we assume that system nanoapps are always static nanoapps. Since
253   // mAppInfo can only be null either prior to loading the app (in which case
254   // this function is not expected to return a valid value anyway), or when a
255   // dynamic nanoapp is not running, "false" is the correct return value in that
256   // case.
257   return (mAppInfo != nullptr) ? mAppInfo->isSystemNanoapp : false;
258 }
259 
logStateToBuffer(char * buffer,size_t * bufferPos,size_t bufferSize) const260 bool PlatformNanoapp::logStateToBuffer(char *buffer, size_t *bufferPos,
261                                        size_t bufferSize) const {
262   bool success = true;
263   if (mAppInfo != nullptr) {
264     success &= debugDumpPrint(buffer, bufferPos, bufferSize, " %s: vendor=\"%s\"",
265                               mAppInfo->name, mAppInfo->vendor);
266   }
267   return success;
268 }
269 
270 }  // namespace chre
271