Add "--resolve-all-app" option to dotnettool
authorWoongsuk Cho <ws77.cho@samsung.com>
Tue, 22 Dec 2020 04:16:52 +0000 (13:16 +0900)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Wed, 23 Dec 2020 23:52:02 +0000 (08:52 +0900)
A patch that resolves the "bin/runtimes" directory to support multi-targeting at the app installation time was added after Tizen 6.0.
After applying this patch, it has been changed to no longer refer to the "bin/runtimes" directory of the application.
However, if the target is upgraded by FOTA, installed applications may have "bin/runtimes" directory.

To solve this problem, "--resolve-all-app" option is added to dotnettool and the FOTA script is also updated.
When you run below command, all installed .net application's platform specific files are resolved.

NativeLauncher/CMakeLists.txt
NativeLauncher/inc/multi_target_resolver.h [new file with mode: 0644]
NativeLauncher/installer-plugin/delete_unused_library_plugin.cc
NativeLauncher/tool/dotnettool.cc
NativeLauncher/tool/multi_target_resolver.cc [new file with mode: 0644]
packaging/715.dotnet_regen_app_ni.patch.sh
packaging/dotnet-launcher.spec

index e3254ee..c344aab 100644 (file)
@@ -191,6 +191,14 @@ ADD_LIBRARY(${NI_COMMON} SHARED ${${NI_COMMON}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${NI_COMMON} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_LIB})
 TARGET_LINK_LIBRARIES(${NI_COMMON} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL} ${TAC_COMMON})
 
