“This is the 7th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
If you want to add a Service to your system, you have to learn about the ServiceManager. I was confused at first, but I hope you found the understanding of ServiceManger useful in this article.
An overview of the
framework/native/cmds/servicemanager/
- service_manager.c
- binder.c
Kernel /drivers/ (Different Linux branch paths are slightly different)
- staging/android/binder.c
- android/binder.c
The service_manager process is started by the init process by parsing the init.rc file.
Service_manager is a daemon of the Binder IPC communication process, which is itself a Binder service. Instead of using libbinder’s multithreaded model to communicate with Binder drivers, service_manager is written by Binder. And there is only one loop, binder_loop, to read and process transactions, which has the advantage of being simple and efficient.
The Service_manager itself is relatively simple: it queries and registers services. For Binder IPC communication, communication between BpBinder and BBinder is more common, such as communication between ActivityManagerProxy and ActivityManagerService.
Start and register system services
1. The ServiceManager is being started
- During system startup, the Kernel module is started first.
- The kenel module starts the init process, which parses the init.rc file and starts a series of native services.
- The Zygote process preloads and initializes some core libraries to facilitate code sharing by subsequent application processes.
- Zygote Starts (fork) the system service process system_server
- AMS is one of a number of system services published in the System_Server process and runs in the System_Server process for the rest of its life cycle.
- AMS starts (forks) a series of application processes.
2. System_Server process
A series of system services started in the System_Server process are registered with the Service_manager process
The system_server process starts a series of system services, such as AMS,PMS, and WMS. These services are started by the system_server process and run in the form of threads.
After the service is started, it is registered with the service_manager process using the ServiceManager#addService(String name, IBinder service) method.
For example, active ManagerService (AMS) is started and registered as follows:
In the SystemServer#startBootstrapServices() method:
private void startBootstrapServices() { .......... // Activity manager runs the show. traceBeginAndSlog("StartActivityManager"); mActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); traceEnd(); . // Set up the Application instance for the system process and get started. traceBeginAndSlog("SetSystemProcess"); mActivityManagerService.setSystemProcess(); traceEnd(); . } // ActivityManagerService setSystemProcess public void setSystemProcess() {try {// Here we register the started AMS service with the Service_manager process. / / the IPC is the communication with service_manager system_server process ServiceManager. The addService (Context. ACTIVITY_SERVICE, this, true); ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); ServiceManager.addService("meminfo", new MemBinder(this)); ServiceManager.addService("gfxinfo", new GraphicsBinder(this)); ServiceManager.addService("dbinfo", new DbBinder(this)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(this)); } ServiceManager.addService("permission", new PermissionController(this)); ServiceManager.addService("processinfo", new ProcessInfoService(this)); ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY); mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader()); synchronized (this) { ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0); app.persistent = true; app.pid = MY_PID; app.maxAdj = ProcessList.SYSTEM_ADJ; app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); synchronized (mPidsSelfLocked) { mPidsSelfLocked.put(app.pid, app); } updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( "Unable to find android system package", e); }}Copy the code
Other system services are also started by the system_server process and registered with the service_manager process via ServiceManager#addService, which will not be analyzed here.
ServiceManager understand
Servicemanager. Java is the representation of the Service_manager process at the Java layer, providing the functions of querying and registering services.
The class is hidden and can only be called by the system. In order to more convenient service invocation system, Android provides individual service wrapper class, such as ActivityManager InputMethodManager, WindowManager, etc.
These classes implement some of the methods of the service class, but the internal implementation is done through the corresponding service class object, which is obtained through the ServiceManager#getService method.
Applications obtain system services
When the App loads the ContextImpl class, the services are registered in the static code block into a Map. When the application needs the relevant service, the Context#getSystemService method is used to obtain the relevant service object.
- Static code blocks register services into the Map collection in the ContextImpl#getSystemService method. The services are stored in the SystemServiceRegistry class:
final class SystemServiceRegistry { // Service registry information. // This information is never changed once static initialization has completed. private static final HashMap<Class<? >, String> SYSTEM_SERVICE_NAMES = new HashMap<Class<? >, String>(); Private static final HashMap<String, ServiceFetcher<? >> SYSTEM_SERVICE_FETCHERS = new HashMap<String, ServiceFetcher<? > > (); / / static code block, the registration service to Map collections of static {... registerService(Context.ACTIVITY_SERVICE, ActivityManager.class, new CachedServiceFetcher<ActivityManager>() { @Override public ActivityManager createService(ContextImpl ctx) { return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}); registerService(Context.ALARM_SERVICE, AlarmManager.class, new CachedServiceFetcher<AlarmManager>() { @Override public AlarmManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.ALARM_SERVICE); IAlarmManager service = IAlarmManager.Stub.asInterface(b); return new AlarmManager(service, ctx); }}); . } /** * Statically registers a system service with the context. * This method must be called during static initialization only. */ private static <T> void registerService(String serviceName, Class<T> serviceClass, ServiceFetcher<T> serviceFetcher) { SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName); SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); }}Copy the code
-
Context retrieves system services:
// ContextImpl getSystemService method @override public Object getSystemService(String name) {return SystemServiceRegistry.getSystemService(this, name); } /**SystemServiceRegistry class getSystemService method, based on the service name, find the service provider in the Map collection, and obtain the service object. * Gets a system service from a given context. */ public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<? > fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher ! = null ? fetcher.getService(ctx) : null; }Copy the code
Then we get the system service we want, such as the input method service.
ServiceManager source code analysis
public final class ServiceManager { private static final String TAG = "ServiceManager"; Binder objects accessed by the Service_manager process private static IServiceManager sServiceManager; // Service object cache collection. The accessed objects are cached. Private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>(); private static IServiceManager getIServiceManager() { if (sServiceManager ! = null) { return sServiceManager; // if the Binder object accessed by the service_manager process is empty, create one. // Find the service manager sServiceManager = ServiceManagerNative .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); return sServiceManager; } /** * Returns a reference to a service with the given name. * * @param name the name of the service to get * @return a reference to the service, or <code>null</code> if the service doesn't exist */ public static IBinder getService(String name) { try { // IBinder service = scache.get (name); if (service ! = null) { return service; Return binder.allowblocking (getIServiceManager().getService(name)); return binder.allowblocking (getIServiceManager().getService(name)); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; } /** * Returns a reference to a service with the given name, or throws * {@link NullPointerException} if none is found. * * @hide */ public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException { final IBinder binder = getService(name); if (binder ! = null) { return binder; } else { throw new ServiceNotFoundException(name); } } /** * Place a new @a service called @a name into the service * manager. * * @param name the name of the new service * @param service the service object */ public static void addService(String name, IBinder service) {try {// Register the service with the Service_manager process for unified management. GetIServiceManager ().addService(name, service, false); } catch (RemoteException e) { Log.e(TAG, "error in addService", e); } } /** * Place a new @a service called @a name into the service * manager. * * @param name the name of the new service * @param service the service object * @param allowIsolated set to true to allow isolated sandboxed processes * to access this service */ public static void addService(String name, IBinder service, boolean allowIsolated) { try { getIServiceManager().addService(name, service, allowIsolated); } catch (RemoteException e) { Log.e(TAG, "error in addService", e); } } /** * Retrieve an existing service called @a name from the * service manager. Non-blocking. */ public static IBinder checkService(String name) { try { IBinder service = sCache.get(name); if (service ! = null) { return service; } else { return Binder.allowBlocking(getIServiceManager().checkService(name)); } } catch (RemoteException e) { Log.e(TAG, "error in checkService", e); return null; } } /** * Return a list of all currently running services. * @return an array of all currently running services, or <code>null</code> in * case of an exception */ public static String[] listServices() { try { // Return getIServiceManager().listServices(); } catch (RemoteException e) { Log.e(TAG, "error in listServices", e); return null; } } /** * This is only intended to be called when the process is first being brought * up and bound by the activity manager. There is only one thread in the process * at that time, so no locking is done. * * @param cache the cache of service references * @hide */ public static void initServiceCache(Map<String, IBinder> cache) { if (sCache.size() ! = 0) { throw new IllegalStateException("setServiceCache may only be called once"); } sCache.putAll(cache); } /** * Exception thrown when no service published for given name. This might be * thrown early during boot before certain services have published * themselves. * * @hide */ public static class ServiceNotFoundException extends Exception { public ServiceNotFoundException(String name) { super("No service published for: " + name); }}}Copy the code