Create vconf related to .NET as a file in RO location
[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
19 #include <pkgmgr-info.h>
20 #include <vconf.h>
21
22 #include "log.h"
23 #include "utils.h"
24 #include "multi_target_resolver.h"
25
26 static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version";
27 static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support";
28 static const char* __DOTNET_RUNTIME_VERSION_KEY = "db/dotnet/runtime_version";
29 static std::vector<std::string> platform_version_list;
30 /*
31 Priority | RID                 | TFM
32 ---------|---------------------|-----------------------
33 1        | tizen.X.Y.Z-{arch}  | netX.Y-tizenX.Y ~ 6.5
34 2        | tizen.X.Y.Z         | netX.Y-tizen
35 3        | tizen-{arch}, tizen | netX.Y
36 4        | linux-{arch}, linux | tizen90 ~ 40
37 5        | unix-{arch}, unix   | net5.0
38 6        | any                 | netcoreapp3.1 ~ 1.0
39 7        | base                | netstandard2.1 ~ 1.0
40 */
41
42 static int convertStrVersionToInt(const std::string& version)
43 {
44         int ret = 0;
45         for (unsigned int i = 0; i < version.length(); i++) {
46                 if (std::isdigit(int(version[i]))) {
47                         ret = ret * 10 + (int(version[i]) - '0');
48                 }
49         }
50         return ret;
51 }
52
53 // Guided by Appfw, vconf daemon does not run at mic stage.
54 // So vconf_get_* api does not work normally.
55 // Therefore, it provides a second chance to read the file when vconf_get_* is null.
56 // /usr/share/dotnet.tizen/lib/dotnet_resolving.info
57 static std::string getDotnetResolvingInfo(const char* key)
58 {
59         std::ifstream ifs(DOTNET_RESOLVING_INFO_PATH);
60         std::string line;
61         while (std::getline(ifs, line)) {
62                 if (!strcmp(line.substr(0, line.find(" ")).c_str(), key)) {
63                         ifs.close();
64                         return line.substr(line.rfind(" ") + 1);
65                 }
66         }
67         _ERR("Faield to get vconf. %s is null", key);
68         return "";
69 }
70
71 static std::vector<std::string> getRidFallbackGraph()
72 {
73         std::string tizen_rid_version;
74         char* tizen_rid_version_value = vconf_get_str(__TIZEN_RID_VERSION_KEY);
75         if (!tizen_rid_version_value) {
76                 _INFO("Faield to get vconf. So, Read the dotnet_resolving.info file");
77                 tizen_rid_version = getDotnetResolvingInfo(__TIZEN_RID_VERSION_KEY);
78         } else {
79                 tizen_rid_version = std::string(tizen_rid_version_value);
80                 free(tizen_rid_version_value);
81         }
82
83         std::vector<std::string> rid_version;
84         std::vector<std::string> RID_FALLBACK_GRAPH;
85         splitPath(tizen_rid_version, rid_version);
86         std::reverse(std::begin(rid_version), std::end(rid_version));
87         for (auto& ridVersion : rid_version) {
88                 //.NET 6.0 is supported from Tizen 6.5.0
89                 if (convertStrVersionToInt(ridVersion) >= 650) {
90                         platform_version_list.push_back(ridVersion.substr(0, ridVersion.rfind('.')));
91                 }
92                 RID_FALLBACK_GRAPH.push_back(std::string("tizen." + ridVersion + "-" + ARCHITECTURE_IDENTIFIER));
93                 RID_FALLBACK_GRAPH.push_back(std::string("tizen." + ridVersion));
94         }
95
96         std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
97         for (auto& os : RID_FALLBACK_OS) {
98                 RID_FALLBACK_GRAPH.push_back(std::string(os + "-" + ARCHITECTURE_IDENTIFIER));
99                 RID_FALLBACK_GRAPH.push_back(std::string(os));
100         }
101         RID_FALLBACK_GRAPH.push_back("any");
102         RID_FALLBACK_GRAPH.push_back("base");
103
104         return RID_FALLBACK_GRAPH;
105 }
106
107 static std::vector<std::string> getTfmFallbackGraph()
108 {
109         std::string dotnet_runtime_version;
110         char* dotnet_runtime_version_value = vconf_get_str(__DOTNET_RUNTIME_VERSION_KEY);
111         if (!dotnet_runtime_version_value) {
112                 _INFO("Faield to get vconf. So, Read the dotnet_resolving.info file");
113                 dotnet_runtime_version = getDotnetResolvingInfo(__DOTNET_RUNTIME_VERSION_KEY);
114         } else {
115                 dotnet_runtime_version = std::string(dotnet_runtime_version_value);
116                 free(dotnet_runtime_version_value);
117         }
118
119         std::vector<std::string> tfm_list;
120         std::vector<std::string> dotnet_version;
121         splitPath(dotnet_runtime_version, dotnet_version);
122         for (auto& dotnetVersion : dotnet_version) {
123                 for (auto& platformVersion : platform_version_list) {
124                         tfm_list.push_back(std::string("net" + dotnetVersion + "-tizen" + platformVersion));
125                 }
126                 tfm_list.push_back(std::string("net" + dotnetVersion + "-tizen"));
127                 tfm_list.push_back(std::string("net" + dotnetVersion));
128         }
129
130         std::string tizen_tfm;
131         char* tizen_tfm_value = vconf_get_str(__TIZEN_TFM_SUPPORT_KEY);
132         if (!tizen_tfm_value) {
133                 _INFO("Faield to get vconf. So, Read the dotnet_resolving.info file");
134                 tizen_tfm = getDotnetResolvingInfo(__TIZEN_TFM_SUPPORT_KEY);
135         } else {
136                 tizen_tfm = std::string(tizen_tfm_value);
137                 free(tizen_tfm_value);
138         }
139         splitPath(tizen_tfm, tfm_list);
140         tfm_list.push_back("net5.0");
141
142         std::vector<std::string> netcoreapp_version = {"3.1", "3.0", "2.2", "2.1", "2.0", "1.1", "1.0"};
143         for (auto& version : netcoreapp_version) {
144                 tfm_list.push_back(std::string("netcoreapp" + version));
145         }
146         std::vector<std::string> netstandard_version = {"2.1", "2.0", "1.6", "1.5", "1.4", "1.3", "1.2", "1.1", "1.0"};
147         for (auto& version : netstandard_version) {
148                 tfm_list.push_back(std::string("netstandard" + version));
149         }
150
151         return tfm_list;
152 }
153
154 // move all files under a certain directory to another directory
155 // ownership / permission / smack label are not changed
156 static bool moveAllFilesTo(const std::string& from, const std::string& to)
157 {
158         std::vector<std::string> files;
159         try {
160                 // make file list to move
161                 for (auto& path : bf::recursive_directory_iterator(from)) {
162                         std::string filePath = path.path().string();
163                         if (isFile(filePath)) {
164                                 files.push_back(filePath);
165                         }
166                 }
167
168                 // move files to target directory
169                 for (auto& f : files) {
170                         bf::rename(f, concatPath(to, getFileName(f)));
171                 }
172         }  catch (const bf::filesystem_error& error) {
173                 _ERR("Failed to iterate directory: %s", error.what());
174                 return false;
175         }
176
177         return true;
178 }
179
180 int resolvePlatformSpecificFiles(const std::string& rootPath)
181 {
182         std::string appBinPath = concatPath(rootPath, "bin");
183         std::string runtimesPath = concatPath(appBinPath, "runtimes");
184
185         // if runtimes directory doesnot exist, return 0
186         if (!isDirectory(runtimesPath)) {
187                 return 0;
188         }
189
190         // found best matched rid and tfm directory and copy all files to bin directory
191         std::vector<std::string> ridFallbackGraph = getRidFallbackGraph();
192         for (auto& rid : ridFallbackGraph) {
193                 std::string ridPath = concatPath(runtimesPath, rid);
194                 if (isDirectory(ridPath)) {
195                         _INFO("Found best matched rid (%s)", rid.c_str());
196                         // copy all files from /runtimes/${rid}/native to appBintPath if exist
197                         std::string nativePath = concatPath(ridPath, "native");
198                         if (isDirectory(nativePath)) {
199                                 _INFO("Found best matched native path");
200                                 if (!moveAllFilesTo(nativePath, appBinPath)) {
201                                         _ERR("Failed to copy files from native path");
202                                         return -1;
203                                 }
204                         }
205
206                         // found best matched tfm folder in the found rid folder
207                         std::string libPath = concatPath(ridPath, "lib");
208                         std::vector<std::string> tfmFallbackGraph = getTfmFallbackGraph();
209                         for (auto& tfm : tfmFallbackGraph) {
210                                 std::string tfmPath = concatPath(libPath, tfm);
211                                 if (isDirectory(tfmPath)) {
212                                         _INFO("Found best matched tfm (%s)", tfm .c_str());
213                                         // copy all files from tfmPath to appBintPath
214                                         if (!moveAllFilesTo(tfmPath, appBinPath)) {
215                                                 _ERR("Failed to copy files from tfm path");
216                                                 return -1;
217                                         }
218                                         break;
219                                 }
220                         }
221                         break;
222                 }
223         }
224
225         // remove runtimes directory
226         if (!removeAll(runtimesPath)) {
227                 _ERR("Failed to remove bin/runtimes directory");
228                 return -1;
229         }
230
231         return 0;
232 }
233
234 // callback function of "pkgmgrinfo_appinfo_filter_foreach_appinfo"
235 static int appResolveCb(pkgmgrinfo_appinfo_h handle, void *user_data)
236 {
237         int ret = 0;
238         char* rootPath;
239
240         ret = pkgmgrinfo_appinfo_get_root_path(handle, &rootPath);
241         if (ret != PMINFO_R_OK) {
242                 _SERR("Failed to get root path");
243                 return -1;
244         }
245
246         if (resolvePlatformSpecificFiles(rootPath) != 0) {
247                 _SERR("Failed to resolve platform specific resources (%s)", rootPath);
248                 return -1;
249         }
250
251         return 0;
252 }
253
254 int resolveAllApps()
255 {
256         int ret = 0;
257
258         pkgmgrinfo_appinfo_filter_h handle;
259         ret = pkgmgrinfo_appinfo_filter_create(&handle);
260         if (ret != PMINFO_R_OK) {
261                 return -1;
262         }
263
264         ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_TYPE, "dotnet");
265         if (ret != PMINFO_R_OK) {
266                 pkgmgrinfo_appinfo_filter_destroy(handle);
267                 return -1;
268         }
269
270         ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appResolveCb, NULL);
271         if (ret != PMINFO_R_OK) {
272                 pkgmgrinfo_appinfo_filter_destroy(handle);
273                 return -1;
274         }
275         pkgmgrinfo_appinfo_filter_destroy(handle);
276
277         return 0;
278 }