Android系统服务分析与Native Service实例

Posted Tr0e

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android系统服务分析与Native Service实例相关的知识,希望对你有一定的参考价值。

文章目录

前言

在前面的文章中:基于AIDL编程实现Android远程Service服务 介绍了如何在 android 中通过 AIDL 实现远程服务,然而并未将自定义的远程服务注册为系统服务(System Service)。Android 为用户提供的很多功能是通过系统服务实现的,本文将学习记录下 Android 系统服务的相关知识,同时学习下远程服务除了使用 ALDL 编写的 Java 层服务外,还存在的另一种形式——Native Service。

System Service

使用命令 adb shell service list 即可列出当前 Android 系统的系统服务列表信息:

下面先来了解下 System Java Service 是如何定义和生成的,参考文章:Android系统服务(SystemService)简介

Vibrator 服务分析

我们从一个简单的系统服务 Vibrator 服务(vibrator: [android.os.IVibratorService])来看一下一个系统服务是怎样建立的。Vibrator 服务提供的控制手机振动的接口,应用可以调用 Vibrator 的接口来让手机产生振动,达到提醒用户的目的。

从 Android 的官方文档中可以看到 Vibrator 只是一个抽象类,只有4个抽象接口:

abstract void cancel() 取消振动
abstract boolean hasVibrator() 是否有振动功能
abstract void vibrate(long[] pattern, int repeat) 按节奏重复振动
abstract void vibrate(long milliseconds) 持续振动

1、应用中使用振动服务的方法也很简单,如让手机持续振动500毫秒:

Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);

2、从文档中可以看到 Vibrator 只是定义在 android.os 包里的一个抽象类,在源码里的位置即frameworks/base/core/java/android/os/Vibrator.java,那么应用中实际使用的是哪个实例呢?应用中使用的 Vibrator 实例是通过 Context 的一个方法getSystemService(Context.VIBRATOR_SERVICE)获得的,而 Context 的实现一般都在 ContextImpl 中,那我们就看一下 ContextImpl 是怎么实现 getSystemService 的:

// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Object getSystemService(String name) 
    return SystemServiceRegistry.getSystemService(this, name);

3、SystemServiceRegistry 是 Android 6.0 之后才有的,Android 6.0 之前的代码没有该类,下面的代码是直接写在 ContextImpl 里的:

//frameworks/base/core/java/android/app/SystemServiceRegistry.java
 public static Object getSystemService(ContextImpl ctx, String name) 
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;

4、SYSTEM_SERVICE_MAP 是一个 HashMap,通过我们服务的名字 name 字符串,从这个 HashMap 里取出一个 ServiceFetcher,再 return 这个 ServiceFetcher 的 getService()。ServiceFetcher 是什么?它的 getService()又是什么?既然他是从 SYSTEM_SERVICE_MAP 这个 HashMap 里 get 出来的,那就找一找这个 HashMap 都 put 了什么。通过搜索 SystemServiceRegistry 可以找到如下代码:

private static <T> void registerService(String serviceName, Class<T> serviceClass,
        ServiceFetcher<T> serviceFetcher) 
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);

5、这里往 SYSTEM_SERVICE_MAP 里 put 了一对 String 与 ServiceFetcher 组成的 key/value 对,registerService() 又是从哪里调用的?继续搜索可以发现很多类似下面的代码:

static 
    registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
            new CachedServiceFetcher<AccessibilityManager>() 
        @Override
        public AccessibilityManager createService(ContextImpl ctx) 
            return AccessibilityManager.getInstance(ctx);
        );

    ...
    registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
            new CachedServiceFetcher<Vibrator>() 
        @Override
        public Vibrator createService(ContextImpl ctx) 
            return new SystemVibrator(ctx);
        );
    ...

6、SystemServiceRegistry 的 static 代码块里通过 registerService 注册了很多的系统服务,其中就包括我们正在调查的VIBRATOR_SERVICE,通过结合上面的分析代码可以可以知道getSystemService(Context.VIBRATOR_SERVICE)得到的是一个 SystemVibrator 的实例,通过查看 SystemVibrator 的代码也可以发现 SystemVibrator 确实是继承自 Vibrator:

public class SystemVibrator extends Vibrator 
    ...

7、我们再从 SystemVibrator 看一下系统的振动控制是怎么实现的。以 hasVibrator() 为例,这个是查询当前系统是否能够振动,在 SystemVibrator 中它的实现如下:

public boolean hasVibrator() 
    ...
    try 
        return mService.hasVibrator();
     catch (RemoteException e) 
    
    ...

