When building a new system service in AOSP, the first technical step is defining the contract between the service and its clients. This is done using the Android Interface Definition Language (AIDL). AIDL files serve as the blueprint from which the build system generates the C++ and Java Binder stubs and proxies.
Designing the Service AIDL Interface
An AIDL interface defines the methods that a client process can invoke on the remote service process. The design should prioritize security, efficiency, and clarity.
Example IMyCustomService.aidl:
package android.os;
import android.os.MyCustomConfig;
import android.os.IMyCustomCallback;
/**
* Interface for interacting with the custom hardware service.
* {@hide}
*/
interface IMyCustomService {
/**
* Retrieves the current status.
* @return 0 for success, negative error code otherwise.
*/
int getStatus();
/**
* Applies a new configuration.
* @param config The configuration to apply.
*/
void applyConfiguration(in MyCustomConfig config);
/**
* Registers a callback for state changes.
*/
void registerCallback(in IMyCustomCallback callback);
}
Key considerations:
- Directional Tags: Method parameters must be explicitly tagged as
in,out, orinout. This tells the Binder driver how to optimize the memory copying between processes.inmeans data flows from client to service;outmeans data flows from service to client. @hideAnnotation: If you are building a system service intended only for platform components and not for third-party apps, you must use the{@hide}javadoc annotation to prevent it from being compiled into the public Android SDK.
Parcelable Types for Your Service
Standard primitives (int, boolean, String) can be passed directly over Binder. For complex data structures, you must define them as Parcelable. In modern AOSP development, you define Parcelables directly in AIDL, rather than writing manual Java/C++ serialization code.
Example MyCustomConfig.aidl:
package android.os;
/** {@hide} */
parcelable MyCustomConfig {
int timeoutMs;
boolean enableLogging;
String profileName;
}
The build system will automatically generate the boilerplate C++ and Java classes required to flatten this struct into a Binder Parcel and reconstruct it on the receiving end.
Callback Interfaces
System services frequently need to push asynchronous events back to clients. Because Binder is inherently synchronous (client calls service and blocks), callbacks require defining a second AIDL interface that the client implements.
Example IMyCustomCallback.aidl:
package android.os;
/** {@hide} */
oneway interface IMyCustomCallback {
void onStateChanged(int newState);
}
Notice the oneway keyword. When a service invokes a oneway method on the client's callback interface, the Binder driver dispatches the transaction and returns immediately. The service process does not block waiting for the client to finish processing the callback. This is critical to prevent a malicious or frozen client app from locking up a core system service.