This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch 
feature/87-add-additional-svc-tracker-bundle-context-funtions
in repository https://gitbox.apache.org/repos/asf/celix.git

commit b5ee724a43a4bfc7def24102f8648b4c58388d8e
Author: Pepijn Noltes <pnol...@apache.org>
AuthorDate: Sat Feb 10 17:15:29 2024 +0100

    gh-509: Add bundle context functions to use underlying svc tracker
---
 .../src/CelixBundleContextServicesTestSuite.cc     | 168 +++++++
 libs/framework/include/celix_bundle_context.h      | 555 +++++++++++++++------
 .../framework/include_deprecated/service_tracker.h |  17 +-
 libs/framework/src/bundle.c                        |   5 +-
 libs/framework/src/bundle_context.c                | 261 +++++++---
 libs/framework/src/bundle_context_private.h        |  29 +-
 libs/framework/src/service_tracker.c               |  30 +-
 7 files changed, 821 insertions(+), 244 deletions(-)

diff --git a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc 
b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
index d17b3892..02c49949 100644
--- a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
@@ -52,6 +52,8 @@ public:
 
         fw = celix_frameworkFactory_createFramework(properties);
         ctx = framework_getContext(fw);
+
+        celix_err_resetErrors();
     }
 
     ~CelixBundleContextServicesTestSuite() override {
@@ -1741,3 +1743,169 @@ TEST_F(CelixBundleContextServicesTestSuite, 
SetServicesWithTrackerWhenMultipleRe
     celix_bundleContext_unregisterService(ctx, svcId2);
     celix_bundleContext_unregisterService(ctx, svcId3);
 }
+
+
+TEST_F(CelixBundleContextServicesTestSuite, 
InvalidArgumentsForUseTrackedServicesTest) {
+    EXPECT_FALSE(celix_bundleContext_useTrackedService(ctx, -1, nullptr, 
nullptr));
+    EXPECT_FALSE(celix_bundleContext_useTrackedService(ctx, 1 /*non 
existing*/, nullptr, nullptr));
+
+    EXPECT_EQ(0, celix_bundleContext_useTrackedServices(ctx, -1, nullptr, 
nullptr));
+    EXPECT_EQ(0, celix_bundleContext_useTrackedServices(ctx, 1 /*non 
existing*/, nullptr, nullptr));
+
+    celix_tracked_service_use_options_t useOpts{};
+    EXPECT_FALSE(celix_bundleContext_useTrackedServiceWithOptions(ctx, -1, 
&useOpts));
+    EXPECT_FALSE(celix_bundleContext_useTrackedServiceWithOptions(ctx, 1 /*non 
existing*/, &useOpts));
+
+    EXPECT_EQ(0, celix_bundleContext_useTrackedServicesWithOptions(ctx, -1, 
&useOpts));
+    EXPECT_EQ(0, celix_bundleContext_useTrackedServicesWithOptions(ctx, 1 
/*non existing*/, &useOpts));
+
+    EXPECT_EQ(0, celix_bundleContext_getTrackedServiceCount(ctx, -1));
+    EXPECT_EQ(0, celix_bundleContext_getTrackedServiceCount(ctx, 1 /*non 
existing*/));
+
+    EXPECT_EQ(nullptr, celix_bundleContext_getTrackedServiceName(ctx, -1));
+    EXPECT_EQ(nullptr, celix_bundleContext_getTrackedServiceName(ctx, 1 /*non 
existing*/));
+
+    EXPECT_EQ(nullptr, celix_bundleContext_getTrackedServiceFilter(ctx, -1));
+    EXPECT_EQ(nullptr, celix_bundleContext_getTrackedServiceFilter(ctx, 1 
/*non existing*/));
+
+    EXPECT_FALSE(celix_bundleContext_isValidTrackerId(ctx, -1));
+}
+
+TEST_F(CelixBundleContextServicesTestSuite, IsValidTrackerIdTest) {
+    long trkId = celix_bundleContext_trackServices(ctx, "test", nullptr, 
nullptr, nullptr);
+    EXPECT_TRUE(celix_bundleContext_isValidTrackerId(ctx, trkId));
+    celix_bundleContext_stopTracker(ctx, trkId);
+    EXPECT_FALSE(celix_bundleContext_isValidTrackerId(ctx, trkId));
+}
+
+TEST_F(CelixBundleContextServicesTestSuite, UseTrackedServiceTest) {
+    // Given 3 foo services with different service properties
+    celix_properties_t* props1 = celix_properties_create();
+    celix_properties_set(props1, "key", "1");
+    long svcId1 = celix_bundleContext_registerService(ctx, (void*)0x42, 
"test", props1);
+    celix_auto(celix_service_registration_guard_t) guard1 = 
celix_serviceRegistrationGuard_init(ctx, svcId1);
+
+    celix_properties_t* props2 = celix_properties_create();
+    celix_properties_set(props2, "key", "2");
+    long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x42, 
"test", props2);
+    celix_auto(celix_service_registration_guard_t) guard2 = 
celix_serviceRegistrationGuard_init(ctx, svcId2);
+
+    celix_properties_t* props3 = celix_properties_create();
+    celix_properties_set(props3, "key", "3");
+    long svcId3 = celix_bundleContext_registerService(ctx, (void*)0x42, 
"test", props3);
+    celix_auto(celix_service_registration_guard_t) guard3 = 
celix_serviceRegistrationGuard_init(ctx, svcId3);
+
+    // When tracking services for a service name
+    long trkId = celix_bundleContext_trackServices(ctx, "test", nullptr, 
nullptr, nullptr);
+    celix_auto(celix_tracker_guard_t) trkGuard = celix_trackerGuard_init(ctx, 
trkId);
+
+    // Then the useTrackedService function should be called for each service
+    struct use_data {
+        long bndId{0};
+        int count{0}; //note atomic not needed because the use function is 
called in the same thread.
+    };
+    use_data data{};
+    data.bndId = celix_bundleContext_getBundleId(ctx);
+    celix_tracked_service_use_options_t useOpts{};
+    useOpts.callbackHandle = (void*)&data;
+    useOpts.use = [](void* handle, void* svc) {
+        EXPECT_EQ((void*)0x42, svc);
+        auto *d = static_cast<use_data*>(handle);
+        d->count++;
+    };
+    useOpts.useWithProperties = [](void* handle, void* svc, const 
celix_properties_t* props) {
+        EXPECT_EQ((void*)0x42, svc);
+        auto* val = celix_properties_get(props, "key", nullptr);
+        EXPECT_TRUE(val != nullptr);
+        auto *d = static_cast<use_data*>(handle);
+        d->count++;
+    };
+    useOpts.useWithOwner = [](void* handle, void* svc, const 
celix_properties_t* props, const celix_bundle_t* owner) {
+        EXPECT_EQ((void*)0x42, svc);
+        auto* val = celix_properties_get(props, "key", nullptr);
+        EXPECT_TRUE(val != nullptr);
+        auto *d = static_cast<use_data*>(handle);
+        d->count++;
+        EXPECT_EQ(celix_bundle_getId(owner), d->bndId);
+    };
+    auto count = celix_bundleContext_useTrackedServicesWithOptions(ctx, trkId, 
&useOpts);
+    EXPECT_EQ(3, count);
+    EXPECT_EQ(9, data.count); // 3x use, 3x useWithProperties, 3x useWithOwner
+
+    // And the useTrackedServiceWithOptions function should be called a single 
time
+    data.count = 0;
+    bool called = celix_bundleContext_useTrackedServiceWithOptions(ctx, trkId, 
&useOpts);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(3, data.count); // 1x use, 1x useWithProperties, 1x useWithOwner
+
+    // And the useTrackedServices function should be called 3 times
+    data.count = 0;
+    count = celix_bundleContext_useTrackedServices(ctx, trkId, 
useOpts.callbackHandle, useOpts.use);
+    EXPECT_EQ(3, count);
+    EXPECT_EQ(3, data.count); // 3x use
+
+    // And the useTrackedService function should be called a single time
+    data.count = 0;
+    called = celix_bundleContext_useTrackedService(ctx, trkId, 
useOpts.callbackHandle, useOpts.use);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(1, data.count); // 1x use
+
+    // When tracking a service with a filter
+    celix_service_tracking_options_t opts{};
+    opts.filter.serviceName = "test";
+    opts.filter.filter = "(key=1)";
+    long trkId2 = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    celix_auto(celix_tracker_guard_t) trkGuard2 = celix_trackerGuard_init(ctx, 
trkId2);
+
+    // Then the useTrackedServiceWithOption function should be called for the 
service with the matching filter
+    useOpts.use = nullptr;
+    useOpts.useWithOwner = nullptr;
+    useOpts.useWithProperties = [](void* handle, void* svc, const 
celix_properties_t* props) {
+        EXPECT_EQ((void*)0x42, svc);
+        auto* val = celix_properties_get(props, "key", nullptr);
+        EXPECT_TRUE(val != nullptr);
+        EXPECT_STREQ("1", val);
+        auto *d = static_cast<use_data*>(handle);
+        d->count++;
+    };
+    data.count = 0;
+    called = celix_bundleContext_useTrackedServiceWithOptions(ctx, trkId2, 
&useOpts);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(1, data.count); // 1x useWithProperties
+
+    // And the useTrackedServicesWithOption function should be called a single 
time
+    data.count = 0;
+    count = celix_bundleContext_useTrackedServicesWithOptions(ctx, trkId2, 
&useOpts);
+    EXPECT_EQ(1, count);
+    EXPECT_EQ(1, data.count); // 1x useWithProperties
+}
+
+TEST_F(CelixBundleContextServicesTestSuite, GetTrackedServicesInfoTest) {
+    //When a service tracker for a specific service name and with a filter
+    celix_service_tracking_options_t opts{};
+    opts.filter.serviceName = "test";
+    opts.filter.filter = "(key=1)";
+    long trkId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    celix_auto(celix_tracker_guard_t) trkGuard = celix_trackerGuard_init(ctx, 
trkId);
+
+    // And a service is registered with a matching service name and filter
+    celix_properties_t* props = celix_properties_create();
+    celix_properties_set(props, "key", "1");
+    long svcId = celix_bundleContext_registerService(ctx, (void*)0x42, "test", 
props);
+    celix_auto(celix_service_registration_guard_t) svcGuard = 
celix_serviceRegistrationGuard_init(ctx, svcId);
+
+    // Then the tracked services info should be available
+    EXPECT_EQ(celix_bundleContext_getTrackedServiceCount(ctx, trkId), 1);
+    EXPECT_STREQ(celix_bundleContext_getTrackedServiceName(ctx, trkId), 
"test");
+    EXPECT_STREQ(celix_bundleContext_getTrackedServiceFilter(ctx, trkId), 
"(&(objectClass=test)(key=1))");
+
+
+    // When a tracker for all services is created
+    long trkId2 = celix_bundleContext_trackServices(ctx, nullptr, nullptr, 
nullptr, nullptr);
+    celix_auto(celix_tracker_guard_t) trkGuard2 = celix_trackerGuard_init(ctx, 
trkId2);
+
+    // Then the tracked services info should be available
+    EXPECT_EQ(celix_bundleContext_getTrackedServiceCount(ctx, trkId2), 1);
+    EXPECT_STREQ(celix_bundleContext_getTrackedServiceName(ctx, trkId2), "*");
+    EXPECT_TRUE(strstr(celix_bundleContext_getTrackedServiceFilter(ctx, 
trkId2), "(objectClass=*)") != nullptr);
+}
diff --git a/libs/framework/include/celix_bundle_context.h 
b/libs/framework/include/celix_bundle_context.h
index d582fabd..e18992f5 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -392,6 +392,197 @@ CELIX_FRAMEWORK_EXPORT long 
celix_bundleContext_findServiceWithOptions(celix_bun
  */
 CELIX_FRAMEWORK_EXPORT celix_array_list_t* 
celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const 
celix_service_filter_options_t *opts);
 
