如何实现一个 System Services?

Posted 吴小龙同學

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何实现一个 System Services?相关的知识,希望对你有一定的参考价值。

Android 系统开发做什么?》写到 android System Services 是专注于特定功能的模块化组件,应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件。Android System Services 是如何写的?来以 DisplayManagerService 为例,具体来看看。

System Service 是如何写的?

应用调用

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

看下 getSystemService 方法,在 Context 类里。

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);


继续跟 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;


什么时候 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());

结合上面的分析代码可以知道 getSystemService(DisplayManager.class)得到的是一个 DisplayManager 的实例。

接下来看 dm.setTemporaryBrightness 方法。

DisplayManager#setTemporaryBrightness

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

mGlobal 是 DisplayManagerGlobal 对象。

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 是 IDisplayManager 对象,初始化在IDisplayManager.Stub.asInterface(ServiceManager.getService(Context.DISPLAY_SERVICE)),看到 IDisplayManager 是一个 aidl 文件:frameworks/base/core/java/android/hardware/display/IDisplayManager.aidl,AIDL (Android Interface Definition Language) 是 Android 中的接口定义文件,为系统提供了一种简单跨进程通信方法,先不管 AIDL。

IDisplayManager

IDisplayManager 定义了包括 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 只是接口,需要找下哪里实现了它,搜索是在 BinderService,BinderService 是 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)后面经过一系列调用会到 LightsService#setLight_native,通过 JNI 调用到 native 层,调用底层进行背光调节,关于背光调节后面文章再细讲。

SystemServer

DisplayManagerService 是继承了 SystemService,DisplayManagerService 是怎么注册为系统服务的呢?在 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();

看完 DisplayManagerService 是怎么写的,不妨模仿写个。
所谓看着代码,感觉还是挺简单的,实际操作起来,各种编译报错……

如何写个 System Service

先上图:

1.编写 AIDL 文件

新建 frameworks/base/core/java/android/hardware/wuxiaolong/IWuXiaolongManager.aidl,内容如下:

package android.hardware.wuxiaolong;
/** @hide */
interface IWuXiaolongManager 

    String getName();

2.Context 定义变量

在 Context 里定义一个代表 wuxiaolong 服务的字符串
frameworks/base/core/java/android/content/Context.java

public static final String WUXIAOLONG_SERVICE = "wuxiaolong";

3.编写系统服务

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.注册系统服务

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.编写 Manager 类

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.注册 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.应用调用

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

8.解决报错

编译报错

  • 报错 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.
******************************

需要执行 make update-api,更新接口,会多出来:

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 
  • 报错 2:
[0mManagers must always be obtained from Context; no direct constructors [ManagerConstructor]

编写 Manager 类需写成单例。

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

getName 方法加上@Nullable注解。

运行报错

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.wuxiaolo

以上是关于如何实现一个 System Services?的主要内容,如果未能解决你的问题,请参考以下文章

如何实现一个 System Services?

如何实现一个 System Services?

System.Web.Services.Protocols.SoapException: 服务器未能识别 HTTP 头 SOAPAction 的值,此问题如何解决

为啥我无法反编译 System.IdentityModel.Services.dll?

Microsoft.Data.Services.Client.dll 与 System.Data.Services.Client.dll

System.Web.Services 无法添加到 Visual Studio 中的 VB.NET 项目中