Skip to content

Service logic moved to kernel#554

Open
KenVanHoeylandt wants to merge 6 commits into
mainfrom
service-logic-move-to-kernel
Open

Service logic moved to kernel#554
KenVanHoeylandt wants to merge 6 commits into
mainfrom
service-logic-move-to-kernel

Conversation

@KenVanHoeylandt

@KenVanHoeylandt KenVanHoeylandt commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added service-specific C helpers to compute user-data and assets directories and full child paths.
    • Introduced a unified service manager and kernel service-instance/context interfaces for registering, starting, stopping, and querying service state.
  • Bug Fixes
    • Paired Bluetooth device settings now resolve from the current user-data/service path instead of a fixed location.
    • GUI-related services now correctly detect the stopped runtime state before starting.
  • Tests
    • Added tests covering service path helpers and service manager/service instance start-stop lifecycle behavior.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 82da8203-7aa0-47ac-b259-b7165e047453

📥 Commits

Reviewing files that changed from the base of the PR and between 469cf0d and a2a802e.

📒 Files selected for processing (4)
  • TactilityKernel/include/tactility/service/service_instance.h
  • TactilityKernel/include/tactility/service/service_manager.h
  • TactilityKernel/source/service/service_instance.cpp
  • Tests/TactilityKernel/Source/ServiceTest.cpp
💤 Files with no reviewable changes (3)
  • TactilityKernel/include/tactility/service/service_instance.h
  • TactilityKernel/source/service/service_instance.cpp
  • Tests/TactilityKernel/Source/ServiceTest.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • TactilityKernel/include/tactility/service/service_manager.h

📝 Walkthrough

Walkthrough

This PR adds a kernel-level C service API for manifests, instances, manager control, and path resolution, plus a user-data path helper. The Tactility C++ service layer is updated to use those kernel APIs for state, registration, and path lookup. Bluetooth paired-device storage now uses the computed user-data path. New doctest coverage exercises the path helpers and service lifecycle flows.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: service logic is being moved into the kernel.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch service-logic-move-to-kernel

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
Tactility/Source/bluetooth/BluetoothPairedDevice.cpp (1)

108-117: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Redundant recomputation of the settings path.

getSettingsFilePath() builds a new string on each call, and here it's invoked twice within the same function (Lines 110 and 113). Minor, but worth caching into a local variable to avoid duplicate string concatenation.

