前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何实现一个 System Services?

如何实现一个 System Services?

作者头像
吴小龙同學
发布2021-12-20 10:06:29
9920
发布2021-12-20 10:06:29
举报
文章被收录于专栏:吴小龙同學吴小龙同學

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

System Service 是如何写的?

应用调用

123

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

看下 getSystemService 方法,在 Context 类里。

Context#getSystemService

123456789

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

1234

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

继续跟 SystemServiceRegistry.getSystemServiceName。

SystemServiceRegistry#getSystemServiceName

1234567891011

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 的?

1234567891011121314151617

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

123

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

mGlobal 是 DisplayManagerGlobal 对象。

DisplayManagerGlobal#setTemporaryBrightness

123456789101112131415161718192021222324

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 的几个接口。

123456789101112131415161718192021

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 内部类。

12345678910111213141516

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 里面:

1234567891011121314151617

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

先上图:

123456789101112131415161718192021222324252627282930313233343536

@startumltitle \n如何实现一个 System Services?\nskinparam backgroundColor #EEEBDCskinparam handwritten truehide empty descriptionstate 1.编写AIDL文件1.编写AIDL文件 --> 2.Context定义变量1.编写AIDL文件:IWuXiaolongManager.aidl2.Context定义变量 --> 3.编写系统服务类2.Context定义变量:String WUXIAOLONG_SERVICE = "wuxiaolong"note left of 2.Context定义变量 : 执行make update-api,\n更新接口3.编写系统服务类 --> 4.注册系统服务类3.编写系统服务类:WuXiaolongManagerService.java4.注册系统服务类--> 5.编写Manager类note right of 4.注册系统服务类 涉及SELinux权限end note5.编写Manager类 --> 6.注册Managernote right of 5.编写Manager类 1.写成单例 2.@Nullable注解end note5.编写Manager类:WuXiaolongManager.java6.注册Manager --> 7.应用调用@enduml

1.编写 AIDL 文件

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

123456

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

2.Context 定义变量

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

1

public static final String WUXIAOLONG_SERVICE = "wuxiaolong";

3.编写系统服务

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

12345678910111213141516171819

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

1234567891011

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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061

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

1234567891011

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

12

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

8.解决报错

编译报错
  • 报错 1:

12345678910111213

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

12345678910111213141516171819202122232425

diff --git a/api/current.txt b/api/current.txtindex 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

12345678910111213141516171819202122232425

diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txtindex 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:

1

[0mManagers must always be obtained from Context; no direct constructors [ManagerConstructor]

编写 Manager 类需写成单例。

  • 报错 3:

1

Missing nullability on method `getName` return [MissingNullability]

getName 方法加上@Nullable注解。

运行报错

1234567891011121314151617181920

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=104-08 15:41:38.802 12717 12758 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: PowerManagerService04-08 15:41:38.802 12717 12758 E AndroidRuntime: java.lang.IllegalStateException: android.os.ServiceManager$ServiceNotFoundException: No service published for: wuxiaolong04-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: wuxiaolong04-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 权限,可执行:

123

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

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

最后 Log 打印如下:

1234

Line 832: 04-08 16:08:55.290 17649 17690 D wxl : SystemServiceRegistry registerServiceLine 833: 04-08 16:08:55.290 17649 17690 D wxl : WuXiaolongManager getInstanceLine 835: 04-08 16:08:55.292 17649 17690 D wxl : WuXiaolongManager getNameLine 836: 04-08 16:08:55.293 17649 17690 D wxl : Name=WuXiaolong..

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • System Service 是如何写的?
    • 应用调用
      • Context#getSystemService
        • ContextImpl#getSystemService
          • SystemServiceRegistry#getSystemServiceName
            • DisplayManager#setTemporaryBrightness
              • DisplayManagerGlobal#setTemporaryBrightness
                • IDisplayManager
                  • SystemServer
                  • 如何写个 System Service
                    • 1.编写 AIDL 文件
                      • 2.Context 定义变量
                        • 3.编写系统服务
                          • 4.注册系统服务
                            • 5.编写 Manager 类
                              • 6.注册 Manager
                                • 7.应用调用
                                  • 8.解决报错
                                    • 编译报错
                                    • 运行报错
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档