Android system service acquisition and registration process
Outline:
- Obtaining System Services
- Registration system Services
- Standalone process services
- Services for independent processes
- conclusion
- The resources
This article is about 1.9K words, about 8 minutes to read.
Android source code based on 8.0.
Preview the overall process
Start analyzing!
Obtaining System Services
In daily development, you can use context.getSystemService () to get system services in your own application:
//ContextImpl.java
public Object getSystemService(String name) {
//SystemServiceRegistry is a registry of system services used to centrally manage system services
return SystemServiceRegistry.getSystemService(this, name);
}
//SystemServiceRegistry.java
public static Object getSystemService(ContextImpl ctx, String name) {
// Fetch ServiceFetcher from the HashMap based on the service nameServiceFetcher<? > fetcher = SYSTEM_SERVICE_FETCHERS.get(name);// Pass in the context, using ServiceFetcher to get the system service
returnfetcher ! =null ? fetcher.getService(ctx) : null;
}
Copy the code
ServiceFetcher is an abstract interface implemented by the abstract class CachedServiceFetcher.
//CachedServiceFetcher.java
public final T getService(ContextImpl ctx) {
// Each context CTX has a system service cache
final Object[] cache = ctx.mServiceCache;
synchronized (cache) {
// Get the system service from the cache
Object service = cache[mCacheIndex];
if (service == null) {
// If there is none in the cache, create one
service = createService(ctx);
// Cache
cache[mCacheIndex] = service;
}
return(T)service; }}CreateService is an abstract method
public abstract T createService(ContextImpl ctx);
Copy the code
In SystemServiceRegistry, there is a static block of code that “registers the service”, which implements the logic of the abstract method createService(). For example, the power service PowerManager,
//SystemServiceRegistry.java
registerService(
Context.POWER_SERVICE, PowerManager.class,
new CachedServiceFetcher<PowerManager>() {
@Override
public PowerManager createService(ContextImpl ctx){
//ServiceManager obtains Binder objects for system services based on service names
IBinder b = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
// Convert the Binder on the server to the AIDL interface type object IPowerManager required by the client
IPowerManager service = IPowerManager.Stub.asInterface(b);
// Use the PowerManager class package layer to facilitate external use
return new PowerManager(ctx.getOuterContext(),
service,
ctx.mMainThread.getHandler());
}});
Copy the code
AIDL can help generate classes for binder communication. IPowerManager is defined in iPowerManager.aidl. Binder internal details are not covered in this article.
The ServiceManager’s getServiceOrThrow() function calls getService(),
//ServiceManager.java
public static IBinder getService(String name) {
/ / cache
IBinder service = sCache.get(name);
if(service ! =null) {
return service;
} else {
// If you can't get it, sCache is not stored, that is, sCache is just preset some services stored during startup
//getService() gets the Binder object of the system service with allowBlocking
return Binder.allowBlocking(getIServiceManager().getService(name));
}
return null;
}
private static IServiceManager getIServiceManager(a) {
if(sServiceManager ! =null) {
return sServiceManager;
}
// Binder cross-process communication:
/ / BinderInternal getContextObject IBinder () get system level context, can be used to locate the service
//asInterface converts IBinder to IServiceManager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
Copy the code
As you can see, our application processes communicate with binder across processes to get the IServiceManager object (essentially BpServiceManager) of the ServiceManager process, The system service can then be obtained via IServiceManager object’s getService.
public interface IServiceManager extends IInterface{
// Get the system service from IServiceManager. If the service does not exist, it blocks for up to 5 seconds until the service is published and registered
public IBinder getService(String name);
}
Copy the code
Look at the IServiceManager implementation. In the IServiceManager. CPP file, there is a BpServiceManager class.
//class BpServiceManager : public BpInterface<IServiceManager>
// The BpInterface here is the internal detail of binder, which is not quite understood
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
// If not, sleep for 1 second and block for 5 seconds at most
for (n = 0; n < 5; n++){
if (n > 0) {
// Sleep for 1 second and fetch it later
sleep(1);
}
sp<IBinder> svc = checkService(name);
// The system service is obtained
if(svc ! =NULL) return svc;
}
return NULL;
}
// Return to binder of the system service
virtual sp<IBinder> checkService( const String16& name) const
{
// Binder uses Parcelable to serialize data
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
// Remote () gets BpBinder, transact sends the request
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();//Binder
}
Copy the code
Let’s review the process of obtaining system services:
- The application process calls getSystemService
- Communicate with binder across processes to get the BpServiceManager object of the ServiceManager process
- Obtain system services from BpServiceManager
Registration system Services
System services can be divided into two broad categories:
The ServiceManager, SurfaceFlinger, etc., which have separate processes, are created by fork when init starts.
Two independent process AMS, PMS, WMS, etc., they in init process fork out Zygote process, Zygote process fork out SystemServer process create.
Standalone process services
A system service for a standalone process starts when the init process parses init.rc, such as SurfaceFlinger. Take a look at its startup configuration file, SurfaceFlinger.
Note: frameworks/native/services following a series of services, but ServiceManager service on the frameworks/native/CMDS/ServiceManager directory.
//frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
class core animation
user system
group graphics drmrpc readproc
onrestart restart zygote
Copy the code
Service in the form of services to start the process, is surfaceflinger process name/system/bin/surfaceflinger is the path of the executable program, the program’s main entrance function in main_surfaceflinger. CPP,
int main(int.char* *) {
//ProcessState starts binder mechanism (binder driver open, memory mapped, buffer allocated)
sp<ProcessState> ps(ProcessState::self());
// Start the binder thread
ps->startThreadPool();
// Initialize surfaceFlinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();
flinger->init();
// Publish to register surfaceFlinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
// Run surfaceFlinger in the current thread
flinger->run();
return 0;
}
Copy the code
Take a look at the implementation of defaultServiceManager() in iservicemanager.cpp,
sp<IServiceManager> defaultServiceManager(a)
{
// If there is a value, return it directly
if(gDefaultServiceManager ! =NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
IServiceManager (BpServiceManager)
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
// If IServiceManager is still null, it will sleep for 1 second and fetch again until it finishes the loop
if (gDefaultServiceManager == NULL)
sleep(1); }}return gDefaultServiceManager;
}
Copy the code
The SurfaceFlinger process and the ServiceManager process are both started by the init process. It is possible that the SurfaceFlinger process obtains IServiceManager before the ServiceManager has been registered. Therefore, the SurfaceFlinger process will sleep while retrieving IServiceManager. End the loop.
After you get IServiceManager, run sm->addService. There is a BpServiceManager class in the iservicemanager.cpp file.
//class BpServiceManager : public BpInterface<IServiceManager>
// The BpInterface here is the internal detail of binder, which is not quite understood
// Register system services (binder)
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
// Binder uses Parcelable to serialize data
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);//Binder
data.writeInt32(allowIsolated ? 1 : 0);
// Remote () gets BpBinder, transact sends the request
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
Copy the code
To sort it out:
- Rc configuration forks out new processes to start system services for multiple independent processes, such as SurfaceFlinger
- Execute SurfaceFlinger’s executable to find the BpServiceManager object for the ServiceManager process
- AddService registers the service through BpServiceManager
Services for independent processes
SystemServer uses the SystemServiceManager class (SSM) to start system services, such as AMS.
//SystemServer.java
private void startBootstrapServices(a) {
//AMS is created and started by SSM
mActivityManagerService = mSystemServiceManager
// Create and start the AMS service
.startService(ActivityManagerService.Lifecycle.class)
// Obtain AMS service with binder
.getService();
/ / AMS registration
mActivityManagerService.setSystemProcess();
}
Copy the code
See ActivityManagerService,
//ActivityManagerService.java
public void setSystemProcess(a) {
/ / AMS registration
ServiceManager.addService(Context.ACTIVITY_SERVICE, this.true);
}
Copy the code
Call the ServiceManager. The addService () to register,
//ServiceManager.java
public static void addService(String name, IBinder service, boolean allowIsolated) {
// As before, communicate with binder across processes to get the BpServiceManager object of the ServiceManager process
// Call BpServiceManager addService
getIServiceManager().addService(name, service, allowIsolated);
}
Copy the code
Visible, whether SystemServer process to start the service, or the init process starts running in a separate process service, is go BpServiceManager ServiceManager process. Eventually the addService centrally registered.
conclusion
To sum up, both system services of independent processes such as SurfaceFlinger started by init process and system services of independent processes such as AMS started by SystemServer process are registered and obtained in ServiceManager process. Android’s Binder mechanism is used for cross-process communication.
But Hardy doesn’t use Binder much in his work, so he’ll leave the details behind for later.
Review again
Series of articles:
- Graphic | Android launch
The resources
- Csdn-servicemanager client agent: BpServiceManager
More sexy articles, pay attention to the original technology public account: Halliday EI