Suggested tweak
 std::vector<PairedDevice> loadAll() {
     std::vector<dirent> entries;
-    if (!file::isDirectory(getSettingsFilePath())) {
+    const auto settings_path = getSettingsFilePath();
+    if (!file::isDirectory(settings_path)) {
         return {};
     }
-    file::scandir(getSettingsFilePath(), entries, [](const dirent* entry) -> int {
+    file::scandir(settings_path, entries, [](const dirent* entry) -> int {
Tests/TactilityKernel/Source/ServiceTest.cpp (2)

4-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fragile ad-hoc extern "C" declaration for internal test hook.

service_instance_set_state is declared here by hand rather than via a shared internal/testing header. If the real signature in service_instance.cpp changes, this won't fail to compile with a clear diagnostic tied to the source of truth — it can silently mismatch at link time. Consider exposing this via a small internal testing header included by both the implementation and this test.


166-182: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider asserting cleanup on start failure.

This test verifies state/context after a failed start, but doesn't assert destroy_called at the end (after service_manager_remove), leaving the destroy path on a failed-start instance unverified.

TactilityKernel/source/paths.cpp (1)

18-21: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Prefer bounded copy over strcpy, even though manually guarded.

Both call sites check length before strcpy, so they aren't currently exploitable, but static analysis flags the raw strcpy pattern (CWE-120), and the rest of the file already uses snprintf for bounded writes. Switching to snprintf for consistency removes the lint noise and guards against future edits that might remove the preceding length check.

Suggested fix using snprintf
-    if (std::strlen(mount_point) + 1 > out_path_size) {
-        return ERROR_BUFFER_OVERFLOW;
-    }
-    std::strcpy(out_path, mount_point);
-    return ERROR_NONE;
+    int written = std::snprintf(out_path, out_path_size, "%s", mount_point);
+    if (written < 0 || (size_t)written >= out_path_size) {
+        return ERROR_BUFFER_OVERFLOW;
+    }
+    return ERROR_NONE;

(apply the same change to the second strcpy call site)

Also applies to: 58-61

Source: Linters/SAST tools


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6abd1ca9-84eb-4b18-8748-65caabaf9b69

📥 Commits

Reviewing files that changed from the base of the PR and between cca7224 and 469cf0d.

📒 Files selected for processing (20)
  • Tactility/Include/Tactility/service/Service.h
  • Tactility/Include/Tactility/service/ServicePaths.h
  • Tactility/Private/Tactility/service/ServiceInstance.h
  • Tactility/Source/bluetooth/BluetoothPairedDevice.cpp
  • Tactility/Source/lvgl/Lvgl.cpp
  • Tactility/Source/service/ServiceInstance.cpp
  • Tactility/Source/service/ServicePaths.cpp
  • Tactility/Source/service/ServiceRegistration.cpp
  • TactilityKernel/include/tactility/paths.h
  • TactilityKernel/include/tactility/service/service_context.h
  • TactilityKernel/include/tactility/service/service_instance.h
  • TactilityKernel/include/tactility/service/service_manager.h
  • TactilityKernel/include/tactility/service/service_manifest.h
  • TactilityKernel/include/tactility/service/service_paths.h
  • TactilityKernel/source/paths.cpp
  • TactilityKernel/source/service/service_instance.cpp
  • TactilityKernel/source/service/service_manager.cpp
  • TactilityKernel/source/service/service_paths.cpp
  • Tests/TactilityKernel/Source/ServicePathsTest.cpp
  • Tests/TactilityKernel/Source/ServiceTest.cpp
💤 Files with no reviewable changes (2)
  • Tactility/Source/service/ServicePaths.cpp
  • Tactility/Source/service/ServiceInstance.cpp

Comment thread Tactility/Source/bluetooth/BluetoothPairedDevice.cpp
Comment thread TactilityKernel/source/service/service_instance.cpp
Comment on lines +114 to +139
// Register before on_start() so a service can find itself while starting.
instance_ledger.instances[id] = instance;
mutex_unlock(&instance_ledger.mutex);

service_instance_set_state(instance, SERVICE_STATE_STARTING);

LOG_I(TAG, "start %s", id);
error = (instance->on_start != nullptr) ? instance->on_start(instance) : ERROR_NONE;

if (error == ERROR_NONE) {
service_instance_set_state(instance, SERVICE_STATE_STARTED);
return ERROR_NONE;
}

LOG_E(TAG, "Failed to start %s: %s", id, error_to_string(error));
service_instance_set_state(instance, SERVICE_STATE_STOPPED);

mutex_lock(&instance_ledger.mutex);
instance_ledger.instances.erase(id);
mutex_unlock(&instance_ledger.mutex);

service_instance_destruct(instance);
delete instance;

return ERROR_RESOURCE;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP '\bservice_manager_(start|stop)\b' -C3
# Look for on_start callbacks that may re-enter the manager
rg -nP '\bon_start\b\s*=' -C3

Repository: TactilityProject/Tactility

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the service manager implementation and related interfaces.
git ls-files 'TactilityKernel/source/service/*' 'TactilityKernel/include/service/*' 'TactilityKernel/source/*service*' | sed -n '1,200p'

printf '\n--- service_manager.cpp outline ---\n'
ast-grep outline TactilityKernel/source/service/service_manager.cpp --view expanded || true

printf '\n--- search for service_manager_start/stop and on_start/on_stop implementations ---\n'
rg -n --hidden --glob '!**/build/**' --glob '!**/dist/**' '\bservice_manager_(start|stop)\b|\bon_start\b|\bon_stop\b' TactilityKernel -C 2

printf '\n--- search for use_count/reference-counting helpers ---\n'
rg -n --hidden --glob '!**/build/**' --glob '!**/dist/**' '\buse_count\b|reference count|refcount|retain|release' TactilityKernel -C 2

Repository: TactilityProject/Tactility

Length of output: 15218


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the relevant portion of service_manager.cpp with line numbers.
wc -l TactilityKernel/source/service/service_manager.cpp
sed -n '1,260p' TactilityKernel/source/service/service_manager.cpp | cat -n

# Inspect the service instance definition and lifecycle helpers.
rg -n --hidden --glob '!**/build/**' '\bstruct service_instance\b|\bclass service_instance\b|\bservice_instance_(set_state|destruct|construct|add_use_count|remove_use_count|get_use_count|find_context)\b' TactilityKernel -C 3

Repository: TactilityProject/Tactility

Length of output: 16111


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Focus on the start/stop implementations and callback wiring.
sed -n '1,260p' TactilityKernel/source/service/service_manager.cpp | cat -n
printf '\n---\n'
sed -n '1,260p' TactilityKernel/source/service/service.cpp | cat -n 2>/dev/null || true
printf '\n---\n'
rg -n --hidden --glob '!**/build/**' '\bon_start\b|\bon_stop\b' TactilityKernel/source TactilityKernel/include -C 4

Repository: TactilityProject/Tactility

Length of output: 18329


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Identify the exact service manager and service callback definitions.
files=$(git ls-files 'TactilityKernel/**/*.cpp' 'TactilityKernel/**/*.h' 'TactilityKernel/**/*.hpp')
printf '%s\n' "$files" | rg 'service_manager|service|kernel' || true

printf '\n--- service_manager.cpp ---\n'
sed -n '1,220p' TactilityKernel/source/service/service_manager.cpp | cat -n

printf '\n--- declarations of service_instance and lifecycle helpers ---\n'
rg -n --hidden --glob '!**/build/**' '\bservice_instance\b|service_instance_set_state|service_instance_destruct|service_instance_construct|service_manager_start|service_manager_stop|find_context' TactilityKernel -C 3

printf '\n--- any callbacks that call stop/start or service_manager directly ---\n'
rg -n --hidden --glob '!**/build/**' '\bservice_manager_(start|stop)\s*\(|\bstart_service\s*\(|\bstop_service\s*\(' TactilityKernel -C 3

Repository: TactilityProject/Tactility

Length of output: 26977


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the service manager implementation around the relevant lifecycle code.
sed -n '1,240p' TactilityKernel/source/service/service_manager.cpp | cat -n

printf '\n--- related symbols in the service subsystem ---\n'
rg -n --hidden --glob '!**/build/**' 'instance_ledger|use_count|service_instance_set_state|service_instance_destruct|service_manager_(start|stop)|on_start|on_stop' TactilityKernel/source TactilityKernel/include -C 3

Repository: TactilityProject/Tactility

Length of output: 32498


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the service-instance lifecycle helpers to see whether a STARTING instance
# can be destructed or whether the refcount protects it.
sed -n '1,140p' TactilityKernel/source/service/service_instance.cpp | cat -n

Repository: TactilityProject/Tactility

Length of output: 3986


Use-after-free if stop() runs while on_start() is still executing. The instance is published to instance_ledger before on_start() and then used again after the callback returns, but service_manager_stop() can erase and delete the same instance in that window. service_instance_try_get() only protects SERVICE_STATE_STARTED, so it does not pin the object during startup. Hold a lifetime reference across on_start() or otherwise defer destruction until startup completes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant