Byte Two Sides: How to Implement a System Services

How is System Service written?

application call

 DisplayManager dm = getSystemService(DisplayManager.class);
 dm.setTemporaryBrightness(0.0f);
 Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);

Look at the getSystemService method, in the Context class.

Context#getSystemService

public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
    // Because subclasses may override getSystemService(String) we cannot
    // perform a lookup by class alone.  We must first map the class to its
    // service name then invoke the string-based method.
    String serviceName = getSystemServiceName(serviceClass);
    return serviceName != null ? (T)getSystemService(serviceName) : null;
}
 
public abstract @Nullable String getSystemServiceName(@NonNull Class<?> serviceClass);

ContextImpl#getSystemService

@Override
public String getSystemServiceName(Class<?> serviceClass) {
    return SystemServiceRegistry.getSystemServiceName(serviceClass);
}

Continue with SystemServiceRegistry.getSystemServiceName.

SystemServiceRegistry#getSystemServiceName

public static String getSystemServiceName(Class<?> serviceClass) {
    if (serviceClass == null) {
        return null;
    }
    final String serviceName = SYSTEM_SERVICE_NAMES.get(serviceClass);
    if (sEnableServiceNotFoundWtf && serviceName == null) {
        // This should be a caller bug.
        Slog.wtf(TAG, "Unknown manager requested: " + serviceClass.getCanonicalName());
    }
    return serviceName;
}

When is registerService?

public final class SystemServiceRegistry {
    static {
        registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
        new CachedServiceFetcher<DisplayManager>() {
            @Override
            public DisplayManager createService(ContextImpl ctx) {
                return new DisplayManager(ctx.getOuterContext());
            }
        });
    }
}
private static <T> void registerService(@NonNull String serviceName,
        @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
}

Combined with the analysis code above, we can know that what getSystemService(DisplayManager.class) gets is an instance of DisplayManager.

Next, look at the dm.setTemporaryBrightness method.

DisplayManager#setTemporaryBrightness

public void setTemporaryBrightness(float brightness) {
    mGlobal.setTemporaryBrightness(brightness);
}

mGlobal is a DisplayManagerGlobal object.

DisplayManagerGlobal#setTemporaryBrightness

private final IDisplayManager mDm;
 
private DisplayManagerGlobal(IDisplayManager dm) {
    mDm = dm;
}
 