+SET(MULTI_TARGET_RESOLVER "multi_target_resolver")
+SET(${MULTI_TARGET_RESOLVER}_SOURCE_FILES
+    tool/multi_target_resolver.cc
+)
+ADD_LIBRARY(${MULTI_TARGET_RESOLVER} SHARED ${${MULTI_TARGET_RESOLVER}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${MULTI_TARGET_RESOLVER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_LIB})
+TARGET_LINK_LIBRARIES(${MULTI_TARGET_RESOLVER} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL})
+
 SET(TPATOOL "tpatool")
 SET(${TPATOOL}_SOURCE_FILES
     tool/tpatool.cc
@@ -205,7 +213,7 @@ SET(${DOTNETTOOL}_SOURCE_FILES
 )
 ADD_EXECUTABLE(${DOTNETTOOL} ${${DOTNETTOOL}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${DOTNETTOOL} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_EXE})
-TARGET_LINK_LIBRARIES(${DOTNETTOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUNCHER_UTIL} ${NI_COMMON} ${TAC_COMMON})
+TARGET_LINK_LIBRARIES(${DOTNETTOOL} ${${PROJECT_NAME}_LDFLAGS} "-pie" ${DOTNET_LAUNCHER_UTIL} ${NI_COMMON} ${TAC_COMMON} ${MULTI_TARGET_RESOLVER})
 
 SET(PREFER_DOTNET_AOT_PLUGIN "prefer_dotnet_aot_plugin")
 SET(${PREFER_DOTNET_AOT_PLUGIN}_SOURCE_FILES
@@ -229,7 +237,7 @@ SET(${DELETE_UNUSED_LIBRARY_PLUGIN}_SOURCE_FILES
 )
 ADD_LIBRARY(${DELETE_UNUSED_LIBRARY_PLUGIN} SHARED ${${DELETE_UNUSED_LIBRARY_PLUGIN}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${DELETE_UNUSED_LIBRARY_PLUGIN} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_LIB})
-TARGET_LINK_LIBRARIES(${DELETE_UNUSED_LIBRARY_PLUGIN} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL})
+TARGET_LINK_LIBRARIES(${DELETE_UNUSED_LIBRARY_PLUGIN} ${${PROJECT_NAME}_LDFLAGS} ${DOTNET_LAUNCHER_UTIL} ${MULTI_TARGET_RESOLVER})
 
 CONFIGURE_FILE(dotnet-launcher.pc.in dotnet-launcher.pc @ONLY)
 
@@ -241,6 +249,7 @@ INSTALL(TARGETS ${DOTNET_CORERUN} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${DOTNET_HYDRA_LOADER} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${TAC_COMMON} DESTINATION ${LIBDIR})
 INSTALL(TARGETS ${NI_COMMON} DESTINATION ${LIBDIR})
+INSTALL(TARGETS ${MULTI_TARGET_RESOLVER} DESTINATION ${LIBDIR})
 INSTALL(TARGETS ${TPATOOL} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${DOTNETTOOL} DESTINATION ${BINDIR})
 INSTALL(TARGETS ${PREFER_DOTNET_AOT_PLUGIN} DESTINATION ${INSTALL_MDPLUGIN_DIR})
diff --git a/NativeLauncher/inc/multi_target_resolver.h b/NativeLauncher/inc/multi_target_resolver.h
new file mode 100644 (file)
index 0000000..380fcd0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MULTI_TAEGET_RESOLVER_H__
+#define __MULTI_TAEGET_RESOLVER_H__
+
+/**
+ * @brief Resolve platform specific files which is in bin/runtimes directory
+          All contents which is in best matched RID and TFM path are moved to the "bin" folder.
+ * @param[in] application root path
+ * @return 0 if success, otherwise -1
+ */
+int resolvePlatformSpecificFiles(const std::string& appRootPath);
+
+/**
+ * @brief resolve bin/runtimes directory if exist.
+ * @return 0 if success, otherwise -1
+ */
+int resolveAllApps();
+
+#endif /* __MULTI_TAEGET_RESOLVER_H__ */
index bd248ac..139d70e 100644 (file)
@@ -16,8 +16,8 @@
 
 #include "log.h"
 #include "utils.h"
+#include "multi_target_resolver.h"
 
-#include <vconf.h>
 #include <vector>
 
 #ifdef  LOG_TAG
@@ -29,124 +29,6 @@ typedef struct _xmlDoc xmlDoc;
 typedef xmlDoc* xmlDocPtr;
 
 bool pluginInstalled = false;
-static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version";
-static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support";
-
-static std::vector<std::string> getRidFallbackGraph()
-{
-       std::vector<std::string> RID_FALLBACK_GRAPH;
-       char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
-       if (tizen_rid) {
-               std::vector<std::string> version;
-               splitPath(tizen_rid, version);
-               std::reverse(std::begin(version), std::end(version));
-               for (unsigned int i = 0; i < version.size(); i++) {
-                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i] + "-" + ARCHITECTURE_IDENTIFIER));
-                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i]));
-               }
-               free(tizen_rid);
-       }
-
-       std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
-       for (unsigned int i = 0; i < RID_FALLBACK_OS.size(); i++) {
-               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i] + "-" + ARCHITECTURE_IDENTIFIER));
-               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i]));
-       }
-       RID_FALLBACK_GRAPH.push_back("any");
-       RID_FALLBACK_GRAPH.push_back("base");
-
-       return RID_FALLBACK_GRAPH;
-}
-
-static std::vector<std::string> getTfmFallbackGraph()
-{
-       std::vector<std::string> tfmList;
-       char* tizen_tfm = vconf_get_str(__TIZEN_TFM_SUPPORT_KEY);
-       if (tizen_tfm) {
-               splitPath(tizen_tfm, tfmList);
-               free(tizen_tfm);
-       }
-
-       return tfmList;
-}
-
-static bool copyAllFilesTo(const std::string& from, const std::string& to)
-{
-       std::vector<std::string> files;
-       try {
-               // make file list to move
-               for (auto& path : bf::recursive_directory_iterator(from)) {
-                       std::string filePath = path.path().string();
-                       if (isFile(filePath)) {
-                               files.push_back(filePath);
-                       }
-               }
-
-               // move files to target directory
-               for (auto& f : files) {
-                       bf::rename(f, concatPath(to, getFileName(f)));
-               }
-       }  catch (const bf::filesystem_error& error) {
-               _ERR("Failed to recursive directory: %s", error.what());
-               return false;
-       }
-
-       return true;
-}
-
-static bool resolvePlatformSpecificFiles(const std::string& appBinPath)
-{
-       std::string runtimesPath = concatPath(appBinPath, "runtimes");
-
-       // if runtimes directory doesnot exist, return true
-       if (!isDirectory(runtimesPath)) {
-               return true;
-       }
-
-       // found best matched rid and tfm directory and copy all files to bin directory
-       std::vector<std::string> ridFallbackGraph = getRidFallbackGraph();
-       for (auto& rid : ridFallbackGraph) {
-               std::string ridPath = concatPath(runtimesPath, rid);
-               if (isDirectory(ridPath)) {
-                       _INFO("Found best matched rid path");
-                       // copy all files from /runtimes/${rid}/native to appBintPath if exist
-                       std::string nativePath = concatPath(ridPath, "native");
-                       if (isDirectory(nativePath)) {
-                               _INFO("Found best matched native path");
-                               if (!copyAllFilesTo(nativePath, appBinPath)) {
-                                       _ERR("Failed to copy files from native path");
-                                       return false;
-                               }
-                       }
-
-                       // found best matched tfm folder in the found rid folder
-                       std::string libPath = concatPath(ridPath, "lib");
-                       std::vector<std::string> tfmFallbackGraph = getTfmFallbackGraph();
-                       for (auto& tfm : tfmFallbackGraph) {
-                               std::string tfmPath = concatPath(libPath, tfm);
-                               if (isDirectory(tfmPath)) {
-                                       _INFO("Found best matched tfm path");
-                                       // copy all files from tfmPath to appBintPath
-                                       if (!copyAllFilesTo(tfmPath, appBinPath)) {
-                                               _ERR("Failed to copy files from tfm path");
-                                               return false;
-                                       }
-                               }
-                       }
-
-                       // finish iteration
-                       break;
-               }
-       }
-
-       // remove runtimes directory
-       if (!removeAll(runtimesPath)) {
-               _ERR("Failed to remove bin/runtimes directory");
-               return false;
-       }
-
-       return true;
-}
 
 extern "C" int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr doc, const char* pkgId)
 {
@@ -173,8 +55,7 @@ extern "C" int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr doc, const char* pkgId)
                return 0;
        }
 