+/**
+ * @brief Use the service with the provided service id using the provided 
callback. The Celix framework will ensure that
+ * the targeted service cannot be removed during the callback.
+ *
+ * The svc is should only be considered valid during the callback.
+ * If no service is found, the callback will not be invoked and this function 
will return false immediately.
+ *
+ * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
+ * stack.
+ *
+ * @param ctx The bundle context
+ * @param serviceId the service id.
+ * @param serviceName the service name of the service. Should match with the 
registered service name of the provided service id (sanity check)
+ * @param callbackHandle The data pointer, which will be used in the callbacks
+ * @param use The callback, which will be called when service is retrieved.
+ * @param bool returns true if a service was found.
+ */
+CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithId(
+    celix_bundle_context_t *ctx,
+    long serviceId,
+    const char* serviceName /*sanity check*/,
+    void *callbackHandle,
+    void (*use)(void *handle, void* svc)
+);
+
+/**
+ * @brief Use the highest ranking service with the provided service name using 
the provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
+ *
+ * The svc is should only be considered valid during the callback.
+ * If no service is found, the callback will not be invoked and this function 
will return false immediately.
+ *
+ * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
+ * stack.
+ *
+ * @param   ctx The bundle context
+ * @param   serviceName the required service name.
+ * @param   callbackHandle The data pointer, which will be used in the 
callbacks
+ * @param   use The callback, which will be called when service is retrieved.
+ * @return  True if a service was found.
+ */
+CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService(
+    celix_bundle_context_t *ctx,
+    const char* serviceName,
+    void *callbackHandle,
+    void (*use)(void *handle, void *svc)
+);
+
+/**
+ * @brief Use the services with the provided service name using the provided 
callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
+ *
+ * The svc is should only be considered valid during the callback.
+ * If no service is found, the callback will not be invoked and this function 
will return 0 immediately.
+ *
+ * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
+ * stack.
+ *
+ * @param   ctx The bundle context
+ * @param   serviceName the required service name.
+ * @param   callbackHandle The data pointer, which will be used in the 
callbacks
+ * @param   use The callback, which will be called for every service found.
+ * @return  The number of services found and called
+ */
+CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServices(
+    celix_bundle_context_t *ctx,
+    const char* serviceName,
+    void *callbackHandle,
+    void (*use)(void *handle, void *svc)
+);
+
+/**
+ * @brief Service Use Options used to fine tune which services to use and 
which callbacks to use.
+ *
+ * If multiple use callbacks are set, all set callbacks will be called for 
every service found.
+ */
+typedef struct celix_service_use_options {
+    /**
+     * @brief The service filter options, used to setup the filter for the 
service to track.
+     */
+    celix_service_filter_options_t filter CELIX_OPTS_INIT;
+
+    /**
+     * @brief An optional timeout (in seconds), if > 0 the use service call 
will block until the timeout is expired or
+     * when at least one service is found. Note that it will be ignored when 
use service on the event loop.
+     * Default (0)
+     *
+     * Only applicable when using the celix_bundleContext_useService or
+     * celix_bundleContext_useServiceWithOptions (use single service calls).
+     */
+    double waitTimeoutInSeconds CELIX_OPTS_INIT;
+
+    /**
+     * @brief The optional callback pointer used in all the provided callback 
function (use, useWithProperties, and
+     * useWithOwner).
+     */
+    void* callbackHandle CELIX_OPTS_INIT;
+
+    /**
+     * @brief The optional use callback will be called when for every services 
found conform the service filter options
+     * - in case of findServices - or only for the highest ranking service 
found - in case of findService -.
+     *
+     * @param handle The callbackHandle pointer as provided in the service 
tracker options.
+     * @param svc The service pointer of the highest ranking service.
+     */
+    void (*use)(void* handle, void* svc) CELIX_OPTS_INIT;
+
+    /**
+     * @brief The optional useWithProperties callback is handled as the use 
callback, but with the addition that the
+     * service properties will also be provided to the callback.
+     */
+    void (*useWithProperties)(void* handle, void* svc, const 
celix_properties_t* props) CELIX_OPTS_INIT;
+
+    /**
+     * @brief The optional useWithOwner callback is handled as the yse 
callback, but with the addition that the service
+     * properties and the bundle owning the service will also be provided to 
the callback.
+     */
+    void (*useWithOwner)(void* handle, void* svc, const celix_properties_t* 
props, const celix_bundle_t* svcOwner)
+        CELIX_OPTS_INIT;
+    /**
+     * @brief Call the provided callbacks from the caller thread directly if 
set, otherwise the callbacks will be called
+     * from the Celix event loop (most likely indirectly). Note that using 
blocking service in the Celix event loop is
+     * generally a bad idea, which should be avoided if possible.
+     */
+#define CELIX_SERVICE_USE_DIRECT (1)
+    /**
+     * @brief Whether "service on demand" pattern is supported when 
CELIX_SERVICE_USE_DIRECT is set.
+     * Note that it has no effect in indirect mode, in which case "service on 
demand" is supported.
+     */
+#define CELIX_SERVICE_USE_SOD (2)
+    int flags CELIX_OPTS_INIT;
+} celix_service_use_options_t;
+
+#ifndef __cplusplus
+/*!
+ * @brief C Macro to create a empty celix_service_use_options_t type.
+ */
+#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \
+    .filter.versionRange = NULL, \
+    .filter.filter = NULL, \
+    .waitTimeoutInSeconds = 0.0F, \
+    .callbackHandle = NULL, \
+    .use = NULL, \
+    .useWithProperties = NULL, \
+    .useWithOwner = NULL, \
+    .flags=0}
+#endif
+
+/**
+ * @brief Use the highest ranking service satisfying the provided service 
filter options using the provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
+ *
+ * The svc is should only be considered valid during the callback.
+ * If no service is found the callback will not be invoked. In such cases, if 
a non-zero waitTimeoutInSeconds is specified in opts,
+ * this function will block until the timeout is expired or when at least one 
service is found, otherwise it will return false immediately.
+ *
+ * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
+ * stack.
+ *
+ * @param   ctx The bundle context.
+ * @param   opts The required options. Note that the serviceName is required.
+ * @return  True if a service was found.
+ */
+CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithOptions(
+    celix_bundle_context_t *ctx,
+    const celix_service_use_options_t *opts);
+
+
+/**
+ * @brief Use the services with the provided service filter options using the 
provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
+ *
+ * The svc is should only be considered valid during the callback.
+ * If no service is found, the callback will not be invoked and this function 
will return 0 immediately.
+ * Note that waitTimeoutInSeconds in opts has no effect.
+ *
+ * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
+ * stack.
+ *
+ * @param   ctx The bundle context.
+ * @param   opts The required options. Note that the serviceName is required.
+ * @return  The number of services found and called
+ */
+CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServicesWithOptions(
+    celix_bundle_context_t *ctx,
+    const celix_service_use_options_t *opts);
+
 /**
  * @brief Track the highest ranking service with the provided serviceName.
  *
@@ -615,7 +806,6 @@ CELIX_FRAMEWORK_EXPORT long 
celix_bundleContext_trackServicesWithOptionsAsync(ce
  * The tracker options are only using during this call and can safely be 
freed/reused after this call returns.
  * Note: Please use the celix_bundleContext_registerServiceFactoryAsync 
instead.
  *
- *
  * @param ctx The bundle context.
  * @param opts The pointer to the tracker options.
  * @return the tracker id (>=0) or < 0 if unsuccessful.
@@ -623,143 +813,71 @@ CELIX_FRAMEWORK_EXPORT long 
celix_bundleContext_trackServicesWithOptionsAsync(ce
 CELIX_FRAMEWORK_EXPORT long 
celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const 
celix_service_tracking_options_t *opts);
 
 /**
- * @brief Stop the tracker with the provided track id.
- *
- * Could be a service tracker, bundle tracker or service tracker tracker.
- * Only works for the trackers owned by the bundle of the bundle context.
+ * @brief Use the highest ranking service, tracked by the provided tracker id, 
using the provided callback.
  *
- * The service tracker will be destroyed async on the Celix event loop thread. 
This means that the function can return
- * before the tracker is destroyed.
+ * If an service is found the use callback will be called on the thread that 
called this function and when function
+ * returns the callback is finished.
  *
- * if the doneCallback is not NULL, this will be called when the destruction 
of the service tracker is done.
- * (will be called on the event loop thread).
+ * An tracker id < 0 will be silently ignored.
+ * An invalid (non existing) tracker id >= 0 will be logged and the function 
will return false.
  *
- * Will log a error if the provided tracker id is unknown. Will silently 
ignore trackerId < 0.
+ * @param[in] ctx The bundle context.
+ * @param[in] trackerId The tracker id.
+ * @param[in] callbackHandle The data pointer, which will be used in the 
callbacks.
+ * @param[in] use The callback, which will be called when service is retrieved.
+ * @return True if a service was found and the use callback was called.
  */
-CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTrackerAsync(
+CELIX_FRAMEWORK_EXPORT
+bool celix_bundleContext_useTrackedService(
         celix_bundle_context_t *ctx,
         long trackerId,
-        void *doneCallbackData,
-        void (*doneCallback)(void* doneCallbackData));
-
-/**
- * @brief Wait for (async) creation of tracker
- */
-CELIX_FRAMEWORK_EXPORT void 
celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t *ctx, long 
trackerId);
-
-/**
- * @brief Wait for (async) stopping of tracking.
- */
-CELIX_FRAMEWORK_EXPORT void 
celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t *ctx, long 
trackerId);
-
-/**
- * @brief Stop the tracker with the provided track id.
- *
- * Could be a service tracker, bundle tracker or service tracker tracker.
- * Only works for the trackers owned by the bundle of the bundle context.
- * Note: Please use the celix_bundleContext_registerServiceFactoryAsync 
instead.
- *
- * Will log a error if the provided tracker id is unknown. Will silently 
ignore trackerId < 0.
- */
-CELIX_FRAMEWORK_EXPORT void 
celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId);
-
-/**
- * @brief Use the service with the provided service id using the provided 
callback. The Celix framework will ensure that
- * the targeted service cannot be removed during the callback.
- *
- * The svc is should only be considered valid during the callback.
- * If no service is found, the callback will not be invoked and this function 
will return false immediately.
- *
- * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
- * stack.
- *
- * @param ctx The bundle context
- * @param serviceId the service id.
- * @param serviceName the service name of the service. Should match with the 
registered service name of the provided service id (sanity check)
- * @param callbackHandle The data pointer, which will be used in the callbacks
- * @param use The callback, which will be called when service is retrieved.
- * @param bool returns true if a service was found.
- */
-CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithId(
-        celix_bundle_context_t *ctx,
-        long serviceId,
-        const char* serviceName /*sanity check*/,
         void *callbackHandle,
         void (*use)(void *handle, void* svc)
 );
 
 /**
- * @brief Use the highest ranking service with the provided service name using 
the provided callback.
+ * @brief Use the services, tracked by the provided tracker id, using the 
provided callback.
  *
- * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
- *
- * The svc is should only be considered valid during the callback.
- * If no service is found, the callback will not be invoked and this function 
will return false immediately.
+ * If 1 or more services is found the use callback will be called for every 
service found on the thread that called this
+ * function and when function returns the callbacks are finished.
  *
- * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
- * stack.
+ * An tracker id < 0 will be silently ignored.
+ * An invalid (non existing) tracker id >= 0 will be logged and the function 
will return 0.
  *
- * @param   ctx The bundle context
- * @param   serviceName the required service name.
- * @param   callbackHandle The data pointer, which will be used in the 
callbacks
- * @param   use The callback, which will be called when service is retrieved.
- * @return  True if a service was found.
- */
-CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService(
-        celix_bundle_context_t *ctx,
-        const char* serviceName,
-        void *callbackHandle,
-        void (*use)(void *handle, void *svc)
-);
-
-/**
- * @brief Use the services with the provided service name using the provided 
callback.
- *
- * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
- *
- * The svc is should only be considered valid during the callback.
- * If no service is found, the callback will not be invoked and this function 
will return 0 immediately.
- *
- * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
- * stack.
- *
- * @param   ctx The bundle context
- * @param   serviceName the required service name.
- * @param   callbackHandle The data pointer, which will be used in the 
callbacks
- * @param   use The callback, which will be called for every service found.
- * @return  The number of services found and called
+ * @param[in] ctx The bundle context.
+ * @param[in] trackerId The tracker id.
+ * @param[in] callbackHandle The data pointer, which will be used in the 
callbacks.
+ * @param[in] use The callback, which will be called for every service found.
+ * @return The number of services found and therefore the number of times the 
use callback was called.
  */
-CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServices(
-        celix_bundle_context_t *ctx,
-        const char* serviceName,
-        void *callbackHandle,
-        void (*use)(void *handle, void *svc)
-);
+CELIX_FRAMEWORK_EXPORT
+size_t celix_bundleContext_useTrackedServices(celix_bundle_context_t* ctx,
+                                              long trackerId,
+                                              void* callbackHandle,
+                                              void (*use)(void* handle, void* 
svc));
 
 /**
- * @brief Service Use Options used to fine tune which services to use and 
which callbacks to use.
+ * @brief Use tracked service options used to configure which use callback to 
use on the tracked services.
+ * If multiple use callbacks are set, all set callbacks will be called for 
every service found.
  */
