Support for architecture-specific assemblies in a folder named runtimes (#276)
[platform/core/dotnet/launcher.git] / NativeLauncher / util / path_manager.cc
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <vconf.h>
22
23 #include <iterator>
24 #include <sstream>
25 #include <fstream>
26
27 #include "utils.h"
28 #include "path_manager.h"
29 #include "plugin_manager.h"
30 #include "log.h"
31
32 static const char* __TIZEN_API_PATH_KEY = "db/dotnet/tizen_api_path";
33 static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version";
34 static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support";
35
36 #define __XSTR(x) #x
37 #define __STR(x) __XSTR(x)
38 static const char* __DEVICE_API_DIR = __STR(DEVICE_API_DIR);
39 static const char* __RUNTIME_DIR = __STR(RUNTIME_DIR);
40 static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
41 #undef __STR
42 #undef __XSTR
43
44 // The sequence of RID_FALLBACK graphs must be:
45 // 1. Tizen + Version + Architecture
46 // 2. Tizen + Version
47 // 3. OS(tizen, linux, unix) + Architecture
48 // 4. OS(tizen, linux, unix)
49 // 5. any, base
50 static std::string getRidFallbackGraphDirs(const std::string& appRoot)
51 {
52         std::vector<std::string> RID_FALLBACK_GRAPH;
53         char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
54         if (tizen_rid) {
55                 std::vector<std::string> version;
56                 splitPath(tizen_rid, version);
57                 std::reverse(std::begin(version), std::end(version));
58                 for (unsigned int i = 0; i < version.size(); i++) {
59                         RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i] + "-" + ARCHITECTURE_IDENTIFIER));
60                         RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i]));
61                 }
62                 free(tizen_rid);
63         }
64
65         std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
66         for (unsigned int i = 0; i < RID_FALLBACK_OS.size(); i++) {
67                 RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i] + "-" + ARCHITECTURE_IDENTIFIER));
68                 RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i]));
69         }
70         RID_FALLBACK_GRAPH.push_back("any");
71         RID_FALLBACK_GRAPH.push_back("base");
72
73         std::string candidate;
74         for (unsigned int i = 0; i < RID_FALLBACK_GRAPH.size(); i++) {
75                 if (!candidate.empty()) {
76                         candidate += ":";
77                 }
78                 candidate += concatPath(appRoot, "bin/runtimes/" + RID_FALLBACK_GRAPH[i] + "/native");
79         }
80
81         return candidate;
82 }
83
84 // 1. /appRoot/runtimes/{Platform}-{Architecture}/native/xxxxx.so
85 // 2. /appRoot/lib/{Architecture}/xxxxx.so
86 static std::string getExtraNativeLibDirs(const std::string& appRoot)
87 {
88         std::string candidate = getRidFallbackGraphDirs(appRoot);
89
90         candidate = candidate + ":" + concatPath(appRoot, "lib/" ARCHITECTURE_IDENTIFIER);
91         if (!strncmp(ARCHITECTURE_IDENTIFIER, "arm64", 5)) {
92                 candidate = candidate + ":" + concatPath(appRoot, "lib/aarch64");
93         } else if (!strncmp(ARCHITECTURE_IDENTIFIER, "armel", 5)) {
94                 candidate = candidate + ":" + concatPath(appRoot, "lib/arm");
95         }
96
97         return candidate;
98 }
99
100 // 1. /appRoot/runtimes/{Platform}-{Architecture}/lib/{TFMs}/xxxxx.dll
101 static std::string getExtraTfmDirs(const std::string& appRoot)
102 {
103         std::string candidate;
104         std::vector<std::string> tfmList;
105         char* tizen_tfm = vconf_get_str(__TIZEN_TFM_SUPPORT_KEY);
106         if (tizen_tfm) {
107                 splitPath(tizen_tfm, tfmList);
108                 free(tizen_tfm);
109         }
110
111         std::vector<std::string> paths;
112         splitPath(replaceAll(getRidFallbackGraphDirs(appRoot), "/native", "/lib"), paths);
113
114         if (tfmList.empty() || paths.empty())
115                 return candidate;
116
117         std::vector<std::string> tfmDirectoryList;
118         for (unsigned int i = 0; i < paths.size(); i++) {
119                 for (unsigned int j = 0; j < tfmList.size(); j++) {
120                         tfmDirectoryList.push_back(concatPath(paths[i], tfmList[j]));
121                 }
122         }
123
124         for (unsigned int i = 0; i < tfmDirectoryList.size(); i++) {
125                 if (!candidate.empty()) {
126                         candidate += ":";
127                 }
128                 candidate += tfmDirectoryList[i];
129         }
130
131         return candidate;
132 }
133
134 void PathManager::updateAppRelatedPath(const std::string& appRootPath)
135 {
136         std::string appBinPath = concatPath(appRootPath, "bin");
137         std::string appLibPath = concatPath(appRootPath, "lib");
138
139         appTacPath = concatPath(appBinPath, TAC_SYMLINK_SUB_DIR);
140         appPaths = appRootPath + ":" + appBinPath + ":" + appLibPath + ":" + appTacPath + ":" + getExtraTfmDirs(appRootPath);
141         appNIPaths = concatPath(appBinPath, APP_NI_SUB_DIR) + ":" + concatPath(appLibPath, APP_NI_SUB_DIR) + ":"+ appTacPath;
142         nativeDllSearchingPaths = runtimePath + ":" + __NATIVE_LIB_DIR + ":" + getExtraNativeLibDirs(appRootPath) + ":" + appBinPath + ":" + appLibPath;
143 }
144
145 PathManager::PathManager() :
146         rootFD(-1)
147 {
148         // set runtime path
149         runtimePath = getAbsolutePath(__RUNTIME_DIR);
150         platformAssembliesPaths.push_back(runtimePath);
151
152         // set tizenfx path
153         char* tmp = vconf_get_str(__TIZEN_API_PATH_KEY);
154         if (tmp) {
155                 tizenfxPath = std::string(tmp);
156                 _DBG("Device API Directory is set by vconf : %s", tmp);
157                 free(tmp);
158         } else {
159                 tizenfxPath = getAbsolutePath(__DEVICE_API_DIR);
160         }
161         platformAssembliesPaths.push_back(tizenfxPath);
162         platformAssembliesPaths.push_back(tizenfxPath + "/ref");
163
164         // set temporal application root path for candidate process
165         rootFD = open("/proc/self", O_DIRECTORY);
166         if (rootFD < 0) {
167                 _ERR("Failed to open /proc/self");
168                 throw std::ios_base::failure("Fail to open /proc/self");
169         }
170
171         appRootPath = std::string("/proc/self/fd/") + std::to_string(rootFD);
172         updateAppRelatedPath(appRootPath);
173
174         _INFO("Path manager created successfully");
175 }
176
177 PathManager::~PathManager()
178 {
179         _INFO("Path manager destroyed");
180 }
181
182 // paths: ":" separated muliple path.
183 void PathManager::addPlatformAssembliesPaths(const std::string& paths, bool isHighPriority)
184 {
185         std::vector<std::string>::iterator it;
186         std::vector<std::string> pathVec;
187         splitPath(paths, pathVec);
188
189         for (unsigned int i = 0; i < pathVec.size(); i++) {
190                 pathVec[i] = getAbsolutePath(pathVec[i]);
191         }
192
193         if (isHighPriority) {
194                 it = platformAssembliesPaths.begin();
195         } else {
196                 it = platformAssembliesPaths.end();
197         }
198
199         platformAssembliesPaths.insert(it, pathVec.begin(), pathVec.end());
200 }
201
202 void PathManager::setAppRootPath(const std::string& rootPath)
203 {
204         // override root path for application launch mode (candidate / standalone mode)
205         if (rootFD >= 0) {
206                 int tmpFD = open(rootPath.c_str(), O_DIRECTORY);
207                 dup3(tmpFD, rootFD, O_CLOEXEC);
208                 if (tmpFD >= 0)
209                         close(tmpFD);
210         }
211
212         appRootPath = getAbsolutePath(rootPath);
213         updateAppRelatedPath(appRootPath);
214 }
215
216 const std::string& PathManager::getRuntimePath()
217 {
218         return runtimePath;
219 }
220
221 const std::string& PathManager::getTizenFXPath()
222 {
223         return tizenfxPath;
224 }
225
226 // return platform assembly paths
227 const std::vector<std::string>& PathManager::getPlatformAssembliesPaths()
228 {
229         return platformAssembliesPaths;
230 }
231
232 // return app root path
233 const std::string& PathManager::getAppRootPath()
234 {
235         return appRootPath;
236 }
237
238 // return .tac_symlink path
239 const std::string& PathManager::getAppTacPath()
240 {
241         return appTacPath;
242 }
243
244 // return dll searching paths for app
245 const std::string& PathManager::getAppPaths()
246 {
247         return appPaths;
248 }
249
250 // return ni dll searching paths for app
251 const std::string& PathManager::getAppNIPaths()
252 {
253         return appNIPaths;
254 }
255
256 // return native dll searching paths for app
257 const std::string& PathManager::getNativeDllSearchingPaths()
258 {
259         return nativeDllSearchingPaths;
260 }