Warning: Undefined array key "night" in /www/wwwroot/dhaomu.com/wp-content/themes/b2/header.php on line 18

如何实现一个 System Services?

如何实现一个 System Services?

如何实现一个 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

先上图:

如何实现一个 System Services?插图1

@startuml


title \n如何实现一个 System Services?\n


skinparam backgroundColor #EEEBDC
skinparam handwritten true

hide empty description



state 1.编写AIDL文件

1.编写AIDL文件 --> 2.Context定义变量
1.编写AIDL文件:IWuXiaolongManager.aidl
2.Context定义变量 --> 3.编写系统服务类
2.Context定义变量:String WUXIAOLONG_SERVICE = "wuxiaolong"
note left of 2.Context定义变量 : 执行make update-api,\n更新接口
3.编写系统服务类 --> 4.注册系统服务类
3.编写系统服务类:WuXiaolongManagerService.java
4.注册系统服务类--> 5.编写Manager类
note right of 4.注册系统服务类
  涉及SELinux权限
end note
5.编写Manager类 --> 6.注册Manager
note right of 5.编写Manager类
  1.写成单例
  2.@Nullable注解
end note
5.编写Manager类:WuXiaolongManager.java
6.注册Manager --> 7.应用调用


@enduml

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 权限够折腾半天了,这篇文章先就酱紫吧。

温馨提示:
1.本站大部分内容均收集于网络!若内容若侵犯到您的权益,请发送邮件至:duhaomu@163.com,我们将第一时间处理!
2.资源所需价格并非资源售卖价格,是收集、整理、编辑详情以及本站运营的适当补贴,并且本站不提供任何免费技术支持。
3.所有资源仅限于参考和学习,版权归原作者所有,更多请阅读网站声明

给TA赞赏
共{{data.count}}人
人已赞赏
未整理

台球教学视频,台球全系列学习视频教程

2021-5-15 0:00:00

未整理

易优cms橙色风格瑜伽垫用品订制厂家企业网站模板源码 带手机版

2021-5-17 0:00:00

0 条回复 A文章作者 M管理员

Warning: Trying to access array offset on value of type null in /www/wwwroot/dhaomu.com/wp-content/themes/b2/functions.php on line 3914

Warning: Trying to access array offset on value of type null in /www/wwwroot/dhaomu.com/wp-content/themes/b2/functions.php on line 3914
----《》
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索