8、这里直接调用了一个 mService.hasVibrator(),那 mService 是什么?哪来的?搜索一下可以发现:

private final IVibratorService mService;
public SystemVibrator() 
    ...
    mService = IVibratorService.Stub.asInterface(
            ServiceManager.getService("vibrator"));

9、mService 是一个 IVibratorService,我们先不去管IVibratorService.Stub.asInterface是怎么回事,先看一下 IVibratorService 是什么。搜索一下代码发现这并不是一个 java 文件,而是一个 aidl 文件:

frameworks/base/core/java/android/os/IVibratorService.aidl

AIDL (Android Interface Definition Language) 是Android中的接口定义文件,为系统提供了一种简单跨进程通信方法。IVibratorService 中定义了几个接口,SystemVibrator中使用的也是这几个接口,包括我们刚才使用的hasVibrator():

interface IVibratorService

    boolean hasVibrator();
    void vibrate(...);
    void vibratePattern(...);
    void cancelVibrate(IBinder token);

10、这里又只是接口定义,接口实现在哪呢?通过在 frameworks/base 目录下进行 grep 搜索,或者在 AndroidXRef 搜索,可以发现 IVibratorService 接口的实现在frameworks/base/services/java/com/android/server/VibratorService.java

public class VibratorService extends IVibratorService.Stub

11、可以看到 VibratorService 实现了 IVibratorService 定义的所有接口,并通过 JNI 调用到 native 层,进行更底层的实现。更底层的实现不是这篇文档讨论的内容,我们需要分析的是 VibratorService 怎么成为系统服务的。那么 VibratorService 是怎么注册为系统服务的呢?在 SystemServer 里面:

VibratorService vibrator = null;
...
//实例化VibratorService并添加到ServiceManager
traceBeginAndSlog("StartVibratorService");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
...
//通知服务系统启动完成
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
try 
    vibrator.systemReady();
 catch (Throwable e) 
    reportWtf("making Vibrator Service ready", e);

Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

这样在 SystemVibrator 里就可以通过下面的代码连接到 VibratorService,与底层的系统服务进行通信了:

IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));

mService 相当于 IVibratorService 在应用层的一个代理,所有的实现还是在 SystemServer 的 VibratorService 里。看代码时可以发现 registerService 是在 static 代码块里静态调用的,所以 getSystemServcr 获得的各个 Manager 也都是单例的。

系统服务实现流程

画个图归纳如下:

从上面的分析,我们可以总结出 Vibrator 服务的整个实现流程:

1、定义一个抽象类 Vibrator,定义了应用中可以访问的一些抽象方法:
frameworks/base/core/java/android/os/Vibrator.java;

2、定义具体的类 SystemVibrator 继承 Vibrator,实现抽象方法:
frameworks/base/core/java/android/os/SystemVibrator.java;

3、定义一个 AIDL 接口文件 IVibratorService,定义系统服务接口:
frameworks/base/core/java/android/os/IVibratorService.aidl

4、定义服务 VibratorService,实现 IVibratorService 定义的接口:
frameworks/base/services/java/com/android/server/VibratorService.java

public class VibratorService extends IVibratorService.Stub

5、将VibratorService添加到系统服务:
frameworks/base/services/java/com/android/server/SystemServer.java

VibratorService vibrator = null;
...
//实例化VibratorService并添加到ServiceManager
Slog.i(TAG, "Vibrator Service");
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
...
//通知服务系统启动完成
try 
    vibrator.systemReady();
 catch (Throwable e) 
    reportWtf("making Vibrator Service ready", e);

6、在 SystemVibrator 中通过 IVibratorService 的代理连接到 VibratorService,这样 SystemVibrator 的接口实现里就可以调用 IVibratorService 的接口:
frameworks/base/core/java/android/os/SystemVibrator.java

private final IVibratorService mService;
...
public SystemVibrator() 
    ...
    mService = IVibratorService.Stub.asInterface(
            ServiceManager.getService("vibrator"));
    ...
    public boolean hasVibrator() 
        ...
        try 
            return mService.hasVibrator();
         catch (RemoteException e) 
        
        ...
    

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

public static final String VIBRATOR_SERVICE = "vibrator";

8、在 ContextImpl 里添加 SystemVibrator 的实例化过程:
frameworks/base/core/java/android/app/ContextImpl.java

registerService(VIBRATOR_SERVICE, new ServiceFetcher() 
public Object createService(ContextImpl ctx) 
    return new SystemVibrator(ctx);
);  

9、在应用中使用 Vibrator 的接口:

Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);