-typedef struct celix_service_use_options {
-    /**
-     * @brief The service filter options, used to setup the filter for the 
service to track.
-     */
-    celix_service_filter_options_t filter CELIX_OPTS_INIT;
-
+typedef struct celix_tracked_service_use_options {
     /**
-     * @brief An optional timeout (in seconds), if > 0 the use service call 
will block until the timeout is expired or
-     * when at least one service is found. Note that it will be ignored when 
use service on the event loop.
+     * @brief An optional timeout (in seconds), if > 0 the use tracked 
service(s) call will block until the timeout is
+     * expired or when at least one service is found. Note that it will be 
ignored when use service on the event loop.
      * Default (0)
+     *
+     * Only applicable when using the celix_bundleContext_useTrackedService or
+     * celix_bundleContext_useTrackedServiceWithOptions (use single service 
calls).
      */
-     double waitTimeoutInSeconds CELIX_OPTS_INIT;
+    double waitTimeoutInSeconds CELIX_OPTS_INIT;
 
     /**
-     * @brief The optional callback pointer used in all the provided callback 
function (set, add, remove, setWithProperties, etc).
+     * @brief The optional callback pointer used in all the provided callback 
function (use, useWithProperties and useWithOwner).
      */
     void *callbackHandle CELIX_OPTS_INIT;
 
     /**
-     * @brief The optional use callback will be called when for every services 
found conform the service filter options
-     * - in case of findServices - or only for the highest ranking service 
found - in case of findService -.
+     * @brief The optional use callback will be called when for every service 
tracked.
      *
      * @param handle The callbackHandle pointer as provided in the service 
tracker options.
      * @param svc The service pointer of the highest ranking service.
@@ -767,84 +885,197 @@ typedef struct celix_service_use_options {
     void (*use)(void *handle, void *svc) CELIX_OPTS_INIT;
 
     /**
-     * @brief The optional useWithProperties callback is handled as the use 
callback, but with the addition that the service properties
-     * will also be provided to the callback.
+     * @brief The optional useWithProperties callback will be called when for 
every service tracked and the
+     * service properties will also be provided to the callback.
      */
     void (*useWithProperties)(void *handle, void *svc, const 
celix_properties_t *props) CELIX_OPTS_INIT;
 
     /**
-     * @brief The optional useWithOwner callback is handled as the yse 
callback, but with the addition that the service properties
-     * and the bundle owning the service will also be provided to the callback.
+     * @brief The optional useWithOwner callback will be called when for every 
service tracked and the
+     * service properties and the bundle owning the service will also be 
provided to the callback.
      */
     void (*useWithOwner)(void *handle, void *svc, const celix_properties_t 
*props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT;
-    /**
-     * @brief Call the provided callbacks from the caller thread directly if 
set, otherwise the callbacks will be called from the Celix event loop (most 
likely indirectly).
-     * Note that using blocking service in the Celix event loop is generally a 
bad idea, which should be avoided if possible.
-     */
-#define CELIX_SERVICE_USE_DIRECT              (1)
-    /**
-     * @brief Whether "service on demand" pattern is supported when 
CELIX_SERVICE_USE_DIRECT is set.
-     * Note that it has no effect in indirect mode, in which case "service on 
demand" is supported.
-     */
-#define CELIX_SERVICE_USE_SOD                 (2)
-    int flags CELIX_OPTS_INIT;
-} celix_service_use_options_t;
+} celix_tracked_service_use_options_t;
 
 #ifndef __cplusplus
 /*!
- * @brief C Macro to create a empty celix_service_use_options_t type.
+ * @brief C Macro to create a empty celix_tracked_service_use_options_t type.
  */
-#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \
-    .filter.versionRange = NULL, \
-    .filter.filter = NULL, \
-    .waitTimeoutInSeconds = 0.0F, \
-    .callbackHandle = NULL, \
-    .use = NULL, \
-    .useWithProperties = NULL, \
-    .useWithOwner = NULL, \
-    .flags=0}
+#define CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS                                
                                        \
+    {                                                                          
                                        \
+        .waitTimeoutInSeconds = 0.0F, .callbackHandle = NULL, .use = NULL, 
.useWithProperties = NULL,                  \
+        .useWithOwner = NULL                                                   
                                        \
+    }
 #endif
 
 /**
- * @brief Use the highest ranking service satisfying the provided service 
filter options using the provided callback.
+ * @brief Use the highest ranking service, tracked by the provided tracker id, 
using the callbacks in the provided
+ * options.
  *
- * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
+ * If an service is found the use callbacks will be called on the thread that 
called this function and when function
+ * returns the callbacks are finished.
  *
- * The svc is should only be considered valid during the callback.
- * If no service is found the callback will not be invoked. In such cases, if 
a non-zero waitTimeoutInSeconds is specified in opts,
- * this function will block until the timeout is expired or when at least one 
service is found, otherwise it will return false immediately.
+ * An tracker id < 0 will be silently ignored.
+ * An invalid (non existing) tracker id >= 0 will be logged and the function 
will return false.
  *
- * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
- * stack.
+ * @note the field USE_DIRECT in the provided options has no effect with this 
function.
  *
- * @param   ctx The bundle context.
- * @param   opts The required options. Note that the serviceName is required.
- * @return  True if a service was found.
+ * @param[in] ctx The bundle context.
+ * @param[in] trackerId The tracker id.
+ * @param[in] callbackHandle The data pointer, which will be used in the 
callbacks.
+ * @param[in] opts The service use options.
+ * @return True if a service was found and the use callbacks where called.
  */
-CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithOptions(
-        celix_bundle_context_t *ctx,
-        const celix_service_use_options_t *opts);
+CELIX_FRAMEWORK_EXPORT
+bool celix_bundleContext_useTrackedServiceWithOptions(celix_bundle_context_t* 
ctx,
+                                                      long trackerId,
+                                                      const 
celix_tracked_service_use_options_t* opts);
 
+/**
+ * @brief Use the services, tracked by the provided tracker id, using the 
callbacks in the provided options.
+ *
+ * If 1 or more services is found the use callbacks will be called for every 
service found on the thread that called
+ * this function and when function returns the callbacks are finished.
+ *
+ * An tracker id < 0 will be silently ignored.
+ * An invalid (non existing) tracker id >= 0 will be logged and the function 
will return 0.
+ *
+ * @note the field USE_DIRECT in the provided options has no effect with this 
function.
+ *
+ * @param[in] ctx The bundle context.
+ * @param[in] trackerId The tracker id.
+ * @param[in] callbackHandle The data pointer, which will be used in the 
callbacks.
+ * @param[in] opts The service use options.
+ * @return The number of services found and therefore the number of times the 
callbacks in the provided options where
+ * called.
+ */
+CELIX_FRAMEWORK_EXPORT
+size_t 
celix_bundleContext_useTrackedServicesWithOptions(celix_bundle_context_t* ctx,
+                                                         long trackerId,
+                                                         const 
celix_tracked_service_use_options_t* opts);
 
 /**
- * @brief Use the services with the provided service filter options using the 
provided callback.
+ * @brief Get the number of tracked services for the provided tracker id.
  *
- * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
+ * Silently ignore tracker ids < 0 and invalid tracker ids.
  *
- * The svc is should only be considered valid during the callback.
- * If no service is found, the callback will not be invoked and this function 
will return 0 immediately.
- * Note that waitTimeoutInSeconds in opts has no effect.
+ * @param[in] ctx The bundle context.
+ * @param[in] trackerId The tracker id.
+ * @return The number of tracked services or 0 if the tracker id is unknown or 
< 0.
+ */
+CELIX_FRAMEWORK_EXPORT
+size_t celix_bundleContext_getTrackedServiceCount(celix_bundle_context_t *ctx, 
long trackerId);
+
+/**
+ * @brief Get the service name of the tracked services for the provided 
tracker id.
  *
- * This function will block until the callback is finished. As result it is 
possible to provide callback data from the
- * stack.
+ * Silently ignore tracker ids < 0 and invalid tracker ids.
  *
- * @param   ctx The bundle context.
- * @param   opts The required options. Note that the serviceName is required.
- * @return  The number of services found and called
+ * @param ctx The bundle context.
+ * @param trackerId The tracker id.
+ * @return The service name of the tracked services or NULL if the tracker id 
is unknown or < 0.
  */
-CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServicesWithOptions(
+CELIX_FRAMEWORK_EXPORT
+const char* celix_bundleContext_getTrackedServiceName(celix_bundle_context_t 
*ctx, long trackerId);
+
+/**
+ * @brief Get the service filter of the tracked services for the provided 
tracker id.
+ *
+ * The returned filter is the combination of the service name and the filter 
from the provided service filter options.
+ * For example serviceName="foo" and filter="(location=middle)" will result in 
a filter of
+ * "(&(objectClass=foo)(location=middle))"
+ *
+ * Silently ignore tracker ids < 0 and invalid tracker ids.
+ *
+ * @param ctx The bundle context.
+ * @param trackerId The tracker id.
+ * @return The service filter of the tracked services or NULL if the tracker 
id is unknown or < 0.
+ */
+CELIX_FRAMEWORK_EXPORT
+const char* 
celix_bundleContext_getTrackedServiceFilter(celix_bundle_context_t* ctx, long 
trackerId);
+
+/**
+ * @brief Returns true if the provided tracker id is a tracker id for an 
existing tracker for the provided bundle
+ * context.
+ * @param ctx The bundle context.
+ * @param trackerId The tracker id.
+ * @return True if the tracker id is valid.
+ */
+CELIX_FRAMEWORK_EXPORT
+bool celix_bundleContext_isValidTrackerId(celix_bundle_context_t* ctx, long 
trackerId);
+
+/**
+ * @brief Stop the tracker with the provided track id.
+ *
+ * Could be a service tracker, bundle tracker or service tracker tracker.
+ * Only works for the trackers owned by the bundle of the bundle context.
+ *
+ * The service tracker will be destroyed async on the Celix event loop thread. 
This means that the function can return
+ * before the tracker is destroyed.
+ *
+ * if the doneCallback is not NULL, this will be called when the destruction 
of the service tracker is done.
+ * (will be called on the event loop thread).
+ *
+ * Will log a error if the provided tracker id is unknown. Will silently 
ignore trackerId < 0.
+ */
+CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTrackerAsync(
         celix_bundle_context_t *ctx,
-        const celix_service_use_options_t *opts);
+        long trackerId,
+        void *doneCallbackData,
+        void (*doneCallback)(void* doneCallbackData));
+
+/**
+ * @brief Wait for (async) creation of tracker
+ */
+CELIX_FRAMEWORK_EXPORT void 
celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t *ctx, long 
trackerId);
+
+/**
+ * @brief Wait for (async) stopping of tracking.
+ */
+CELIX_FRAMEWORK_EXPORT void 
celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t *ctx, long 
trackerId);
+
+/**
+ * @brief Stop the tracker with the provided track id.
+ *
+ * Could be a service tracker, bundle tracker or service tracker tracker.
+ * Only works for the trackers owned by the bundle of the bundle context.
+ * Note: Please use the celix_bundleContext_registerServiceFactoryAsync 
instead.
+ *
+ * Will log a error if the provided tracker id is unknown. Will silently 
ignore trackerId < 0.
+ */
+CELIX_FRAMEWORK_EXPORT void 
celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId);
+
+/**
+ * @brief Tracker guard.
+ */
+typedef struct celix_tracker_guard {
+    celix_bundle_context_t* ctx;
+    long trackerId;
+} celix_tracker_guard_t;
+
+/**
+ * @brief Initialize a scope guard for an existing bundle, service or meta 
tracker.
+ * @param [in] ctx The bundle context associated with the service registration.
+ * @param [in] trackerId The tracker id.
+ * @return An initialized service registration guard.
+ */
+static CELIX_UNUSED inline celix_tracker_guard_t
+celix_trackerGuard_init(celix_bundle_context_t* ctx, long trackerId) {
+    return (celix_tracker_guard_t) { .ctx = ctx, .trackerId = trackerId };
+}
+
+/**
+ * @brief De-initialize a tracker guard.
+ * Will stop the tracker if the tracker id is >= 0.
+ * @param [in] trackerGuard A tracker guard
+ */
+static CELIX_UNUSED inline void 
celix_trackerGuard_deinit(celix_tracker_guard_t* trackerGuard) {
+    if (trackerGuard->trackerId >= 0) {
+        celix_bundleContext_stopTracker(trackerGuard->ctx, 
trackerGuard->trackerId);
+    }
+}
+
+CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_tracker_guard_t, 
celix_trackerGuard_deinit)
 
 /**
  * @brief List the installed and started bundle ids.
diff --git a/libs/framework/include_deprecated/service_tracker.h 
b/libs/framework/include_deprecated/service_tracker.h
index 5f75c8ab..cba45a09 100644
--- a/libs/framework/include_deprecated/service_tracker.h
+++ b/libs/framework/include_deprecated/service_tracker.h
@@ -66,7 +66,7 @@ CELIX_FRAMEWORK_DEPRECATED_EXPORT size_t 
serviceTracker_nrOfTrackedServices(serv
 
 
/**********************************************************************************************************************
  
**********************************************************************************************************************
- * Updated API
+ * Updated API. Note API is still deprecated for external usage, the api will 
become private in the future.
  
**********************************************************************************************************************
  
**********************************************************************************************************************/
 
@@ -140,6 +140,21 @@ CELIX_FRAMEWORK_DEPRECATED_EXPORT size_t 
celix_serviceTracker_useServices(
         void (*useWithOwner)(void *handle, void *svc, const celix_properties_t 
*props, const celix_bundle_t *owner)
 );
 
