Services provide a powerful mechanism for plugins to expose functionality to other plugins. The service architecture enables loose coupling between plugins while maintaining strong contracts through Java interfaces.
The service system is managed by the ServiceManager class, which maintains a registry of service interfaces and their implementations.Reference: ~/workspace/source/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/ServiceManager.java:35
When your plugin directly implements a service interface, do NOT call registerServiceProvided() for that service. The framework automatically registers it.
Plugins can respond when services become available:
public class MyPlugin extends Plugin { @Override public void serviceAdded(Class<?> interfaceClass, Object service) { if (interfaceClass == ProgramManager.class) { // ProgramManager service is now available setupProgramManager((ProgramManager) service); } }}
public class MyPlugin extends Plugin { private ProgramManager programManager; @Override public void serviceRemoved(Class<?> interfaceClass, Object service) { if (interfaceClass == ProgramManager.class) { // ProgramManager service is being removed cleanupProgramManager(); programManager = null; } }}
For optional services, don’t declare them in servicesRequired:
@Overrideprotected void init() { // Optional service - may be null OptionalService service = tool.getService(OptionalService.class); if (service != null) { enableOptionalFeature(service); }}
Always check for null when retrieving services that aren’t required dependencies.
OptionalService service = tool.getService(OptionalService.class);if (service != null) { service.doWork();}
Thread Safety
Service methods may be called from multiple threads. Design services to be thread-safe or document threading requirements.
public class ThreadSafeService implements MyService { private final Object lock = new Object(); @Override public void doWork() { synchronized (lock) { // Thread-safe implementation } }}
Error Handling
Document and handle errors appropriately in service methods.
/** * Processes the given data. * @param data the data to process * @throws IllegalArgumentException if data is invalid * @throws IOException if processing fails */void processData(Data data) throws IOException;
The ServiceManager class provides the core service registry functionality:
public class ServiceManager { // Add a service to the registry public <T> void addService(Class<? extends T> interfaceClass, T service); // Remove a service from the registry public void removeService(Class<?> interfaceClass, Object service); // Get first service implementation public <T> T getService(Class<T> interfaceClass); // Get all service implementations public <T> T[] getServices(Class<T> interfaceClass); // Check if service exists public boolean isService(Class<?> serviceInterface); // Add/remove service listeners public void addServiceListener(ServiceListener listener); public void removeServiceListener(ServiceListener listener);}
// Check if service is required but missingMyService service = tool.getService(MyService.class);if (service == null) { Msg.warn(this, "MyService is not available"); return;}