public static DisplayManagerGlobal getInstance() {
    synchronized (DisplayManagerGlobal.class) {
        if (sInstance == null) {
            IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
            if (b != null) {
                sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
            }
        }
        return sInstance;
    }
}
public void setTemporaryBrightness(float brightness) {
    try {
        mDm.setTemporaryBrightness(brightness);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

mDm is the IDisplayManager object, initialized in IDisplayManager.Stub.asInterface(ServiceManager.getService(Context.DISPLAY_SERVICE)), see that IDisplayManager is an aidl file: frameworks/base/core/java/android/hardware/display/IDisplayManager.aidl, AIDL (Android Interface Definition Language) is the interface definition file in Android, for The system provides a simple cross-process communication method, regardless of AIDL.

iDisplayManager

IDisplayManager defines several interfaces including setTemporaryBrightness.

interface IDisplayManager {
    //……
    void registerCallback(in IDisplayManagerCallback callback);
 
    // Requires CONFIGURE_WIFI_DISPLAY permission.
    // The process must have previously registered a callback.
    void startWifiDisplayScan();
 
    // Requires CONFIGURE_WIFI_DISPLAY permission.
    void stopWifiDisplayScan();
 
    // Requires CONFIGURE_WIFI_DISPLAY permission.
    void connectWifiDisplay(String address);
 
    // No permissions required.
    void disconnectWifiDisplay();
 
    // Temporarily sets the display brightness.
    void setTemporaryBrightness(float brightness);
    //……
}

IDisplayManager is just an interface. You need to find where it is implemented. The search is in BinderService, which is the internal class of DisplayManagerService.

final class BinderService extends IDisplayManager.Stub {
    @Override // Binder call
    public void setTemporaryBrightness(float brightness) {
        mContext.enforceCallingOrSelfPermission(
                Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
                "Permission required to set the display's brightness");
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mSyncRoot) {
                mDisplayPowerController.setTemporaryBrightness(brightness);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }
}
 

mDisplayPowerController.setTemporaryBrightness(brightness)Later, after a series of calls, it will go to LightsService#setLight_native, call to the native layer through JNI, and call the bottom layer to adjust the backlight. The article will elaborate on the backlight adjustment later.

SystemServer

DisplayManagerService inherits SystemService, how does DisplayManagerService register as a system service? Inside SystemServer:

private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
    t.traceBegin("StartDisplayManager");
    //开启DisplayManagerService
    mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
    t.traceEnd();
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    //通知服务系统启动完成
    t.traceBegin("MakeDisplayManagerServiceReady");
    try {
        // TODO: use boot phase and communicate these flags some other way
        mDisplayManagerService.systemReady(safeMode, mOnlyCore);
    } catch (Throwable e) {
        reportWtf("making Display Manager Service ready", e);
    }
    t.traceEnd();
}

After reading how DisplayManagerService is written, you may wish to imitate it. The so-called looking at the code, it feels quite simple, but in actual operation, various compilation errors are reported...

How to write a System Service

First picture:

1. Write the AIDL file

Create new frameworks/base/core/java/android/hardware/wuxiaolong/IWuXiaolongManager.aidl, the content is as follows:

package android.hardware.wuxiaolong;
/** @hide */
interface IWuXiaolongManager {
 
    String getName();
}

2.Context defines variables

Define a string frameworks/base/core/java/android/content/Context.java representing wuxiaolong service in Context

public static final String WUXIAOLONG_SERVICE = "wuxiaolong";

3. Write system services

frameworks/base/services/core/java/com/android/server/wuxiaolong/WuXiaolongManagerService.java

package com.android.server.wuxiaolong;
 
import android.content.Context;
import android.hardware.wuxiaolong.IWuXiaolongManager;
 
public class WuXiaolongManagerService extends IWuXiaolongManager.Stub {
    private final Context mContext;
 
    public WuXiaolongManagerService(Context context) {
        super();
        mContext = context;
    }
 
    @Override
    public String getName() {
        String name = "WuXiaolong..";
        return name;
    }
}

4. Registration system service

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

import com.android.server.wuxiaolong.WuXiaolongManagerService;
private void startOtherServices() {
    // 部分代码省略...
    try {
        android.util.Log.d("wxl","SystemServer WuXiaolongManagerService");
        ServiceManager.addService(Context.WUXIAOLONG_SERVICE, new WuXiaolongManagerService(context));
    } catch (Throwable e) {
        reportWtf("starting WuXiaolongManagerService", e);
    }
    // 部分代码省略...
}

5. Write the Manager class

frameworks/base/core/java/android/hardware/wuxiaolong/WuXiaolongManager.java

 
package android.hardware.wuxiaolong;
 
import android.os.IBinder;
import android.os.ServiceManager;
import android.hardware.wuxiaolong.IWuXiaolongManager;
import android.content.Context;
import android.os.RemoteException;
import android.compat.annotation.UnsupportedAppUsage;
import android.annotation.Nullable;
import android.os.ServiceManager.ServiceNotFoundException;
import android.annotation.SystemService;
 
@SystemService(Context.WUXIAOLONG_SERVICE)
public class WuXiaolongManager {
    private static WuXiaolongManager sInstance;
    private final IWuXiaolongManager mService;
    private Context mContext;
 
    /**
     * @hide
     */
    public WuXiaolongManager(IWuXiaolongManager iWuXiaolongManager) {
        mService = iWuXiaolongManager;
    }
 
    /**
     * Gets an instance of the WuXiaolong manager.
     *
     * @return The WuXiaolong manager instance.
     * @hide
     */
    @UnsupportedAppUsage
    public static WuXiaolongManager getInstance() {
        android.util.Log.d("wxl", "WuXiaolongManager getInstance");
        synchronized (WuXiaolongManager.class) {
            if (sInstance == null) {
 
                try {
                    IBinder b = ServiceManager.getServiceOrThrow(Context.WUXIAOLONG_SERVICE);
                    sInstance = new WuXiaolongManager(IWuXiaolongManager.Stub
                            .asInterface(ServiceManager.getServiceOrThrow(Context.WUXIAOLONG_SERVICE)));
                } catch (ServiceNotFoundException e) {
                    throw new IllegalStateException(e);
                }
 
            }
            return sInstance;
        }
    }
 
    @Nullable
    public String getName() {
        android.util.Log.d("wxl", "WuXiaolongManager getName");
        try {
            return mService.getName();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

6. Register Manager

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

import android.hardware.wuxiaolong.WuXiaolongManager;
static {
    registerService(Context.WUXIAOLONG_SERVICE, WuXiaolongManager.class,
            new CachedServiceFetcher<WuXiaolongManager>() {
                @Override
                public WuXiaolongManager createService(ContextImpl ctx)
                        throws ServiceNotFoundException {
                    android.util.Log.d("wxl","SystemServiceRegistry registerService");
                    return WuXiaolongManager.getInstance();
                }});
}

7. Application call

WuXiaolongManager mWuXiaolongManager = (WuXiaolongManager)mContext.getSystemService(Context.WUXIAOLONG_SERVICE);
android.util.Log.d("wxl","Name="+ mWuXiaolongManager.getName());

8. Solve the error

compile error

  • Error 1:
******************************
You have tried to change the API from what has been previously approved.
 
To make these errors go away, you have two choices:
   1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)
      to the new methods, etc. shown in the above diff.
 
   2. You can update current.txt and/or removed.txt by executing the following command:
         make api-stubs-docs-non-updatable-update-current-api
 
      To submit the revised current.txt to the main Android repository,
      you will need approval.
******************************

You need to execute make update-api to update the interface, and there will be more:

frameworks/base/api/current.txt

diff --git a/api/current.txt b/api/current.txt
index 6b1a96c..0779378 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -10256,6 +10256,7 @@ package android.content {
     field public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
     field public static final String WIFI_SERVICE = "wifi";
     field public static final String WINDOW_SERVICE = "window";
+    field public static final String WUXIAOLONG_SERVICE = "wuxiaolong";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -18318,6 +18319,14 @@ package android.hardware.usb {
 
 }
 
+package android.hardware.wuxiaolong {
+
+  public class WuXiaolongManager {
+    method @Nullable public String getName();
+  }
+
+}
+
 package android.icu.lang {

frameworks/base/non-updatable-api/current.txt

diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index adf1bb5..e738c02 100755
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -10256,6 +10256,7 @@ package android.content {
     field public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
     field public static final String WIFI_SERVICE = "wifi";
     field public static final String WINDOW_SERVICE = "window";
+    field public static final String WUXIAOLONG_SERVICE = "wuxiaolong";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -18318,6 +18319,14 @@ package android.hardware.usb {
 
 }
 
+package android.hardware.wuxiaolong {
+
+  public class WuXiaolongManager {
+    method @Nullable public String getName();
+  }
+
+}
+
 package android.icu.lang {
  • Error 2:
[0mManagers must always be obtained from Context; no direct constructors [ManagerConstructor]

The Manager class needs to be written as a singleton.

  • Error 3:
Missing nullability on method `getName` return [MissingNullability]

The getName method is @Nullableannotated.

run error

04-08 15:41:38.798   297   297 E SELinux : avc:  denied  { find } for pid=12717 uid=1000 name=wuxiaolong scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=1
04-08 15:41:38.802 12717 12758 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: PowerManagerService
04-08 15:41:38.802 12717 12758 E AndroidRuntime: java.lang.IllegalStateException: android.os.ServiceManager$ServiceNotFoundException: No service published for: wuxiaolong
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.hardware.wuxiaolong.WuXiaolongManager.getInstance(WuXiaolongManager.java:47)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.app.SystemServiceRegistry$27.createService(SystemServiceRegistry.java:497)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.app.SystemServiceRegistry$27.createService(SystemServiceRegistry.java:493)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.app.SystemServiceRegistry$CachedServiceFetcher.getService(SystemServiceRegistry.java:1760)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.app.SystemServiceRegistry.getSystemService(SystemServiceRegistry.java:1440)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.app.ContextImpl.getSystemService(ContextImpl.java:1921)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at com.android.server.display.DisplayPowerController.updatePowerState(DisplayPowerController.java:1191)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at com.android.server.display.DisplayPowerController.access$700(DisplayPowerController.java:92)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at com.android.server.display.DisplayPowerController$DisplayControllerHandler.handleMessage(DisplayPowerController.java:2074)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:106)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:223)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.os.HandlerThread.run(HandlerThread.java:67)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at com.android.server.ServiceThread.run(ServiceThread.java:44)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: Caused by: android.os.ServiceManager$ServiceNotFoundException: No service published for: wuxiaolong
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.os.ServiceManager.getServiceOrThrow(ServiceManager.java:153)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	at android.hardware.wuxiaolong.WuXiaolongManager.getInstance(WuXiaolongManager.java:40)
04-08 15:41:38.802 12717 12758 E AndroidRuntime: 	... 12 more

Here is the executable without SELinux permissions:

adb shell
setenforce 0 (临时禁用掉SELinux)
getenforce  (得到结果为Permissive)

Temporarily disable SELinux, and the function will be normal. I won’t talk about SELinux here, and I will have a chance to write an SELinux article later.

The final Log is printed as follows:

Line 832: 04-08 16:08:55.290 17649 17690 D wxl     : SystemServiceRegistry registerService
Line 833: 04-08 16:08:55.290 17649 17690 D wxl     : WuXiaolongManager getInstance
Line 835: 04-08 16:08:55.292 17649 17690 D wxl     : WuXiaolongManager getName
Line 836: 04-08 16:08:55.293 17649 17690 D wxl     : Name=WuXiaolong..

Guess you like

Origin blog.csdn.net/xiaowang_lj/article/details/132089225