zoukankan      html  css  js  c++  java
  • 如何实现一个 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.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
    

    这里是缺少 SELinux 权限,可执行:

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

    临时禁用掉 SELinux,功能就正常了,关于 SELinux 这里不说了,后面有机会写篇 SELinux 文章。

    最后 Log 打印如下:

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

    手写个 System Service 实践过后没那么简单,光 SELinux 权限够折腾半天了,这篇文章先就酱紫吧。

  • 相关阅读:
    PAT2019顶级7-2:美丽的序列(线段树+DP)
    ZOJ2112 Dynamic Rank(可持久化线段树套树状数组)
    CF1353E K-periodic Garland(动态规划)
    CF1353D Constructing the array(优先队列)
    HDU2069 Coin Change(基础DP)
    surf(树状数组+DP)
    双倍快乐(回文树)
    ZOJ3591 Nim(博弈论)
    HDU6601 Keep On EveryThing But Triangle(可持久化线段树)
    HDU6599 I Love Palindrome String(回文树)
  • 原文地址:https://www.cnblogs.com/WuXiaolong/p/14766263.html
Copyright © 2011-2022 走看看