This is an automated email from the ASF dual-hosted git repository. pengzheng pushed a commit to branch feature/556-osgi-uninstall in repository https://gitbox.apache.org/repos/asf/celix.git
commit 6008b3d734a204711b98c4b588bcd51dfa0b2384 Author: PengZheng <[email protected]> AuthorDate: Thu Jun 1 21:40:26 2023 +0800 Add support for bundle unload. Unloading a bundle from a framework instance will release all its resources but leave the bundle in cache so that it can be reloaded using `install`. --- bundles/shell/shell/CMakeLists.txt | 1 + bundles/shell/shell/gtest/src/ShellTestSuite.cc | 3 + bundles/shell/shell/src/std_commands.c | 9 ++- bundles/shell/shell/src/std_commands.h | 2 + bundles/shell/shell/src/unload_command.c | 24 +++++++ .../src/CelixBundleContextBundlesTestSuite.cc | 82 +++++++++++++++++++++- .../framework/gtest/src/CelixFrameworkTestSuite.cc | 9 +++ libs/framework/include/celix_bundle_context.h | 16 +++++ libs/framework/include/celix_framework.h | 22 ++++++ libs/framework/src/bundle.c | 4 +- libs/framework/src/bundle_context.c | 4 ++ libs/framework/src/framework.c | 16 +++-- .../src/framework_bundle_lifecycle_handler.c | 14 ++-- libs/framework/src/framework_private.h | 6 +- 14 files changed, 195 insertions(+), 17 deletions(-) diff --git a/bundles/shell/shell/CMakeLists.txt b/bundles/shell/shell/CMakeLists.txt index a07c76b6..34914da8 100644 --- a/bundles/shell/shell/CMakeLists.txt +++ b/bundles/shell/shell/CMakeLists.txt @@ -41,6 +41,7 @@ if (SHELL) src/install_command.c src/update_command.c src/uninstall_command.c + src/unload_command.c src/help_command.c src/dm_shell_list_command.c src/query_command.c diff --git a/bundles/shell/shell/gtest/src/ShellTestSuite.cc b/bundles/shell/shell/gtest/src/ShellTestSuite.cc index 36d1f9c2..4117f0ad 100644 --- a/bundles/shell/shell/gtest/src/ShellTestSuite.cc +++ b/bundles/shell/shell/gtest/src/ShellTestSuite.cc @@ -104,11 +104,14 @@ TEST_F(ShellTestSuite, testAllCommandsAreCallable) { callCommand(ctx, "start", false); // incorrect number of arguments callCommand(ctx, "uninstall not-a-number", false); callCommand(ctx, "uninstall", false); // incorrect number of arguments + callCommand(ctx, "unload not-a-number", false); + callCommand(ctx, "unload", false); // incorrect number of arguments callCommand(ctx, "update not-a-number", false); callCommand(ctx, "update", false); // incorrect number of arguments callCommand(ctx, "stop 15", false); //non existing bundle id callCommand(ctx, "start 15", false); //non existing bundle id callCommand(ctx, "uninstall 15", false); //non existing bundle id + callCommand(ctx, "unload 15", false); //non existing bundle id callCommand(ctx, "update 15", false); //non existing bundle id } diff --git a/bundles/shell/shell/src/std_commands.c b/bundles/shell/shell/src/std_commands.c index dd3934ad..8edbf092 100644 --- a/bundles/shell/shell/src/std_commands.c +++ b/bundles/shell/shell/src/std_commands.c @@ -82,7 +82,7 @@ celix_std_commands_t* celix_stdCommands_create(celix_bundle_context_t* ctx) { .exec = uninstallCommand_execute, .name = "celix::uninstall", .description = "uninstall bundle(s).", - .usage = "uninstall <file> [<file> ...]" + .usage = "uninstall <id> [<id> ...]" }; commands->std_commands[5] = (struct celix_shell_command_register_entry) { @@ -133,6 +133,13 @@ celix_std_commands_t* celix_stdCommands_create(celix_bundle_context_t* ctx) { .usage = "quit" }; commands->std_commands[11] = + (struct celix_shell_command_register_entry) { + .exec = unloadCommand_execute, + .name = "celix::unload", + .description = "unload bundle(s).", + .usage = "unload <id> [<id> ...]" + }; + commands->std_commands[12] = (struct celix_shell_command_register_entry) { .exec = NULL }; diff --git a/bundles/shell/shell/src/std_commands.h b/bundles/shell/shell/src/std_commands.h index 6c0a8d06..a2be1070 100644 --- a/bundles/shell/shell/src/std_commands.h +++ b/bundles/shell/shell/src/std_commands.h @@ -48,6 +48,8 @@ bool installCommand_execute(void *handle, const char *commandLine, FILE *outStre bool uninstallCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream); +bool unloadCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream); + bool updateCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream); bool helpCommand_execute(void *handle, const char *commandLine, FILE *outStream, FILE *errStream); diff --git a/bundles/shell/shell/src/unload_command.c b/bundles/shell/shell/src/unload_command.c new file mode 100644 index 00000000..b27a37e1 --- /dev/null +++ b/bundles/shell/shell/src/unload_command.c @@ -0,0 +1,24 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 "bundle_command.h" + +bool unloadCommand_execute(void *handle, const char* constCommandLine, FILE *outStream, FILE *errStream) { + return bundleCommand_execute(handle, constCommandLine, outStream, errStream, celix_framework_unloadBundleAsync); +} diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc index e6213766..f7672087 100644 --- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc @@ -203,11 +203,87 @@ TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUninstallBundlesTest) { long bndId6 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true); ASSERT_TRUE(bndId4 >= 0L); - ASSERT_FALSE(bndId1 == bndId4); //bundle cache -> reuse of bundle id. + ASSERT_FALSE(bndId1 == bndId4); ASSERT_TRUE(bndId5 >= 0L); - ASSERT_FALSE(bndId2 == bndId5); //bundle cache -> reuse of bundle id. + ASSERT_FALSE(bndId2 == bndId5); ASSERT_TRUE(bndId6 >= 0L); - ASSERT_FALSE(bndId3 == bndId6); //bundle cache -> reuse of bundle id. + ASSERT_FALSE(bndId3 == bndId6); +} + +TEST_F(CelixBundleContextBundlesTestSuite, InstallAndUnloadBundlesTest) { + //install bundles + long bndId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true); + long bndId2 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false); + long bndId3 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true); + + ASSERT_TRUE(bndId1 >= 0L); + ASSERT_TRUE(bndId2 >= 0L); + ASSERT_TRUE(bndId3 >= 0L); + + ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1)); + ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId2)); + ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId3)); + + ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1)); + ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2)); //not auto started + ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId3)); + + char *bndRoot1 = nullptr; + ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId1, &bndRoot1, [](void* handle, const celix_bundle_t* bnd) { + char **root = static_cast<char **>(handle); + *root = celix_bundle_getEntry(bnd, "/"); + })); + ASSERT_TRUE(bndRoot1 != nullptr); + char* bndRoot2 = nullptr; + ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId2, &bndRoot2, [](void* handle, const celix_bundle_t* bnd) { + char **root = static_cast<char **>(handle); + *root = celix_bundle_getEntry(bnd, "/"); + })); + ASSERT_TRUE(bndRoot2 != nullptr); + char* bndRoot3 = nullptr; + ASSERT_TRUE(celix_bundleContext_useBundle(ctx, bndId3, &bndRoot3, [](void* handle, const celix_bundle_t* bnd) { + char **root = static_cast<char **>(handle); + *root = celix_bundle_getEntry(bnd, "/"); + })); + ASSERT_TRUE(bndRoot3 != nullptr); + + ASSERT_TRUE(celix_utils_directoryExists(bndRoot1)); + ASSERT_TRUE(celix_utils_directoryExists(bndRoot2)); + ASSERT_TRUE(celix_utils_directoryExists(bndRoot3)); + + //unload bundles + ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId1)); + ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId2)); + ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId3)); + + ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId1)); + ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId2)); + ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, bndId3)); + + ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId1)); //not uninstall -> not active + ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId2)); + ASSERT_FALSE(celix_bundleContext_isBundleActive(ctx, bndId3)); + + // bundle cache is NOT cleaned up + ASSERT_TRUE(celix_utils_directoryExists(bndRoot1)); + ASSERT_TRUE(celix_utils_directoryExists(bndRoot2)); + ASSERT_TRUE(celix_utils_directoryExists(bndRoot3)); + + free(bndRoot1); + free(bndRoot2); + free(bndRoot3); + + //reinstall bundles + long bndId4 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true); + long bndId5 = celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, false); + long bndId6 = celix_bundleContext_installBundle(ctx, TEST_BND3_LOC, true); + + ASSERT_TRUE(bndId4 >= 0L); + ASSERT_TRUE(bndId1 == bndId4); //bundle cache -> reuse of bundle id. + ASSERT_TRUE(bndId5 >= 0L); + ASSERT_TRUE(bndId2 == bndId5); //bundle cache -> reuse of bundle id. + ASSERT_TRUE(bndId6 >= 0L); + ASSERT_TRUE(bndId3 == bndId6); //bundle cache -> reuse of bundle id. } TEST_F(CelixBundleContextBundlesTestSuite, StartBundleWithException) { diff --git a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc index 1a3562c1..89c20f61 100644 --- a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc +++ b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc @@ -93,6 +93,15 @@ TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopAndUninstallBundleTest) { std::this_thread::sleep_for(std::chrono::milliseconds{100}); EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId)); + celix_framework_unloadBundleAsync(framework.get(), bndId); + std::this_thread::sleep_for(std::chrono::milliseconds{100}); + EXPECT_FALSE(celix_framework_isBundleInstalled(framework.get(), bndId)); + + // reloaded bundle should reuse the same bundle id + EXPECT_EQ(bndId, celix_framework_installBundleAsync(framework.get(), SIMPLE_TEST_BUNDLE1_LOCATION, false)); + EXPECT_TRUE(celix_framework_isBundleInstalled(framework.get(), bndId)); + EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId)); + celix_framework_uninstallBundleAsync(framework.get(), bndId); std::this_thread::sleep_for(std::chrono::milliseconds{100}); EXPECT_FALSE(celix_framework_isBundleInstalled(framework.get(), bndId)); diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h index 8b1ef2bc..fc73b180 100644 --- a/libs/framework/include/celix_bundle_context.h +++ b/libs/framework/include/celix_bundle_context.h @@ -905,6 +905,22 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_installBundle(celix_bundle_conte */ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_uninstallBundle(celix_bundle_context_t *ctx, long bndId); +/** + * @brief Unload the bundle with the provided bundle id. If needed the bundle will be stopped first. + * Will silently ignore bundle ids < 0. + * Note that unloaded bundle is kept in bundle cache and can be reloaded with the celix_bundleContext_installBundle function. + * + * If this function is called on the Celix event thread, the actual stopping of the bundle will be done async and + * on a separate thread. + * If this function is called from a different thread than the Celix event thread, then the function will return after + * the bundle is stopped. + * + * @param ctx The bundle context + * @param bndId The bundle id to unload. + * @return true if the bundle is correctly unloaded. False if not. + */ +CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_unloadBundle(celix_bundle_context_t *ctx, long bndId); + /** * @brief Stop the bundle with the provided bundle id. * Will silently ignore bundle ids < 0. diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h index e5beb0d2..2bfbd114 100644 --- a/libs/framework/include/celix_framework.h +++ b/libs/framework/include/celix_framework.h @@ -138,6 +138,17 @@ CELIX_FRAMEWORK_EXPORT long celix_framework_installBundle(celix_framework_t *fw, */ CELIX_FRAMEWORK_EXPORT bool celix_framework_uninstallBundle(celix_framework_t *fw, long bndId); +/** + * @brief Unload the bundle with the provided bundle id. If needed the bundle will be stopped first. + * Will silently ignore bundle ids < 0. + * Note that unloaded bundle is kept in bundle cache and can be reloaded with the celix_framework_installBundle function. + * + * @param fw The Celix framework + * @param bndId The bundle id to unload. + * @return true if the bundle is correctly unloaded. False if not. + */ +CELIX_FRAMEWORK_EXPORT bool celix_framework_unloadBundle(celix_framework_t *fw, long bndId); + /** * @brief Update the bundle with the provided bundle id. * @@ -221,6 +232,17 @@ CELIX_FRAMEWORK_EXPORT void celix_framework_updateBundleAsync(celix_framework_t */ CELIX_FRAMEWORK_EXPORT void celix_framework_uninstallBundleAsync(celix_framework_t *fw, long bndId); +/** + * @brief Unload the bundle with the provided bundle id async. If needed the bundle will be stopped first. + * Will silently ignore bundle ids < 0. + * Note that unloaded bundle is kept in bundle cache and can be reloaded with the celix_framework_installBundle function. + * The bundle will be unloaded on a separate spawned thread. + * + * @param fw The Celix framework + * @param bndId The bundle id to unload. + */ +CELIX_FRAMEWORK_EXPORT void celix_framework_unloadBundleAsync(celix_framework_t *fw, long bndId); + /** * @brief Stop the bundle with the provided bundle id async. * Will silently ignore bundle ids < 0. diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c index 7f08f15e..64eaa241 100644 --- a/libs/framework/src/bundle.c +++ b/libs/framework/src/bundle.c @@ -238,8 +238,8 @@ celix_status_t bundle_update(bundle_pt bundle, const char* updatedBundleUrl) { } celix_status_t bundle_stop(bundle_pt bundle) { - //note deprecated call use celix_bundleContext_startBundle instead - return celix_framework_startBundle(bundle->framework, celix_bundle_getId(bundle)); + //note deprecated call use celix_bundleContext_stopBundle instead + return celix_framework_stopBundle(bundle->framework, celix_bundle_getId(bundle)); } celix_status_t bundle_uninstall(bundle_pt bundle) { diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c index 8a802b7c..b3f70232 100644 --- a/libs/framework/src/bundle_context.c +++ b/libs/framework/src/bundle_context.c @@ -995,6 +995,10 @@ bool celix_bundleContext_uninstallBundle(bundle_context_t *ctx, long bndId) { return celix_framework_uninstallBundle(ctx->framework, bndId); } +bool celix_bundleContext_unloadBundle(celix_bundle_context_t *ctx, long bndId) { + return celix_framework_unloadBundle(ctx->framework, bndId); +} + bool celix_bundleContext_useServiceWithId( bundle_context_t *ctx, long serviceId, diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c index 823d3d19..8671abac 100644 --- a/libs/framework/src/framework.c +++ b/libs/framework/src/framework.c @@ -1872,11 +1872,11 @@ long celix_framework_installBundleAsync(celix_framework_t *fw, const char *bundl return celix_framework_installAndStartBundleInternal(fw, bundleLoc, autoStart, true); } -static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long bndId, bool forcedAsync) { +static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long bndId, bool forcedAsync, bool permanent) { bool uninstalled = false; celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry != NULL) { - celix_status_t status = celix_framework_uninstallBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync); + celix_status_t status = celix_framework_uninstallBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync, permanent); celix_framework_waitForBundleEvents(fw, bndId); //note not decreasing bndEntry, because this entry should now be deleted (uninstalled) uninstalled = status == CELIX_SUCCESS; @@ -1885,11 +1885,19 @@ static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long } bool celix_framework_uninstallBundle(celix_framework_t *fw, long bndId) { - return celix_framework_uninstallBundleInternal(fw, bndId, false); + return celix_framework_uninstallBundleInternal(fw, bndId, false, true); } void celix_framework_uninstallBundleAsync(celix_framework_t *fw, long bndId) { - celix_framework_uninstallBundleInternal(fw, bndId, true); + celix_framework_uninstallBundleInternal(fw, bndId, true, true); +} + +bool celix_framework_unloadBundle(celix_framework_t *fw, long bndId) { + return celix_framework_uninstallBundleInternal(fw, bndId, false, false); +} + +void celix_framework_unloadBundleAsync(celix_framework_t *fw, long bndId) { + celix_framework_uninstallBundleInternal(fw, bndId, true, false); } celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry, bool permanent) { diff --git a/libs/framework/src/framework_bundle_lifecycle_handler.c b/libs/framework/src/framework_bundle_lifecycle_handler.c index 669778d8..6ffa9bb3 100644 --- a/libs/framework/src/framework_bundle_lifecycle_handler.c +++ b/libs/framework/src/framework_bundle_lifecycle_handler.c @@ -49,11 +49,15 @@ static void* celix_framework_BundleLifecycleHandlingThread(void *data) { celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, true); break; + case CELIX_BUNDLE_LIFECYCLE_UNLOAD: + celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); + celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, false); + break; default: //update celix_framework_updateBundleEntry(handler->framework, handler->bndEntry, handler->updatedBundleUrl); break; } - if (handler->command != CELIX_BUNDLE_LIFECYCLE_UNINSTALL) { + if (handler->command != CELIX_BUNDLE_LIFECYCLE_UNINSTALL && handler->command != CELIX_BUNDLE_LIFECYCLE_UNLOAD) { celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); } celix_framework_cleanupBundleLifecycleHandler(handler->framework, handler); @@ -132,18 +136,18 @@ celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_ } } -celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread) { +celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent) { if (forceSpawnThread) { fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "uninstall bundle from a separate thread"); - celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_UNINSTALL, NULL); + celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, permanent ? CELIX_BUNDLE_LIFECYCLE_UNINSTALL : CELIX_BUNDLE_LIFECYCLE_UNLOAD, NULL); return CELIX_SUCCESS; } else if (celix_framework_isCurrentThreadTheEventLoop(fw)) { fw_log(fw->logger, CELIX_LOG_LEVEL_DEBUG, "Cannot uninstall bundle from Celix event thread. Using a separate thread to uninstall bundle. See celix_bundleContext_uninstall Bundle for more info."); - celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_UNINSTALL, NULL); + celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, permanent ? CELIX_BUNDLE_LIFECYCLE_UNINSTALL : CELIX_BUNDLE_LIFECYCLE_UNLOAD, NULL); return CELIX_SUCCESS; } else { - return celix_framework_uninstallBundleEntry(fw, bndEntry, true); + return celix_framework_uninstallBundleEntry(fw, bndEntry, permanent); } } diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h index f2944cac..c506e94b 100644 --- a/libs/framework/src/framework_private.h +++ b/libs/framework/src/framework_private.h @@ -113,7 +113,8 @@ enum celix_bundle_lifecycle_command { CELIX_BUNDLE_LIFECYCLE_START, CELIX_BUNDLE_LIFECYCLE_STOP, CELIX_BUNDLE_LIFECYCLE_UNINSTALL, - CELIX_BUNDLE_LIFECYCLE_UPDATE + CELIX_BUNDLE_LIFECYCLE_UPDATE, + CELIX_BUNDLE_LIFECYCLE_UNLOAD }; typedef struct celix_framework_bundle_lifecycle_handler { @@ -396,9 +397,10 @@ celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_ * @param fw The Celix framework * @param bndEntry A bnd entry * @param forceSpawnThread If the true, the start bundle will always be done on a spawn thread + * @param permanent If true, the bundle will be permanently uninstalled (e.g. the bundle archive will be removed). * @return CELIX_SUCCESS of the call went alright. */ -celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread); +celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent); /** * Update (and if needed stop and start) a bundle and ensure that this is not done on the Celix event thread.