10、为保证编译正常,还需要将 AIDL 文件添加到编译配置里frameworks/base/Android.mk

LOCAL_SRC_FILES += \\
...
core/java/android/os/IVibratorService.aidl \\

Native Service

Android 系统服务大致分为三大类:本地守护进程、Native 系统服务和 Java 系统服务,如下图所示:

本地守护进程

init 进程根据 init.rc 文件中的定义,启动本地守护进程。这些进程会常驻在系统中,有的只会启动一次,有的如果退出了,还会被 init 启动。具体的启动方式就在 init.rc 中定义。下面大体列举几个守护进程及其功能。

Native系统服务

Native Service,这是 Android 系统里的一种特色,就是通过 C++ 或是 C 代码写出来的、供 Java 进行远程调用的 Remote Service,因为C/C++代码生成的是Native代码(机器代码),于是叫 Native Service。Java语言不能直接进行系统调用,必须透过 JNI 来调用 C 代码来访问系统功能,而 Native Service 则完全不同,C++具备直接进行系统调用的能力,于是在访问操作系统或是硬件功能时,不再需要 JNI,可以直接进行调用,代码实现上会更加统一。显然 Native 代码比 Java 这种解释型语言高得多的执行效率,随着 Android 系统的性能需求越来越高,Native Service 需求将越来越高。

Native Service 运行在本地守护进程中,比如 mediaserver 守护进程中就包含 AudioFlinger、MediaPlayerService、CameraService、AudioPolicyService和SoundTriggerHwService 等服务。在 mediaserver 进程的 main 函数中,初始化这些服务的实例,代码如下:

int main(int argc __unused, char** argv)

    ...
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ALOGI("ServiceManager: %p", sm.get());
    AudioFlinger::instantiate();
    MediaPlayerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();
    SoundTriggerHwService::instantiate();
    ...
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

在所属进程初始化的时候会将 Native 系统服务注册到 ServiceManager 中。这样,其他的应用或服务就可以通过 binder 机制调用 Native 系统服务了。当然,我们也可以自己开发一个 Native 系统服务,实现其 Binder 接口,这样 Native 层的其他应用或服务就可以调用该服务了。如果我们开发的 Native 系统服务想提供给 Java 层应用使用,就需要实现一个 Java 接口,然后通过 JNI 调用 Native 系统服务


与 Java 类型的 System Service 中的 Stub.Proxy 对象的实现相对应,Native Service 也会定义 BpXXX 对象,其中B代表Binder,p代码Proxy,所需要的接口名为XXX。因为所需要发送的Binder通信都是经由 BpBinder::transact() 方法发送,于是Java环境与Native环境的Proxy在本质上是一回事,只是提供不同编程语言环境里的不同实现而已。同时,在接收与处理端, IPCThreadState 对象回调到 BBinder 引用的 onTransact() 时,此时的 BBinder 引用的并不再是一个 JavaBBinder 对象,而是拓展出来的 BnXXX 对象,n代表Native。于是 BBinder::transact() 就会直接调用 BnXXX 里实现的 onTransact(),在这一 onTransact() 方法里就可以处理 Binder 消息,并将结果返回。

蓝牙设置实例

Demo 项目结构如下:

IDeviceMac.h接口文件

通过一个读取和设置蓝牙地址的例子为例,接口名为 IDeviceMac, 代码如下:

#ifndef XTC_IDEVICEMAC_H
#define XTC_IDEVICEMAC_H

#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#include <android/log.h>

#ifdef TAG
#undef TAG
#endif
#define TAG "DeviceMac"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)

namespace android 

class IDeviceMac : public IInterface 
public:
    enum 
        SET_BT_MAC = IBinder::FIRST_CALL_TRANSACTION,
        GET_BT_MAC,
    ;

    virtual int setBTMac(String8 bt) = 0;

    virtual String8 getBTMac() = 0;

    DECLARE_META_INTERFACE(DeviceMac);
;

class BnDeviceMac : public BnInterface<IDeviceMac> 
public:
    virtual status_t onTransact( uint32_t code,
                                const Parcel& data,
                                Parcel* reply,
                                uint32_t flags);
;
   
 // end namespace android
#endif