+/**
+ * @brief Get the number of tracked services.
+ */
+CELIX_FRAMEWORK_DEPRECATED_EXPORT size_t 
celix_serviceTracker_getTrackedServiceCount(celix_service_tracker_t *tracker);
+
+/**
+ * @brief Get the tracker service name.
+ */
+CELIX_FRAMEWORK_DEPRECATED_EXPORT const char* 
celix_serviceTracker_getTrackedServiceName(celix_service_tracker_t *tracker);
+
+/**
+ * @brief Get the tracker filter.
+ */
+CELIX_FRAMEWORK_DEPRECATED_EXPORT const char* 
celix_serviceTracker_getTrackedServiceFilter(celix_service_tracker_t *tracker);
+
 
 #ifdef __cplusplus
 }
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index 6a687696..8eaf7112 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -583,9 +583,8 @@ void 
celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list) {
 celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t 
*bnd) {
     celix_array_list_t* result = celix_arrayList_create();
     celixThreadMutex_lock(&bnd->context->mutex);
-    hash_map_iterator_t iter = 
hashMapIterator_construct(bnd->context->serviceTrackers);
-    while (hashMapIterator_hasNext(&iter)) {
-        celix_bundle_context_service_tracker_entry_t *trkEntry = 
hashMapIterator_nextValue(&iter);
+    CELIX_LONG_HASH_MAP_ITERATE(bnd->context->serviceTrackers, iter) {
+        celix_bundle_context_service_tracker_entry_t *trkEntry = 
iter.value.ptrValue;
         if (trkEntry->tracker != NULL) {
             celix_bundle_service_tracker_list_entry_t *entry = calloc(1, 
sizeof(*entry));
             entry->filter = celix_utils_strdup(trkEntry->tracker->filter);
diff --git a/libs/framework/src/bundle_context.c 
b/libs/framework/src/bundle_context.c
index 0f0bc344..ccc49ddf 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -68,10 +68,10 @@ celix_status_t bundleContext_create(framework_pt framework, 
celix_framework_logg
             celixThreadMutex_create(&context->mutex, NULL);
 
             context->svcRegistrations = celix_arrayList_create();
-            context->bundleTrackers = hashMap_create(NULL,NULL,NULL,NULL);
-            context->serviceTrackers = hashMap_create(NULL,NULL,NULL,NULL);
-            context->metaTrackers =  hashMap_create(NULL,NULL,NULL,NULL);
-            context->stoppingTrackerEventIds = 
hashMap_create(NULL,NULL,NULL,NULL);
+            context->bundleTrackers = celix_longHashMap_create();
+            context->serviceTrackers = celix_longHashMap_create();
+            context->metaTrackers =  celix_longHashMap_create();
+            context->stoppingTrackerEventIds = celix_longHashMap_create();
             context->nextTrackerId = 1L;
 
             *bundle_context = context;
@@ -84,20 +84,19 @@ celix_status_t bundleContext_create(framework_pt framework, 
celix_framework_logg
 }
 
 celix_status_t bundleContext_destroy(bundle_context_pt context) {
-       celix_status_t status = CELIX_SUCCESS;
-
-    if(context == NULL) {
+    if (context == NULL) {
         return CELIX_ILLEGAL_ARGUMENT;
     }
-    assert(hashMap_size(context->bundleTrackers) == 0);
-    hashMap_destroy(context->bundleTrackers, false, false);
-    assert(hashMap_size(context->serviceTrackers) == 0);
-    hashMap_destroy(context->serviceTrackers, false, false);
-    assert(hashMap_size(context->metaTrackers) == 0);
-    hashMap_destroy(context->metaTrackers, false, false);
+
+    assert(celix_longHashMap_size(context->bundleTrackers) == 0);
+    celix_longHashMap_destroy(context->bundleTrackers);
+    assert(celix_longHashMap_size(context->serviceTrackers) == 0);
+    celix_longHashMap_destroy(context->serviceTrackers);
+    assert(celix_longHashMap_size(context->metaTrackers) == 0);
+    celix_longHashMap_destroy(context->metaTrackers);
     assert(celix_arrayList_size(context->svcRegistrations) == 0);
     celix_arrayList_destroy(context->svcRegistrations);
-    hashMap_destroy(context->stoppingTrackerEventIds, false, false);
+    celix_longHashMap_destroy(context->stoppingTrackerEventIds);
 
     celixThreadMutex_destroy(&context->mutex);
 
@@ -108,7 +107,7 @@ celix_status_t bundleContext_destroy(bundle_context_pt 
context) {
     }
 
     free(context);
-       return status;
+    return CELIX_SUCCESS;
 }
 
 void celix_bundleContext_cleanup(celix_bundle_context_t* ctx) {
@@ -593,7 +592,7 @@ static long 
celix_bundleContext_trackBundlesWithOptionsInternal(
 
     celixThreadMutex_lock(&ctx->mutex);
     entry->trackerId = ctx->nextTrackerId++;
-    hashMap_put(ctx->bundleTrackers, (void*)(entry->trackerId), entry);
+    celix_longHashMap_put(ctx->bundleTrackers, entry->trackerId, entry);
     long trackerId = entry->trackerId;
     celixThreadMutex_unlock(&ctx->mutex);
 
@@ -670,20 +669,24 @@ bool celix_bundleContext_useBundle(
     return celix_framework_useBundle(ctx->framework, false, bundleId, 
callbackHandle, use);
 }
 
-static void bundleContext_cleanupBundleTrackers(bundle_context_t *ctx) {
+static void bundleContext_cleanupBundleTrackers(bundle_context_t* ctx) {
     module_pt module;
-    const char *symbolicName;
+    const char* symbolicName;
     bundle_getCurrentModule(ctx->bundle, &module);
     module_getSymbolicName(module, &symbolicName);
 
     celix_array_list_t* danglingTrkIds = NULL;
 
     celixThreadMutex_lock(&ctx->mutex);
-    hash_map_iterator_t iter = hashMapIterator_construct(ctx->bundleTrackers);
-    while (hashMapIterator_hasNext(&iter)) {
-        long trkId = (long)hashMapIterator_nextKey(&iter);
-        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling bundle 
tracker with id %li for bundle %s. Add missing 
'celix_bundleContext_stopTracker' calls.", trkId, symbolicName);
-        if (danglingTrkIds == NULL) {
+    CELIX_LONG_HASH_MAP_ITERATE(ctx->bundleTrackers, iter) {
+        long trkId = iter.key;
+        fw_log(
+            ctx->framework->logger,
+            CELIX_LOG_LEVEL_ERROR,
+            "Dangling bundle tracker with id %li for bundle %s. Add missing 
'celix_bundleContext_stopTracker' calls.",
+            trkId,
+            symbolicName);
+        if (!danglingTrkIds) {
             danglingTrkIds = celix_arrayList_create();
         }
         celix_arrayList_addLong(danglingTrkIds, trkId);
@@ -699,20 +702,25 @@ static void 
bundleContext_cleanupBundleTrackers(bundle_context_t *ctx) {
     }
 }
 
-static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx) {
+static void bundleContext_cleanupServiceTrackers(bundle_context_t* ctx) {
     module_pt module;
-    const char *symbolicName;
+    const char* symbolicName;
     bundle_getCurrentModule(ctx->bundle, &module);
     module_getSymbolicName(module, &symbolicName);
 
     celix_array_list_t* danglingTrkIds = NULL;
 
     celixThreadMutex_lock(&ctx->mutex);
-    hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackers);
-    while (hashMapIterator_hasNext(&iter)) {
-        long trkId = (long)hashMapIterator_nextKey(&iter);
-        celix_bundle_context_service_tracker_entry_t* entry = 
hashMap_get(ctx->serviceTrackers, (void*)trkId);
-        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling 
service tracker with trkId %li, for bundle %s and with filter %s. Add missing 
'celix_bundleContext_stopTracker' calls.", trkId, symbolicName, 
entry->tracker->filter);
+    CELIX_LONG_HASH_MAP_ITERATE(ctx->serviceTrackers, iter) {
+        long trkId = iter.key;
+        celix_bundle_context_service_tracker_entry_t* entry = 
celix_longHashMap_get(ctx->serviceTrackers, trkId);
+        fw_log(ctx->framework->logger,
+               CELIX_LOG_LEVEL_ERROR,
+               "Dangling service tracker with trkId %li, for bundle %s and 
with filter %s. Add missing "
+               "'celix_bundleContext_stopTracker' calls.",
+               trkId,
+               symbolicName,
+               entry->tracker->filter);
         if (danglingTrkIds == NULL) {
             danglingTrkIds = celix_arrayList_create();
         }
@@ -729,20 +737,25 @@ static void 
bundleContext_cleanupServiceTrackers(bundle_context_t *ctx) {
     }
 }
 
-static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx) 
{
+static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t* ctx) 
{
     module_pt module;
-    const char *symbolicName;
+    const char* symbolicName;
     bundle_getCurrentModule(ctx->bundle, &module);
     module_getSymbolicName(module, &symbolicName);
 
     celix_array_list_t* danglingTrkIds = NULL;
 
     celixThreadMutex_lock(&ctx->mutex);
-    hash_map_iterator_t iter = hashMapIterator_construct(ctx->metaTrackers);
-    while (hashMapIterator_hasNext(&iter)) {
-        long trkId = (long)hashMapIterator_nextKey(&iter);
-        celix_bundle_context_service_tracker_tracker_entry_t *entry = 
hashMap_get(ctx->metaTrackers, (void*)trkId);
-        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling meta 
tracker (service tracker tracker) with trkId %li, for bundle %s and for the 
services %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, 
symbolicName, entry->serviceName);
+    CELIX_LONG_HASH_MAP_ITERATE(ctx->metaTrackers, iter) {
+        long trkId = iter.key;
+        celix_bundle_context_service_tracker_tracker_entry_t* entry = 
celix_longHashMap_get(ctx->metaTrackers, trkId);
+        fw_log(ctx->framework->logger,
+               CELIX_LOG_LEVEL_ERROR,
+               "Dangling meta tracker (service tracker tracker) with trkId 
%li, for bundle %s and for the services %s. "
+               "Add missing 'celix_bundleContext_stopTracker' calls.",
+               trkId,
+               symbolicName,
+               entry->serviceName);
         if (danglingTrkIds == NULL) {
             danglingTrkIds = celix_arrayList_create();
         }
@@ -791,7 +804,7 @@ static void celix_bundleContext_removeBundleTracker(void 
*data) {
     celix_bundle_context_bundle_tracker_entry_t *tracker = data;
     fw_removeBundleListener(tracker->ctx->framework, tracker->ctx->bundle, 
&tracker->listener);
     celixThreadMutex_lock(&tracker->ctx->mutex);
-    hashMap_remove(tracker->ctx->stoppingTrackerEventIds, 
(void*)tracker->trackerId);
+    celix_longHashMap_remove(tracker->ctx->stoppingTrackerEventIds, 
tracker->trackerId);
     celixThreadMutex_unlock(&tracker->ctx->mutex);
     free(tracker);
 }
@@ -800,7 +813,7 @@ static void celix_bundleContext_removeServiceTracker(void 
*data) {
     celix_bundle_context_service_tracker_entry_t *tracker = data;
     celix_serviceTracker_destroy(tracker->tracker);
     celixThreadMutex_lock(&tracker->ctx->mutex);
-    hashMap_remove(tracker->ctx->stoppingTrackerEventIds, 
(void*)tracker->trackerId);
+    celix_longHashMap_remove(tracker->ctx->stoppingTrackerEventIds, 
tracker->trackerId);
     celixThreadMutex_unlock(&tracker->ctx->mutex);
     if (tracker->isFreeFilterNeeded) {
         free((char*)tracker->opts.filter.serviceName);
@@ -814,7 +827,7 @@ static void 
celix_bundleContext_removeServiceTrackerTracker(void *data) {
     celix_bundle_context_service_tracker_tracker_entry_t *tracker = data;
     celix_framework_unregister(tracker->ctx->framework, tracker->ctx->bundle, 
tracker->serviceId);
     celixThreadMutex_lock(&tracker->ctx->mutex);
-    hashMap_remove(tracker->ctx->stoppingTrackerEventIds, 
(void*)tracker->trackerId);
+    celix_longHashMap_remove(tracker->ctx->stoppingTrackerEventIds, 
tracker->trackerId);
     celixThreadMutex_unlock(&tracker->ctx->mutex);
     free(tracker->serviceName);
     free(tracker);
@@ -833,25 +846,28 @@ static void 
celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long
 
     celixThreadMutex_lock(&ctx->mutex);
 
-    if (hashMap_containsKey(ctx->bundleTrackers, (void *) trackerId)) {
+    if (celix_longHashMap_hasKey(ctx->bundleTrackers, trackerId)) {
         found = true;
-        bundleTracker = hashMap_remove(ctx->bundleTrackers, (void *) 
trackerId);
+        bundleTracker = celix_longHashMap_get(ctx->bundleTrackers, trackerId);
+        (void)celix_longHashMap_remove(ctx->bundleTrackers, trackerId);
         if (!bundleTracker->created && !async) {
             //note tracker not yet created, so cancel instead of removing
             bundleTracker->cancelled = true;
             cancelled = true;
         }
-    } else if (hashMap_containsKey(ctx->serviceTrackers, (void *) trackerId)) {
+    } else if (celix_longHashMap_hasKey(ctx->serviceTrackers, trackerId)) {
         found = true;
-        serviceTracker = hashMap_remove(ctx->serviceTrackers, (void *) 
trackerId);
+        serviceTracker = celix_longHashMap_get(ctx->serviceTrackers, 
trackerId);
+        (void)celix_longHashMap_remove(ctx->serviceTrackers, trackerId);
         if (serviceTracker->tracker == NULL && !async) {
             //note tracker not yet created, so cancel instead of removing
             serviceTracker->cancelled = true;
             cancelled = true;
         }
-    } else if (hashMap_containsKey(ctx->metaTrackers, (void *) trackerId)) {
+    } else if (celix_longHashMap_hasKey(ctx->metaTrackers, trackerId)) {
         found = true;
-        svcTrackerTracker = hashMap_remove(ctx->metaTrackers, (void *) 
trackerId);
+        svcTrackerTracker = celix_longHashMap_get(ctx->metaTrackers, 
trackerId);
+        (void)celix_longHashMap_remove(ctx->metaTrackers, trackerId);
         //note because a meta tracker is a service listener hook under waiter, 
no additional cancel is needed (svc reg will be cancelled)
     }
 
@@ -885,7 +901,7 @@ static void 
celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long
     } else if (found && async) {
         //NOTE: for async stopping of tracking we need to ensure we cant wait 
for the tracker destroy id event.
         long eventId = celix_framework_nextEventId(ctx->framework);
-        hashMap_put(ctx->stoppingTrackerEventIds, (void*)trackerId, 
(void*)eventId);
+        celix_longHashMap_put(ctx->stoppingTrackerEventIds, trackerId, 
(void*)eventId);
 
         if (bundleTracker != NULL) {
             celix_framework_fireGenericEvent(ctx->framework, eventId, 
celix_bundle_getId(ctx->bundle), "stop tracker", bundleTracker, 
celix_bundleContext_removeBundleTracker, doneData, doneCallback);
@@ -937,25 +953,25 @@ static void 
celix_bundleContext_waitForTrackerInternal(celix_bundle_context_t* c
 
     if (waitForStart) {
         celixThreadMutex_lock(&ctx->mutex);
-        if (hashMap_containsKey(ctx->bundleTrackers, (void *) trackerId)) {
+        if (celix_longHashMap_hasKey(ctx->bundleTrackers, trackerId)) {
             found = true;
-            celix_bundle_context_bundle_tracker_entry_t* bundleTracker = 
hashMap_get(ctx->bundleTrackers, (void *) trackerId);
+            celix_bundle_context_bundle_tracker_entry_t* bundleTracker = 
celix_longHashMap_get(ctx->bundleTrackers, trackerId);
             eventId = bundleTracker->createEventId;
-        } else if (hashMap_containsKey(ctx->serviceTrackers, (void *) 
trackerId)) {
+        } else if (celix_longHashMap_hasKey(ctx->serviceTrackers, trackerId)) {
             found = true;
-            celix_bundle_context_service_tracker_entry_t* serviceTracker = 
hashMap_get(ctx->serviceTrackers, (void *) trackerId);
+            celix_bundle_context_service_tracker_entry_t* serviceTracker = 
celix_longHashMap_get(ctx->serviceTrackers, trackerId);
             eventId = serviceTracker->createEventId;
-        } else if (hashMap_containsKey(ctx->metaTrackers, (void *) trackerId)) 
{
+        } else if (celix_longHashMap_hasKey(ctx->metaTrackers, trackerId)) {
             found = true;
-            celix_bundle_context_service_tracker_tracker_entry_t* 
svcTrackerTracker = hashMap_get(ctx->metaTrackers, (void *) trackerId);
+            celix_bundle_context_service_tracker_tracker_entry_t* 
svcTrackerTracker = celix_longHashMap_get(ctx->metaTrackers, trackerId);
             svcId = svcTrackerTracker->serviceId;
         }
         celixThreadMutex_unlock(&ctx->mutex);
     } else {
         celixThreadMutex_lock(&ctx->mutex);
-        if (hashMap_containsKey(ctx->stoppingTrackerEventIds, 
(void*)trackerId)) {
+        if (celix_longHashMap_hasKey(ctx->stoppingTrackerEventIds, trackerId)) 
{
             found = true;
-            eventId = (long)hashMap_get(ctx->stoppingTrackerEventIds, 
(void*)trackerId);
+            eventId = celix_longHashMap_getLong(ctx->stoppingTrackerEventIds, 
trackerId, -1);
         }
         celixThreadMutex_unlock(&ctx->mutex);
     }
@@ -1310,7 +1326,7 @@ static long 
celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_co
             celixThreadMutex_lock(&ctx->mutex);
             entry->trackerId = ctx->nextTrackerId++;
             trackerId = entry->trackerId;
-            hashMap_put(ctx->serviceTrackers, (void *) trackerId, entry);
+            celix_longHashMap_put(ctx->serviceTrackers, trackerId, entry);
             celixThreadMutex_unlock(&ctx->mutex);
         }
         return trackerId;
@@ -1334,7 +1350,7 @@ static long 
celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_co
         celixThreadMutex_lock(&ctx->mutex);
         entry->trackerId = ctx->nextTrackerId++;
         long trackerId = entry->trackerId;
-        hashMap_put(ctx->serviceTrackers, (void *)entry->trackerId, entry);
+        celix_longHashMap_put(ctx->serviceTrackers, entry->trackerId, entry);
         celixThreadMutex_unlock(&ctx->mutex);
 
         long id = celix_framework_fireGenericEvent(ctx->framework, 
entry->createEventId, celix_bundle_getId(ctx->bundle), "create service tracker 
event", entry, celix_bundleContext_createTrackerOnEventLoop, entry, 
celix_bundleContext_doneCreatingTrackerOnEventLoop);
@@ -1355,6 +1371,135 @@ long 
celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *c
     return celix_bundleContext_trackServicesWithOptionsInternal(ctx, opts, 
true);
 }
 
+bool celix_bundleContext_useTrackedService(
+    celix_bundle_context_t *ctx,
+    long trackerId,
+    void *callbackHandle,
+    void (*use)(void *handle, void* svc)
+) {
+    celix_tracked_service_use_options_t opts = 
CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS;
+    opts.callbackHandle = callbackHandle;
+    opts.use = use;
+    return celix_bundleContext_useTrackedServiceWithOptions(ctx, trackerId, 
&opts);
+}
+
+size_t celix_bundleContext_useTrackedServices(celix_bundle_context_t* ctx,
+                                              long trackerId,
+                                              void* callbackHandle,
+                                              void (*use)(void* handle, void* 
svc)) {
+    celix_tracked_service_use_options_t opts = 
CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS;
+    opts.callbackHandle = callbackHandle;
+    opts.use = use;
+    return celix_bundleContext_useTrackedServicesWithOptions(ctx, trackerId, 
&opts);
+}
+
+/**
+ * @brief Find a service tracker with the given tracker id. ctx->mutex must be 
locked.
+ */
+static celix_service_tracker_t* 
celix_bundleContext_findServiceTracker(celix_bundle_context_t* ctx, long 
trackerId) {
+    if (trackerId < 0) {
+        return NULL; //silent ignore
+    }
+
+    celix_bundle_context_service_tracker_entry_t* entry = 
celix_longHashMap_get(ctx->serviceTrackers, trackerId);
+    if (!entry) {
+        fw_log(ctx->framework->logger,
+               CELIX_LOG_LEVEL_ERROR,
+               "Cannot use tracked service with tracker id %li, because no 
tracker with that id is found",
+               trackerId);
+        return NULL;
+    }
+    return entry->tracker;
+}
+
+static size_t 
celix_bundleContext_useTrackedServiceWithOptionsInternal(celix_bundle_context_t*
 ctx,
+                                                                       long 
trackerId,
+                                                                       const 
celix_tracked_service_use_options_t* opts,
+                                                                       bool 
singleUse) {
+    celix_auto(celix_mutex_lock_guard_t) lck = 
celixMutexLockGuard_init(&ctx->mutex);
+    celix_service_tracker_t* trk = celix_bundleContext_findServiceTracker(ctx, 
trackerId);
+    if (!trk) {
+        return 0;
+    }
+
+    if (singleUse) {
+        bool called = celix_serviceTracker_useHighestRankingService(trk,
+                                                                    NULL,
+                                                                    
opts->waitTimeoutInSeconds,
+                                                                    
opts->callbackHandle,
+                                                                    opts->use,
+                                                                    
opts->useWithProperties,
+                                                                    
opts->useWithOwner);
+        return called ? 1 : 0;
+    } else {
+        return celix_serviceTracker_useServices(
+            trk, NULL, opts->callbackHandle, opts->use, 
opts->useWithProperties, opts->useWithOwner);
+    }
+}
+
+bool celix_bundleContext_useTrackedServiceWithOptions(celix_bundle_context_t* 
ctx,
+                                                      long trackerId,
+                                                      const 
celix_tracked_service_use_options_t* opts) {
+    return celix_bundleContext_useTrackedServiceWithOptionsInternal(ctx, 
trackerId, opts, true) > 0;
+}
+
+size_t 
celix_bundleContext_useTrackedServicesWithOptions(celix_bundle_context_t* ctx,
+                                                         long trackerId,
+                                                         const 
celix_tracked_service_use_options_t* opts) {
+    return celix_bundleContext_useTrackedServiceWithOptionsInternal(ctx, 
trackerId, opts, false);
+}
+
+void celix_bundleContext_getTrackerInfo(celix_bundle_context_t *ctx, long 
trackerId, size_t *trackedServiceCount, const char **trackedServiceName, const 
char **trackedServiceFilter) {
+    if (trackedServiceCount) {
+        *trackedServiceCount = 0;
+    }
+    if (trackedServiceName) {
+        *trackedServiceName = NULL;
+    }
+    if (trackedServiceFilter) {
+        *trackedServiceFilter = NULL;
+    }
+
+    celix_auto(celix_mutex_lock_guard_t) lck = 
celixMutexLockGuard_init(&ctx->mutex);
+    celix_service_tracker_t* trk = celix_bundleContext_findServiceTracker(ctx, 
trackerId);
+    if (!trk) {
+        return;
+    }
+
+    if (trackedServiceCount) {
+        *trackedServiceCount = 
celix_serviceTracker_getTrackedServiceCount(trk);
+    }
+    if (trackedServiceName) {
+        *trackedServiceName = celix_serviceTracker_getTrackedServiceName(trk);
+    }
+    if (trackedServiceFilter) {
+        *trackedServiceFilter = 
celix_serviceTracker_getTrackedServiceFilter(trk);
+    }
+}
+
+size_t celix_bundleContext_getTrackedServiceCount(celix_bundle_context_t *ctx, 
long trackerId) {
+    size_t result = 0;
+    celix_bundleContext_getTrackerInfo(ctx, trackerId, &result, NULL, NULL);
+    return result;
+}
+
+const char* celix_bundleContext_getTrackedServiceName(celix_bundle_context_t 
*ctx, long trackerId) {
+    const char* result = NULL;
+    celix_bundleContext_getTrackerInfo(ctx, trackerId, NULL, &result, NULL);
+    return result;
+}
+
+const char* 
celix_bundleContext_getTrackedServiceFilter(celix_bundle_context_t* ctx, long 
trackerId) {
+    const char* result = NULL;
+    celix_bundleContext_getTrackerInfo(ctx, trackerId, NULL, NULL, &result);
+    return result;
+}
+
+bool celix_bundleContext_isValidTrackerId(celix_bundle_context_t* ctx, long 
trackerId) {
+    celix_auto(celix_mutex_lock_guard_t) lck = 
celixMutexLockGuard_init(&ctx->mutex);
+    return celix_longHashMap_hasKey(ctx->serviceTrackers, trackerId);
+}
+
 long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char 
*serviceName) {
     celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS;
     opts.serviceName = serviceName;
@@ -1471,7 +1616,7 @@ long celix_bundleContext_trackServiceTrackersInternal(
 
     if (entry->serviceId >= 0) {
         celixThreadMutex_lock(&ctx->mutex);
-        hashMap_put(ctx->metaTrackers, (void*)entry->trackerId, entry);
+        celix_longHashMap_put(ctx->metaTrackers, entry->trackerId, entry);
         long trkId = entry->trackerId;
         celixThreadMutex_unlock(&ctx->mutex);
         return trkId;
diff --git a/libs/framework/src/bundle_context_private.h 
b/libs/framework/src/bundle_context_private.h
index 38482d1d..13c3f350 100644
--- a/libs/framework/src/bundle_context_private.h
+++ b/libs/framework/src/bundle_context_private.h
@@ -20,13 +20,15 @@
 #ifndef BUNDLE_CONTEXT_PRIVATE_H_
 #define BUNDLE_CONTEXT_PRIVATE_H_
 
+#include <stdbool.h>
+
 #include "bundle_context.h"
 #include "bundle_listener.h"
 #include "celix_bundle_context.h"
 #include "celix_log.h"
+#include "celix_long_hash_map.h"
 #include "listener_hook_service.h"
 #include "service_tracker.h"
-#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -76,17 +78,20 @@ typedef struct 
celix_bundle_context_service_tracker_tracker_entry {
 } celix_bundle_context_service_tracker_tracker_entry_t;
 
 struct celix_bundle_context {
-       celix_framework_t *framework;
-       celix_bundle_t *bundle;
-
-       celix_thread_mutex_t mutex; //protects fields below (NOTE/FIXME also 
used by bundle.c for listing service tracker usage)
-        celix_array_list_t *svcRegistrations; //serviceIds
-       celix_dependency_manager_t *mng;
-       long nextTrackerId;
-       hash_map_t *bundleTrackers; //key = trackerId, value = 
celix_bundle_context_bundle_tracker_entry_t*
-       hash_map_t *serviceTrackers; //key = trackerId, value = 
celix_bundle_context_service_tracker_entry_t*
-       hash_map_t *metaTrackers; //key = trackerId, value = 
celix_bundle_context_service_tracker_tracker_entry_t*
-    hash_map_t *stoppingTrackerEventIds; //key = trackerId, value = eventId 
for stopping the tracker. Note id are only present if the stop tracking is 
queued.
+    celix_framework_t* framework;
+    celix_bundle_t* bundle;
+
+    celix_thread_mutex_t
+        mutex; // protects fields below (NOTE/FIXME also used by bundle.c for 
listing service tracker usage)
+    celix_array_list_t* svcRegistrations; // serviceIds
+    celix_dependency_manager_t* mng;
+    long nextTrackerId;
+    celix_long_hash_map_t* bundleTrackers;  // key = trackerId, value = 
celix_bundle_context_bundle_tracker_entry_t*
+    celix_long_hash_map_t* serviceTrackers; // key = trackerId, value = 
celix_bundle_context_service_tracker_entry_t*
+    celix_long_hash_map_t*
+        metaTrackers; // key = trackerId, value = 
celix_bundle_context_service_tracker_tracker_entry_t*
+    celix_long_hash_map_t* stoppingTrackerEventIds; // key = trackerId, value 
= eventId for stopping the tracker. Note
+                                                    // id are only present if 
the stop tracking is queued.
 };
 
 /**
diff --git a/libs/framework/src/service_tracker.c 
b/libs/framework/src/service_tracker.c
index 481bcfce..d3bbbb21 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -712,20 +712,19 @@ void celix_serviceTracker_destroy(celix_service_tracker_t 
*tracker) {
     }
 }
 
-static celix_tracked_entry_t* 
celix_serviceTracker_findHighestRankingService(service_tracker_t *tracker, 
const char* serviceName) {
-    //precondition tracker->mutex locked
+static celix_tracked_entry_t* 
celix_serviceTracker_findHighestRankingService(service_tracker_t* tracker,
+                                                                             
const char* serviceName) {
+    // precondition tracker->mutex locked
     celix_tracked_entry_t* highest = NULL;
     for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); ++i) {
         celix_tracked_entry_t* tracked = 
celix_arrayList_get(tracker->trackedServices, i);
-        if (serviceName == NULL || (serviceName != NULL && 
tracked->serviceName != NULL &&
-                                    
celix_utils_stringEquals(tracked->serviceName, serviceName))) {
+        if (serviceName == NULL ||
+            (tracked->serviceName != NULL && 
celix_utils_stringEquals(tracked->serviceName, serviceName))) {
             if (highest == NULL) {
                 highest = tracked;
             } else {
                 int compare = celix_utils_compareServiceIdsAndRanking(
-                        tracked->serviceId, tracked->serviceRanking,
-                        highest->serviceId, highest->serviceRanking
-                );
+                    tracked->serviceId, tracked->serviceRanking, 
highest->serviceId, highest->serviceRanking);
                 if (compare < 0) {
                     highest = tracked;
                 }
@@ -817,4 +816,19 @@ size_t celix_serviceTracker_useServices(
         tracked_release(entry);
     }
     return count;
-}
\ No newline at end of file
+}
+
+size_t celix_serviceTracker_getTrackedServiceCount(celix_service_tracker_t 
*tracker) {
+    celix_auto(celix_mutex_lock_guard_t) lck = 
celixMutexLockGuard_init(&tracker->mutex);
+    return (size_t) celix_arrayList_size(tracker->trackedServices);
+}
+
+const char* celix_serviceTracker_getTrackedServiceName(celix_service_tracker_t 
*tracker) {
+    celix_auto(celix_mutex_lock_guard_t) lck = 
celixMutexLockGuard_init(&tracker->mutex);
+    return tracker->serviceName;
+}
+
+const char* 
celix_serviceTracker_getTrackedServiceFilter(celix_service_tracker_t *tracker) {
+    celix_auto(celix_mutex_lock_guard_t) lck = 
celixMutexLockGuard_init(&tracker->mutex);
+    return tracker->filter;
+}

Reply via email to