• 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 
loadFromBuffer(uint64_t appId,uint32_t appVersion,const void * appBinary,size_t appBinaryLen)72 bool PlatformNanoappBase::loadFromBuffer(uint64_t appId, uint32_t appVersion,
73                                          const void *appBinary,
74                                          size_t appBinaryLen) {
75   CHRE_ASSERT(!isLoaded());
76   bool success = false;
77   constexpr size_t kMaxAppSize = 2 * 1024 * 1024;  // 2 MiB
78 
79   if (appBinaryLen > kMaxAppSize) {
80     LOGE("Rejecting app size %zu above limit %zu", appBinaryLen, kMaxAppSize);
81   } else {
82     mAppBinary = memoryAllocBigImage(appBinaryLen);
83     if (mAppBinary == nullptr) {
84       LOGE("Couldn't allocate %zu byte buffer for nanoapp 0x%016" PRIx64,
85            appBinaryLen, appId);
86     } else {
87       mExpectedAppId = appId;
88       mExpectedAppVersion = appVersion;
89       mAppBinaryLen = appBinaryLen;
90       memcpy(mAppBinary, appBinary, appBinaryLen);
91       success = true;
92     }
93   }
94 
95   return success;
96 }
97 
loadFromFile(uint64_t appId,const char * filename)98 void PlatformNanoappBase::loadFromFile(uint64_t appId, const char *filename) {
99   CHRE_ASSERT(!isLoaded());
100   mExpectedAppId = appId;
101   mFilename = filename;
102 }
103 
loadStatic(const struct chreNslNanoappInfo * appInfo)104 void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
105   CHRE_ASSERT(!isLoaded());
106   mIsStatic = true;
107   mAppInfo = appInfo;
108 }
109 
isLoaded() const110 bool PlatformNanoappBase::isLoaded() const {
111   return (mIsStatic || mAppBinary != nullptr || mDsoHandle != nullptr);
112 }
113 
isUimgApp() const114 bool PlatformNanoappBase::isUimgApp() const {
115   return mIsUimgApp;
116 }
117 
closeNanoapp()118 void PlatformNanoappBase::closeNanoapp() {
119   if (mDsoHandle != nullptr) {
120     if (dlclose(mDsoHandle) != 0) {
121       LOGE("dlclose failed: %s", dlerror());
122     }
123     mDsoHandle = nullptr;
124   }
125 }
126 
openNanoapp()127 bool PlatformNanoappBase::openNanoapp() {
128   bool success = false;
129 
130   if (mIsStatic) {
131     success = true;
132   } else if (mFilename != nullptr) {
133     success = openNanoappFromFile();
134   } else if (mAppBinary != nullptr) {
135     success = openNanoappFromBuffer();
136   } else {
137     CHRE_ASSERT(false);
138   }
139 
140   // Save this flag locally since it may be referenced while the system is in
141   // micro-image
142   if (mAppInfo != nullptr) {
143     mIsUimgApp = mAppInfo->isTcmNanoapp;
144   }
145 
146   return success;
147 }
148 
openNanoappFromBuffer()149 bool PlatformNanoappBase::openNanoappFromBuffer() {
150   CHRE_ASSERT(mAppBinary != nullptr);
151   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
152   bool success = false;
153 
154   // Populate a filename string (just a requirement of the dlopenbuf API)
155   constexpr size_t kMaxFilenameLen = 17;
156   char filename[kMaxFilenameLen];
157   snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId);
158 
159   mDsoHandle = dlopenbuf(
160       filename, static_cast<const char *>(mAppBinary),
161       static_cast<int>(mAppBinaryLen), RTLD_NOW);
162   if (mDsoHandle == nullptr) {
163     LOGE("Failed to load nanoapp: %s", dlerror());
164   } else {
165     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
166         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
167     if (mAppInfo == nullptr) {
168       LOGE("Failed to find app info symbol: %s", dlerror());
169     } else {
170       success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo);
171       if (!success) {
172         mAppInfo = nullptr;
173       } else {
174         LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64 ") version 0x%"
175              PRIx32 " uimg %d system %d", mAppInfo->name, mAppInfo->appId,
176              mAppInfo->appVersion, mAppInfo->isTcmNanoapp,
177              mAppInfo->isSystemNanoapp);
178         memoryFreeBigImage(mAppBinary);
179         mAppBinary = nullptr;
180       }
181     }
182   }
183 
184   return success;
185 }
186 
openNanoappFromFile()187 bool PlatformNanoappBase::openNanoappFromFile() {
188   CHRE_ASSERT(mFilename != nullptr);
189   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
190   bool success = false;
191 
192   mDsoHandle = dlopen(mFilename, RTLD_NOW);
193   if (mDsoHandle == nullptr) {
194     LOGE("Failed to load nanoapp from file %s: %s", mFilename, dlerror());
195   } else {
196     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
197         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
198     if (mAppInfo == nullptr) {
199       LOGE("Failed to find app info symbol in %s: %s", mFilename, dlerror());
200     } else {
201       success = validateAppInfo(mExpectedAppId, 0, mAppInfo,
202                                 true /* ignoreAppVersion */);
203       if (!success) {
204         mAppInfo = nullptr;
205       } else {
206         LOGI("Successfully loaded nanoapp %s (0x%016" PRIx64 ") version 0x%"
207              PRIx32 " uimg %d system %d from file %s", mAppInfo->name,
208              mAppInfo->appId, mAppInfo->appVersion, mAppInfo->isTcmNanoapp,
209              mAppInfo->isSystemNanoapp, mFilename);
210         // Save the app version field in case this app gets disabled and we
211         // still get a query request for the version later on. We are OK not
212         // knowing the version prior to the first load because we assume that
213         // nanoapps loaded via file are done at CHRE initialization time.
214         mExpectedAppVersion = mAppInfo->appVersion;
215       }
216     }
217   }
218 
219   return success;
220 }
221 
getAppId() const222 uint64_t PlatformNanoapp::getAppId() const {
223   return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId;
224 }
225 
getAppVersion() const226 uint32_t PlatformNanoapp::getAppVersion() const {
227   return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion;
228 }
229 
getTargetApiVersion() const230 uint32_t PlatformNanoapp::getTargetApiVersion() const {
231   return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0;
232 }
233 
isSystemNanoapp() const234 bool PlatformNanoapp::isSystemNanoapp() const {
235   // Right now, we assume that system nanoapps are always static nanoapps. Since
236   // mAppInfo can only be null either prior to loading the app (in which case
237   // this function is not expected to return a valid value anyway), or when a
238   // dynamic nanoapp is not running, "false" is the correct return value in that
239   // case.
240   return (mAppInfo != nullptr) ? mAppInfo->isSystemNanoapp : false;
241 }
242 
logStateToBuffer(char * buffer,size_t * bufferPos,size_t bufferSize) const243 bool PlatformNanoapp::logStateToBuffer(char *buffer, size_t *bufferPos,
244                                        size_t bufferSize) const {
245   bool success = true;
246   if (mAppInfo != nullptr) {
247     success &= debugDumpPrint(buffer, bufferPos, bufferSize, " %s: vendor=\"%s\"",
248                               mAppInfo->name, mAppInfo->vendor);
249   }
250   return success;
251 }
252 
253 }  // namespace chre
254