-       std::string appBinPath = concatPath(rootPath, "bin");
-       if (!resolvePlatformSpecificFiles(appBinPath)) {
+       if (resolvePlatformSpecificFiles(rootPath) != 0) {
                _ERR("Failed to resolve platform specific resources of nuget");
        }
 
index 4b9e579..c5d5af2 100644 (file)
@@ -17,6 +17,7 @@
 #include "utils.h"
 #include "ni_common.h"
 #include "tac_common.h"
+#include "multi_target_resolver.h"
 
 #include <vector>
 #include <cstring>
@@ -44,6 +45,8 @@ void DisplayUsage() {
                "       --tac-disable-pkg         - Disable TAC for package\n"
                "       --tac-enable-pkg          - Enable TAC for package\n"
                "       --ibc-dir                 - Specify a directory containing IBC files\n"
+               "       --resolve-all-app         - Remove unused multi-targeting files of all apps\n"
+               "                                   (this option is used for FOTA script or test)\n"
                "\n"
                "Options:\n"
                "       --r2r                     - Generate a Ready-To-Run image (disable: /FragileNonVersionable)\n"
@@ -269,6 +272,13 @@ int main(int argc, char* argv[])
                        it = args.erase(it);
                }
        }
+       //sh-3.2# dotnettool --resolve-all-app
+       else if (cmd == "--resolve-all-app") {
+               int ret = resolveAllApps();
+               if (ret != 0) {
+                       fprintf(stderr, "Failed to remove unused multi-targeting files\n");
+               }
+       }
        else {
                fprintf(stderr, "Unknown option [%s]\n", cmd.c_str());
                DisplayUsage();
diff --git a/NativeLauncher/tool/multi_target_resolver.cc b/NativeLauncher/tool/multi_target_resolver.cc
new file mode 100644 (file)
index 0000000..317aae4
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <pkgmgr-info.h>
+#include <vconf.h>
+
+#include "log.h"
+#include "utils.h"
+#include "multi_target_resolver.h"
+
+static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version";
+static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support";
+
+static std::vector<std::string> getRidFallbackGraph()
+{
+       std::vector<std::string> RID_FALLBACK_GRAPH;
+       char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
+       if (tizen_rid) {
+               std::vector<std::string> version;
+               splitPath(tizen_rid, version);
+               std::reverse(std::begin(version), std::end(version));
+               for (unsigned int i = 0; i < version.size(); i++) {
+                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i] + "-" + ARCHITECTURE_IDENTIFIER));
+                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i]));
+               }
+               free(tizen_rid);
+       }
+
+       std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
+       for (unsigned int i = 0; i < RID_FALLBACK_OS.size(); i++) {
+               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i] + "-" + ARCHITECTURE_IDENTIFIER));
+               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i]));
+       }
+       RID_FALLBACK_GRAPH.push_back("any");
+       RID_FALLBACK_GRAPH.push_back("base");
+
+       return RID_FALLBACK_GRAPH;
+}
+
+static std::vector<std::string> getTfmFallbackGraph()
+{
+       std::vector<std::string> tfmList;
+       char* tizen_tfm = vconf_get_str(__TIZEN_TFM_SUPPORT_KEY);
+       if (tizen_tfm) {
+               splitPath(tizen_tfm, tfmList);
+               free(tizen_tfm);
+       }
+
+       return tfmList;
+}
+
+// move all files under a certain directory to another directory
+// ownership / permission / smack label are not changed
+static bool moveAllFilesTo(const std::string& from, const std::string& to)
+{
+       std::vector<std::string> files;
+       try {
+               // make file list to move
+               for (auto& path : bf::recursive_directory_iterator(from)) {
+                       std::string filePath = path.path().string();
+                       if (isFile(filePath)) {
+                               files.push_back(filePath);
+                       }
+               }
+
+               // move files to target directory
+               for (auto& f : files) {
+                       bf::rename(f, concatPath(to, getFileName(f)));
+               }
+       }  catch (const bf::filesystem_error& error) {
+               _ERR("Failed to iterate directory: %s", error.what());
+               return false;
+       }
+
+       return true;
+}
+
+int resolvePlatformSpecificFiles(const std::string& rootPath)
+{
+       std::string appBinPath = concatPath(rootPath, "bin");
+       std::string runtimesPath = concatPath(appBinPath, "runtimes");
+
+       // if runtimes directory doesnot exist, return 0
+       if (!isDirectory(runtimesPath)) {
+               return 0;
+       }
+
+       // found best matched rid and tfm directory and copy all files to bin directory
+       std::vector<std::string> ridFallbackGraph = getRidFallbackGraph();
+       for (auto& rid : ridFallbackGraph) {
+               std::string ridPath = concatPath(runtimesPath, rid);
+               if (isDirectory(ridPath)) {
+                       _INFO("Found best matched rid (%s)", rid.c_str());
+                       // copy all files from /runtimes/${rid}/native to appBintPath if exist
+                       std::string nativePath = concatPath(ridPath, "native");
+                       if (isDirectory(nativePath)) {
+                               _INFO("Found best matched native path");
+                               if (!moveAllFilesTo(nativePath, appBinPath)) {
+                                       _ERR("Failed to copy files from native path");
+                                       return -1;
+                               }
+                       }
+
+                       // found best matched tfm folder in the found rid folder
+                       std::string libPath = concatPath(ridPath, "lib");
+                       std::vector<std::string> tfmFallbackGraph = getTfmFallbackGraph();
+                       for (auto& tfm : tfmFallbackGraph) {
+                               std::string tfmPath = concatPath(libPath, tfm);
+                               if (isDirectory(tfmPath)) {
+                                       _INFO("Found best matched tfm (%s)", tfm .c_str());
+                                       // copy all files from tfmPath to appBintPath
+                                       if (!moveAllFilesTo(tfmPath, appBinPath)) {
+                                               _ERR("Failed to copy files from tfm path");
+                                               return -1;
+                                       }
+                               }
+                       }
+
+                       break;
+               }
+       }
+
+       // remove runtimes directory
+       if (!removeAll(runtimesPath)) {
+               _ERR("Failed to remove bin/runtimes directory");
+               return -1;
+       }
+
+       return 0;
+}
+
+// callback function of "pkgmgrinfo_appinfo_filter_foreach_appinfo"
+static int appResolveCb(pkgmgrinfo_appinfo_h handle, void *user_data)
+{
+       int ret = 0;
+       char* rootPath;
+
+       ret = pkgmgrinfo_appinfo_get_root_path(handle, &rootPath);
+       if (ret != PMINFO_R_OK) {
+               fprintf(stderr, "Failed to get root path");
+               return -1;
+       }
+
+       if (resolvePlatformSpecificFiles(rootPath) != 0) {
+               fprintf(stderr, "Failed to resolve platform specific resources (%s)\n", rootPath);
+               return -1;
+       }
+
+       return 0;
+}
+
+int resolveAllApps()
+{
+       int ret = 0;
+
+       pkgmgrinfo_appinfo_filter_h handle;
+       ret = pkgmgrinfo_appinfo_filter_create(&handle);
+       if (ret != PMINFO_R_OK) {
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_TYPE, "dotnet");
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_filter_destroy(handle);
+               return -1;
+       }
+
+       ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appResolveCb, NULL);
+       if (ret != PMINFO_R_OK) {
+               pkgmgrinfo_appinfo_filter_destroy(handle);
+               return -1;
+       }
+       pkgmgrinfo_appinfo_filter_destroy(handle);
+
+       return 0;
+}
+
index 1a6dda6..85008df 100644 (file)
@@ -6,4 +6,4 @@ PATH=/usr/bin:/bin:/usr/sbin:/sbin
 
 /usr/bin/dotnettool --tac-regen-all
 /usr/bin/dotnettool --ni-regen-all-app
-
+/usr/bin/dotnettool --resolve-all-app
index 7d1ee19..80685dc 100644 (file)
@@ -196,6 +196,7 @@ chsmack -a User /usr/bin/dotnet-nui-loader
 %{_libdir}/libdotnet_launcher_core.so
 %{_libdir}/libni_common.so
 %{_libdir}/libtac_common.so
+%{_libdir}/libmulti_target_resolver.so
 %{_tmpfilesdir}/%{name}.conf
 /usr/share/parser-plugins/dotnet-launcher.info
 %{_framework_dir}/Tizen.Runtime.dll