5c12aaa59240c92edb711e1008956fc7cbfa2e6c
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / multi_target_resolver.cc
1 /*
2  * Copyright (c) 2020 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 <string>
18 #include <fstream>
19 #include <pkgmgr-info.h>
20
21 #include "log.h"
22 #include "utils.h"
23 #include "multi_target_resolver.h"
24
25 static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version"; //8.0.0:7.0.0:6.5.0:6.0.0:5.5.0:5.0.0:4.0.0
26 static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support"; //net6.0-tizen8.0:net6.0-tizen:net6.0:tizen10.0:tizen90:tizen80:tizen70:tizen60:tizen50:tizen40
27
28 /*
29 Priority | RID                 | TFM
30 ---------|---------------------|-----------------------
31 1        | tizen.X.Y.Z-{arch}  | netX.Y-tizenX.Y ~ 6.5
32 2        | tizen.X.Y.Z         | netX.Y-tizen
33 3        | tizen-{arch}, tizen | netX.Y
34 4        | linux-{arch}, linux | tizen10.0 ~ 40
35 5        | unix-{arch}, unix   | net5.0
36 6        | any                 | netcoreapp3.1 ~ 1.0
37 7        | base                | netstandard2.1 ~ 1.0
38 */
39
40 // Guided by Appfw, vconf daemon does not run at mic stage.
41 // So vconf_get_* api does not work normally.
42 // Therefore, it is changed to manage as a file instead of using vconf API.
43 // /usr/share/dotnet.tizen/lib/dotnet_resolving.info
44 static std::string getDotnetResolvingInfo(const char* key)
45 {
46         std::ifstream ifs(DOTNET_RESOLVING_INFO_PATH);
47         std::string line;
48         while (std::getline(ifs, line)) {
49                 if (!strcmp(line.substr(0, line.find(" ")).c_str(), key)) {
50                         ifs.close();
51                         return line.substr(line.rfind(" ") + 1);
52                 }
53         }
54         return "";
55 }
56
57 static std::vector<std::string> getRidFallbackGraph()
58 {
59         std::string tizen_rid_version = getDotnetResolvingInfo(__TIZEN_RID_VERSION_KEY);
60         std::vector<std::string> rid_version;
61         std::vector<std::string> RID_FALLBACK_GRAPH;
62         splitPath(tizen_rid_version, rid_version);
63         for (auto& ridVersion : rid_version) {
64                 RID_FALLBACK_GRAPH.push_back(std::string("tizen." + ridVersion + "-" + ARCHITECTURE_IDENTIFIER));
65                 RID_FALLBACK_GRAPH.push_back(std::string("tizen." + ridVersion));
66         }
67
68         std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
69         for (auto& os : RID_FALLBACK_OS) {
70                 RID_FALLBACK_GRAPH.push_back(std::string(os + "-" + ARCHITECTURE_IDENTIFIER));
71                 RID_FALLBACK_GRAPH.push_back(std::string(os));
72         }
73         RID_FALLBACK_GRAPH.push_back("any");
74         RID_FALLBACK_GRAPH.push_back("base");
75
76         return RID_FALLBACK_GRAPH;
77 }
78
79 static std::vector<std::string> getTfmFallbackGraph()
80 {
81         std::string tizen_tfm_support = getDotnetResolvingInfo(__TIZEN_TFM_SUPPORT_KEY);
82         std::vector<std::string> TFM_FALLBACK_GRAPH;
83         splitPath(tizen_tfm_support, TFM_FALLBACK_GRAPH);
84         TFM_FALLBACK_GRAPH.push_back("net5.0");
85
86         std::vector<std::string> netcoreapp_version = {"3.1", "3.0", "2.2", "2.1", "2.0", "1.1", "1.0"};
87         for (auto& version : netcoreapp_version) {
88                 TFM_FALLBACK_GRAPH.push_back(std::string("netcoreapp" + version));
89         }
90         std::vector<std::string> netstandard_version = {"2.1", "2.0", "1.6", "1.5", "1.4", "1.3", "1.2", "1.1", "1.0"};
91         for (auto& version : netstandard_version) {
92                 TFM_FALLBACK_GRAPH.push_back(std::string("netstandard" + version));
93         }
94
95         return TFM_FALLBACK_GRAPH;
96 }
97
98 // move all files under a certain directory to another directory
99 // ownership / permission / smack label are not changed
100 static bool moveAllFilesTo(const std::string& from, const std::string& to)
101 {
102         std::vector<std::string> files;
103         try {
104                 // make file list to move
105                 for (auto& path : bf::recursive_directory_iterator(from)) {
106                         std::string filePath = path.path().string();
107                         if (isFile(filePath)) {
108                                 files.push_back(filePath);
109                         }
110                 }
111
112                 // move files to target directory
113                 for (auto& f : files) {
114                         bf::rename(f, concatPath(to, getFileName(f)));
115                 }
116         }  catch (const bf::filesystem_error& error) {
117                 _ERR("Failed to iterate directory: %s", error.what());
118                 return false;
119         }
120
121         return true;
122 }
123
124 int resolvePlatformSpecificFiles(const std::string& rootPath)
125 {
126         std::string appBinPath = concatPath(rootPath, "bin");
127         std::string runtimesPath = concatPath(appBinPath, "runtimes");
128
129         // if runtimes directory doesnot exist, return 0
130         if (!isDirectory(runtimesPath)) {
131                 return 0;
132         }
133
134         // found best matched rid and tfm directory and copy all files to bin directory
135         std::vector<std::string> ridFallbackGraph = getRidFallbackGraph();
136         try {
137                 for (auto& rid : bf::recursive_directory_iterator(runtimesPath)) {
138                         std::string ridPath = rid.path().string();
139                         if (bf::is_directory(ridPath) && strstr(ridPath.c_str(), ARCHITECTURE_IDENTIFIER) != NULL) {
140                                 for (auto& ridFG : ridFallbackGraph) {
141                                         if (!strcmp(getFileName(ridPath).c_str(), ridFG.c_str())) {
142                                                 std::string nativePath = concatPath(ridPath, "native");
143                                                 if (isDirectory(nativePath)) {
144                                                         _INFO("Found best matched rid (%s)", ridFG.c_str());
145                                                         // copy all files from bin/runtimes/${rid}/native to appBintPath if exist
146                                                         if (!moveAllFilesTo(nativePath, appBinPath)) {
147                                                                 _ERR("Failed to copy files from native path");
148                                                                 return -1;
149                                                         }
150                                                 }
151
152                                                 // found best matched tfm folder in the found rid folder
153                                                 std::string libPath = concatPath(ridPath, "lib");
154                                                 std::vector<std::string> tfmFallbackGraph = getTfmFallbackGraph();
155                                                 for (auto& tfmFG : tfmFallbackGraph) {
156                                                         std::string tfmPath = concatPath(libPath, tfmFG);
157                                                         if (isDirectory(tfmPath)) {
158                                                                 _INFO("Found best matched tfm (%s)", tfmFG .c_str());
159                                                                 // copy all files from bin/runtimes/${rid}/lib/${tfm} to appBintPath if exist
160                                                                 if (!moveAllFilesTo(tfmPath, appBinPath)) {
161                                                                         _ERR("Failed to copy files from tfm path");
162                                                                         return -1;
163                                                                 }
164                                                                 break;
165                                                         }
166                                                 }
167                                                 break;
168                                         }
169                                 }
170                                 break;
171                         }
172                 }
173         } catch (const bf::filesystem_error& error) {
174                 _ERR("Failed to recursive directory: %s", error.what());
175         }
176
177         // remove runtimes directory
178         if (!removeAll(runtimesPath)) {
179                 _ERR("Failed to remove bin/runtimes directory");
180                 return -1;
181         }
182
183         return 0;
184 }
185
186 // callback function of "pkgmgrinfo_appinfo_filter_foreach_appinfo"
187 static int appResolveCb(pkgmgrinfo_appinfo_h handle, void *user_data)
188 {
189         int ret = 0;
190         char* rootPath;
191
192         ret = pkgmgrinfo_appinfo_get_root_path(handle, &rootPath);
193         if (ret != PMINFO_R_OK) {
194                 _SERR("Failed to get root path");
195                 return -1;
196         }
197
198         if (resolvePlatformSpecificFiles(rootPath) != 0) {
199                 _SERR("Failed to resolve platform specific resources (%s)", rootPath);
200                 return -1;
201         }
202
203         return 0;
204 }
205
206 void resolveAllApps()
207 {
208         int ret = 0;
209
210         pkgmgrinfo_appinfo_filter_h handle;
211         ret = pkgmgrinfo_appinfo_filter_create(&handle);
212         if (ret != PMINFO_R_OK) {
213                 _SERR("Failed to create pkgmgrinfo");
214                 return;
215         }
216
217         ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_TYPE, "dotnet");
218         if (ret != PMINFO_R_OK) {
219                 pkgmgrinfo_appinfo_filter_destroy(handle);
220                 _SERR("Failed to add pkgmgrinfo filter app type");
221                 return;
222         }
223
224         ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appResolveCb, NULL);
225         if (ret != PMINFO_R_OK) {
226                 pkgmgrinfo_appinfo_filter_destroy(handle);
227                 _SERR("Failed to remove unused multi-targeting files");
228                 return;
229         }
230         pkgmgrinfo_appinfo_filter_destroy(handle);
231 }