The company plans to do customized development for Android system of the device. I have never done system development before, but I only know some basic knowledge, so now I am learning while doing.

System services are an important part of Android, such as ActivityManagerService (AMS), PackageManagerSersvice (PMS), WindowManagerService (WMS), These system services are key services in the Framework layer. This article takes a look at the complete process of adding a system service based on Android source code.

Write AIDL files

File location frameworks/base/core/Java/com/myservice /

IMyService.aidl

package android.myservice;

interface IMyService
{
	void setState(int value);
	void setName(String name);
	void setWhiteList(in List<String> list);
}
Copy the code

AIDL only supports the transfer of primitive Java type data. To pass a custom class, you need to implement the Parcelable interface. In addition, if you pass an array of primitive types, you need to specify the in out keyword, such as void test(in byte[] input, Out byte[] output), use in if the array is passed as an argument to the called end, use out if the array is only used to receive data, and the actual data is filled by the called end.

After the file is written, add it to the compiled Android.mk after LOCAL_SRC_FILES:

frameworks/base/Android.mk

LOCAL_SRC_FILES += \ core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \ core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \ The core/Java/android/accounts/IAccountManager aidl \ code omitted... Core/Java/com/myservice IMyService aidl \ code omitted...Copy the code

Manager class

Android ManagerServices are not directly accessible, and need to be operated through their client proxy class. We also write a proxy class for our Service.

frameworks/base/core/java/com/myservice/MyManager.java

package android.myservice;

import android.myservice.IMyService;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
import java.util.List;

public class MyManager {
    

    private final Context mContext;
    private final IMyService mService;

    public MyManager(Context context, IMyService sevice) {
        mContext = context;
        mService = sevice;
    }

    public void setState(int value){
        try {
            mService.setState(value);
        } catch(RemoteException e) { e.printStackTrace(); }}public void setName(String name){
        try {
            mService.setName(name);
        } catch(RemoteException e) { e.printStackTrace(); }}public void setWhiteList(List<String> list){
        try {
            mService.setWhiteList(list);
        } catch(RemoteException e) { e.printStackTrace(); }}}Copy the code

Writing system services

frameworks/base/services/core/java/com/android/server/myservice/MyService.java

package com.android.server.myservice;


import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import java.util.List;

import android.myservice.MyManager;
import android.myservice.IMyService;


public class MyService extends IMyService.Stub {


    private String TAG = "MyService";
    private Context mContext;

    public MyService(Context context) {
        mContext = context;
    }


    @Override
    public void setState(int value){
        Log.d(TAG,"setState:"+value);
       
    }

    @Override
	public void setName(String name){
        Log.d(TAG,"setName:"+name);
    }

    @Override
	public void setWhiteList(List<String> list){
        for(int i = 0; i<list.size(); i++){ Log.d(TAG,"setWhiteList:"+list.get(i)); }}}Copy the code

Registration system Services

Add system service constants to Context

frameworks/base/core/java/android/content/Context.java

/ * *@hide* /
    @StringDef({ POWER_SERVICE, WINDOW_SERVICE, LAYOUT_INFLATER_SERVICE, ... MY_SERVICE, //add ... HARDWARE_PROPERTIES_SERVICE, //@hide: SOUND_TRIGGER_SERVICE, SHORTCUT_SERVICE, //@hide: CONTEXTHUB_SERVICE, })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ServiceName {}
Copy the code
/**
     * Use with {@link #getSystemService} to retrieve a
     * {@link android.myservice.MyManager}.
     * @hide
     *
     * @see #getSystemService
     * @see android.myservice.MyManager
     */
    public static final String MY_SERVICE = "myservice";
Copy the code

All system services run in a process called system_server, and we need to add the written services to it. There are many services in SystemServer, so we add our system services to the end

frameworks/base/services/java/com/android/server/SystemServer.java

import com.android.server.myservice.MyService;

private void startOtherServices(a) {
     MyService myManagerService = null; .try{  
          myManagerService = new MyService(context);
		  Log.i("MyService"."In SystemServer, MyService add..");  
		  ServiceManager.addService(Context.MY_SERVICE, myManagerService);  
		} catch (Throwable e) {  
			Log.i("MyService"."In SystemServer, MyService add err.."+e); }}Copy the code

This time to reboot the machine, will report the following error, no permission

E/SELinux: avc:  denied  { add } for service=myservice pid=1743 uid=1000 scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=0
E/ServiceManager: add_service('myservice',5a) uid=1000 - PERMISSION DENIED
Copy the code

Add SELinux permissions

device/qcom/sepolicy/common/service.te

type myservice_service,      app_api_service, system_server_service, service_manager_type;

Copy the code

device/qcom/sepolicy/common/service_contexts

enrichrcsservice                               u:object_r:radio_service:s0
myservice           			               u:object_r:myservice_service:s0
Copy the code

Permissions can also be added to the system/sepolicy/service_contexts and system/sepolicy/service. The te, the effect is the same, but only can be added in one place, otherwise it will repeat.

Registration Manager

Context.getsystemservice () : context.getSystemService() : context.getSystemService() : context.getSystemService() : context.getSystemService() : context.getSystemService() : context.getSystemService() : context.getSystemService() : context.getSystemService(

frameworks/base/core/java/android/app/SystemServiceRegistry.java

import android.myservice.MyManager;
importandroid.myservice.IMyService; . registerService(Context.CONTEXTHUB_SERVICE, ContextHubManager.class,new CachedServiceFetcher<ContextHubManager>() {
            @Override
            public ContextHubManager createService(ContextImpl ctx) {
                return new ContextHubManager(ctx.getOuterContext(),
                  ctx.mMainThread.getHandler().getLooper());
            }});

// add MyManager
registerService(Context.MY_SERVICE, MyManager.class,
			new CachedServiceFetcher<MyManager>() {
				@Override
				public MyManager createService(ContextImpl ctx) {
					IBinder b = ServiceManager.getService(Context.MY_SERVICE);
					IMyService service = IMyService.Stub.asInterface(b);
					return new MyManager(ctx, service);
		}});
Copy the code

OK, system code modification is complete!

Boot. img and system.img can be compiled separately, with permission control in boot.img and code modification in system.img

After system startup

1970-01-13 04:01:02.700 1550-1550/system_process I/MyService: In SystemServer, MyService add..
Copy the code

If no error is reported, the startup is successful!

App call

Use context.getSystemService(” myService “) to retrieve the MyManager object and call the method in myService.

Client App:

Service:

Done!