以上代码很简单:

  1. 定义一个 IDeviceMac 类继承自接口类IInterface( IInterface 跟Java环境一下,可用于提供 asBinder() 方法,返回一个IBinder引用), IDeviceMac 类里定义了对外提供的服务接口(如setBTMac()、getBTMac());
  2. 同时注意到DECLARE_META_INTERFACE(DeviceMac);是一个宏定义,用来定义继承IInterface必须实现的两个方法,asInterface()函数和 getInterfaceDescriptor() 函数;
  3. Java 环境里的 IBinder 会有 asInterface() 接口方法,在 libbinder 里通过 C++ 实现的 IBinder 则不能提供这一接口,于是需要通过一个全局有效的 interface_cast() 宏来完成这一功能,interface_cast() 是调用一个尚未定义的 INTERFACE::asInterface() 宏,于是只会在有明确定义 asInterface() 的地方,interface_cast() 才会有效;
  4. 可以看到我们定义IDeviceMac后,还定义了一个类BnDeviceMac,这个是Binder调用的一个规范,即定义Ixxx接口后,Bpxxx表示Client端接口,Bnxxx表示Service端接口, BpxxxBnxxx都需要我们去实现具体内容,并且BnxxxBpxxx中的方法和Ixxx中的方法是一一对应的。

IDeviceMac.cpp接口实现文件

接下来继续编写 IDeviceMac.cpp 文件:

#include "IDeviceMac.h"

namespace android 

class BpDeviceMac : public BpInterface<IDeviceMac> 

public:
    BpDeviceMac(const sp<IBinder>& impl) : BpInterface<IDeviceMac>(impl)
    
    

    int setBTMac(String8 bt) 
        LOGI("Bp setBT");
        Parcel data, reply;
        data.writeInterfaceToken(IDeviceMac::getInterfaceDescriptor());
        data.writeString8(bt);
        remote()->transact(SET_BT_MAC, data, &reply);
        return reply.readInt32();
    

    String8 getBTMac() 
        LOGI("Bp getBT");
        Parcel data, reply;
        data.writeInterfaceToken(IDeviceMac::getInterfaceDescriptor());
        remote()->transact(GET_BT_MAC, data, &reply);
        return reply.readString8();
    
;

IMPLEMENT_META_INTERFACE(DeviceMac, "DeviceMac");
/* Macro above expands to code below.
const android::String16 IDeviceMac::descriptor("DeviceMac");
const android::String16& IDeviceMac::getInterfaceDescriptor() const 
    return IDeviceMac::descriptor;

android::sp<IDeviceMac> IDeviceMac::asInterface(const android::sp<android::IBinder>& obj) 
    android::sp<IDeviceMac> intr;
    if (obj != NULL) 
        intr = static_cast<IDeviceMac*>(obj->queryLocalInterface(IDeviceMac::descriptor).get());
        if (intr == NULL) 
            intr = new BpDeviceMac(obj);
        
    
    return intr;

*/

status_t BnDeviceMac::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 
    CHECK_INTERFACE(IDeviceMac, data, reply);
    LOGI("Bn onTransact code:%d", code);
    switch(code) 
        case SET_BT_MAC:
            reply->writeInt32(setBTMac(data.readString8()));
            return NO_ERROR;
        case GET_BT_MAC:
            reply->writeString8(getBTMac());
            return NO_ERROR;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    


 // end namespace android

代码简单解读:

  1. 上面代码中IMPLEMENT_META_INTERFACE(DeviceMac, "DeviceMac");下面注释掉的内容就是这个宏定义代表的实际代码,也是就是说IDeviceMac.h中的那个宏定义其实就是定义这两个方法;
  2. BpDeviceMac 里面的内容就是把相关参数写到Parcel中,这是一个用来读写跨进程参数的类, 然后调用remote()->transact(), 就调用到BnDeviceMac::onTransact()中,BnDeviceMac::onTransact()函数中已经跨过进程了,具体怎么做到的就涉及到 IPC 原理了,这里不做讨论;
  3. 接下来定义的 BnDeviceMac::onTransact 做的事情也很简单,就是从Parcel中将Client传过来的数据读出来,然后调用BnDeviceMac中对应的实现方法,这里需要注意,由于BnDeviceMac::onTransact()代码和BpDeviceMac写在了同一个文件中,看起来有点像BnDeviceMac调用BpDeviceMac的 一样,其实是BnDeviceMac::onTranscat()中调用的setBTMac() getBTMac()是在调用BnDeviceMac中实现的方法, 接下来就讲BnDeviceMac的实现。

DeviceMacService服务实现文件

1、DeviceMacService.h 如下:

#以上是关于Android系统服务分析与Native Service实例的主要内容,如果未能解决你的问题,请参考以下文章

Android系统服务分析与Native Service实例

Android -- Audio Native服务之启动流程分析

React Native之通知栏消息提示(android)

Android Binder 框架层详解

Android 分析Native库的加载过程及x86系统运行arm库的原理

Flutter如何与Native(Android)进行交互