android系统开发binder调用(C++和java相互调用)
阅读原文时间:2021年04月20日阅读:2

一、添加java端系统service

1.添加aidl文件

  • 在framework/base下面新建文件夹gateway/java/com/cns/android/gateway

创建IGatewaySystemService.aidl

    package com.cns.android.gateway;

    import com.cns.android.gateway.IGatewaySystemCallback;

    /**
     * {@hide}
     */

    interface IGatewaySystemService {
        //开启log
        void beginLog();
        //关闭log
        void endLog();
           //注册回调 
        void registerGatewaySystemCallbackCallback(IGatewaySystemCallback callback);
            //解除注册
        void unregisterGatewaySystemCallbackCallback(IGatewaySystemCallback callback);
    }
  • 创建回调aidl

        package com.cns.android.gateway;
            interface IGatewaySystemCallback{
            }
  • 创建Android.mk
    把aidl文件添加到framework/base/Android.mk中(这是我的aidl路径,具体的改成自己的)

        LOCAL_SRC_FILES += \
        \***
        ../../vendor/cns_gateway_utils/aidl/com/cns/android/gateway/IGatewaySystemService.aidl \
        ../../vendor/cns_gateway_utils/aidl/com/cns/android/gateway/IGatewaySystemCallback.aidl \

编译framework/base/Android.mk
系统编译的时候,会在out目录下生成对应的IGatewaySystemService.java、IGatewaySystemCallback.java文件

  • 修改build/make/core/pathmap.mk 不然会找不到可编译文件

        FRAMEWORKS_BASE_SUBDIRS := \
            $(addsuffix /java, \
                core \
                graphics \
                ***
                gateway \
             )
  • 修改白名单whitelist,否则编译会报错,找不到类
    build/core/tasks/check_boot_jars/package_whitelist.txt
    有些系统得位置在build/make/core/tasks/check_boot_jars/package_whitelist.txt
    #framework.jar下添加
    com.cns.android.gateway

2.添加aidl实现类service

    GatewaySystemService.java
    package com.cns.android.gateway;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.os.RemoteException;
    import android.provider.Settings;
    import android.service.notification.StatusBarNotification;
    import android.util.Log;

    //集成binder
    public class GatewaySystemService extends IGatewaySystemService.Stub{
        private  final String TAG = this.getClass().toString();
        private Context mContext;
        private final static String actionName = "com.cns.android.notemanager.NotificationMonitor";
        private final static String packageName = "com.archermind.notemanager";

    public GatewaySystemService(Context context){
        this.mContext = context;
        Log.d(TAG,"+++++++init GatewaySystemService+++++++++");
    }

    //开启log
    public void beginLog(){

    }
    //关闭log
    public void endLog(){

    }

    //        //注册回调
    public void registerGatewaySystemCallbackCallback(IGatewaySystemCallback callback){

    }
    //解除注册
    public void unregisterGatewaySystemCallbackCallback(IGatewaySystemCallback callback){

    }
    }

系统service最终的实现在这个类里面

3.注册service

(1)frameworks/base/services/java/com/android/server/SystemServer.java的startOtherServices方法中添加注册服务方法

     traceBeginAndSlog("StartGatewaySystemService");
     try {
         ServiceManager.addService(Context.GATEWAY_SYSTEM_SERVICE,
                 new GatewaySystemService(mSystemContext));
     } catch (Throwable e) {
         reportWtf("starting GatewaySystemService", e);
     }
     traceEnd();

(2)Context.GATEWAY_SYSTEM_SERVICE 是在Context中添加的常量

frameworks/base/core/java/android/content/Context.java

     @SystemApi
    public static final String GATEWAY_SYSTEM_SERVICE = "gateway_system_service";

4.添加manager类

app可以通过manager来调用binder Service
创建manager类

    package com.cns.android.gateway;

    import android.content.Context;
    import android.os.RemoteException;
    import android.util.Log;

    public class GatewaySystemManager {
        private final Context mContext;
        private  final String TAG = this.getClass().toString();
        private IGatewaySystemService mService;

    public GatewaySystemManager(Context context,IGatewaySystemService service) {
        super();
        mContext = context;
        this.mService = service;
        Log.d(TAG,"GatewaySystemManager init");

    }

    //开启log
    public void beginLog(){
        try {
            mService.beginLog();
        }catch (RemoteException ex){
            ex.printStackTrace();
        }
    }
    //关闭log
    public void endLog(){
        try {
            mService.endLog();
        }catch (RemoteException ex){
            ex.printStackTrace();
        }
    }


    //注册回调
    public void registerGatewaySystemCallbackCallback(IGatewaySystemCallback callback){
        try {
            mService.registerGatewaySystemCallbackCallback(callback);
        }catch (RemoteException ex){
            ex.printStackTrace();
        }
    }
    //解除注册
    public void unregisterGatewaySystemCallbackCallback(IGatewaySystemCallback callback){
        try {
            mService.unregisterGatewaySystemCallbackCallback(callback);
        }catch (RemoteException ex){
            ex.printStackTrace();
        }
    }
}

在这里会去调用binder Service中的方法

5.注册manager

frameworks/base/core/java/android/app/SystemServiceRegistry.java中注册Manager
        registerService(Context.GATEWAY_SYSTEM_SERVICE, GatewaySystemManager.class, new CachedServiceFetcher<GatewaySystemManager>() {
            @Override
            public GatewaySystemManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                IBinder b = ServiceManager.getServiceOrThrow(Context.GATEWAY_SYSTEM_SERVICE);
                IGatewaySystemService service = IGatewaySystemService.Stub.asInterface(b);
                return new GatewaySystemManager(ctx.getOuterContext(),service);
            }
        });


    }

6.添加te规则

有可能添加的te权限跟原来的权限会冲突,所以需要在编译的时候根据错误修改

    audit(1441759284.810:5): avc: denied { read } for pid=1494 comm="sdcard" name="0" dev="nandk" ino=245281 scontext=u:r:sdcardd:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=0
    scontext = u:r:sdcardd
    tcontext= u:object_r:system_data_file:s0
    tclass = dir
    avc: denied { read }

在scontext所指的.te文件(例如sdcardd.te)中加入类似如下allowe内容:
allow sdcardd system_data_file:dir read;
修改scontext.te文件
allow scontext tcontext:tclass denied
要加入的权限很多时,可以用中括号,比如:
allow sdcardd system_data_file:dir { read write add_name create};

例子:

    07-05 20:10:44.186 351-351/? E/SELinux: avc:  denied  { find } for service=gateway_system_service pid=10347 uid=10075 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:gateway_system_service:s0 tclass=service_manager
    scontext=u:r:untrusted_app
    tcontext=u:object_r:gateway_system_service
    tclass=service_manager
    avc:  denied  { find }

根据公式,修改untrusted_app.te文件,
添加allow untrusted_app gateway_system_service:service_manager find
make installclean后重新编译,刷boot.img才会生效。

二、java实现client

1.通过Manager调用

在上面,注册了GatewaySystemService的Manager GatewaySystemManager
可以通过

    GatewaySystemManager gatewaySystemManager = (GatewaySystemManager) mContext.getSystemService("gateway_system_service");//获取manager

调用manager方法,最终调用GatewaySystemService方法
gatewaySystemManager.beginLog();

2.通过Binder调用

    IBinder b = ServiceManager.getService("gateway_system_service");
    IGatewaySystemService service = IGatewaySystemService.Stub.asInterface(b);

    service.beginLog();//直接调用

三、native实现Binder service

1.定义INotificationGatewayService.aidl

    package android.notification;

    import android.notification.INotificationGatewayCallback;

    /**
     * {@hide}
     */

    interface INotificationGatewayService {
        const String SERVICE_NAME = "notification_service";
        /**
         * new notification to linux
         * param priority: [-2,2]. 2 is highest priority
         * param isAction: set true,it is triggered and opened the detailed page
         */
        void addNotification(String title, String content, String icon, String notificationid, String packageName, int priority,boolean isAction);

    /**
     * new popup to linux.  
     * param paramsJson: see specific doc
     */
    void addPopup(String notificationid, String packageName, String icon, String paramsJson);

    /**
     * delete all notifications of certain app(app uninstall)
     */ 
    void delAllNotification(String packageName);

    /**
     * register callback
     */ 
    void registerNotificationCallback(INotificationGatewayCallback callback);
}

2.定义INotificationGatewayCallback.aidl

    package android.notification;


    interface INotificationGatewayCallback{
        /**
         * click event, android will receive and handle
         */     
    void onClickNotification(String notificationid);

    /**
     * delete notification
     */ 
    void onDelNotification(String notificationid);
}

2.把aidl放进Android.mk文件中

    LOCAL_SRC_FILES := \
            INotificationGatewayCallback.aidl \
            INotificationGatewayService.aidl \
            NotificationBinderService.cpp \
            main.cpp

这样会在out目录下编译出Bp和Bn

3.实现Service方法

(1)定义头文件NotificationBinderService.h

    /*
     * NotificationBinderService.h
     *
     *  Created on: May 22, 2018
     *      Author: young
     */

    #ifndef NOTIFICATIONBINDERSERVICE_HPP_
    #define NOTIFICATIONBINDERSERVICE_HPP_

    #include <android/notification/BnNotificationGatewayService.h>//调用编译自动生成的头文件
    #include <android/notification/INotificationGatewayCallback.h>

    using namespace android;
    using namespace android::notification;
    using namespace android::binder;
    using namespace std;

    namespace android {
    namespace notification {
    //继承BnNotificationGatewayService ,此文件是自动编译生成,可以通过locate BnNotificationGatewayService找到
    //BnNotificationGatewayService 是Service,具体的方法都是在这个里面实现的
    class NotificationBinderService: public BnNotificationGatewayService, public IBinder::DeathRecipient {
    public:
        NotificationBinderService();
        ~NotificationBinderService();

        ::android::binder::Status addNotification(const ::android::String16& title, const ::android::String16& content, const ::android::String16& icon, const ::android::String16& notificationid, const ::android::String16& packageName, int32_t priority, bool isAction) override;
        ::android::binder::Status addPopup(const ::android::String16& notificationid, const ::android::String16& packageName, const ::android::String16& icon, const ::android::String16& paramsJson) override;
        ::android::binder::Status delAllNotification(const ::android::String16& packageName) override;
        ::android::binder::Status registerNotificationCallback(const ::android::sp<::android::notification::INotificationGatewayCallback>& callback) override;


        void onClickNotification(const ::android::String16& notificationid);
        void onDelNotification(const ::android::String16& notificationid);
    private:
        NotificationBinderService(const NotificationBinderService&) = delete;
        NotificationBinderService& operator=(const NotificationBinderService&) = delete;

        void binderDied(const wp<IBinder>& who) override;
        android::sp<android::notification::INotificationGatewayCallback> callback_;

        std::mutex mutex_;

    };

    }
    }

(2)定义具体的实现文件 NotificationBinderService.cpp

    /*
     * NotificationBinderService.cpp
     *
     *  Created on: May 22, 2018
     *      Author: young
     */

    #include "NotificationBinderService.h"
    #include <binder/IPCThreadState.h>
    #include <binder/Status.h>

    namespace android {
    namespace notification {

    NotificationBinderService::NotificationBinderService() {
     ALOGE("Notification>>NotificationBinderService");
    }

    NotificationBinderService::~NotificationBinderService() {

    }

    ::android::binder::Status NotificationBinderService::addNotification(const ::android::String16& title, const ::android::String16& content, const ::android::String16& icon, const ::android::String16& notificationid, const ::android::String16& packageName, int32_t priority, bool isAction){



        const char* retitle = android::String8(title).string();
        char re1[strlen(retitle)] ;
        strcpy(re1,retitle);
        const char* reicon = android::String8(icon).string();
        char re2[strlen(reicon)];
        strcpy(re2,reicon);
        const char* renotificationid = android::String8(notificationid).string();
        char re3[strlen(renotificationid)];
        strcpy(re3,renotificationid);
        const char* repackageName = android::String8(packageName).string();
        char re4[strlen(repackageName)];
        strcpy(re4,repackageName);


        ALOGE("Notification>>REQ_ADD_NOTIFICATION title:%s icon:%s notificationid:%s packageName:%s priority:%d isAction:%d",re1,re2,re3,re4,priority,isAction);
        return binder::Status::ok();
    }
    ::android::binder::Status NotificationBinderService::addPopup(const ::android::String16& notificationid, const ::android::String16& packageName, const ::android::String16& icon, const ::android::String16& paramsJson) {

        ALOGE("Notification>>REQ_ADD_POPUP notificationid:%s packageName:%s icon:%s paramsJson:%s",notificationid.string(),packageName.string(),icon.string(),paramsJson.string());
        return binder::Status::ok();
    }
    ::android::binder::Status NotificationBinderService::delAllNotification(const ::android::String16& packageName){
        ALOGE("Notification>>REQ_DEL_ALL packageName:%s",packageName.string());
        return binder::Status::ok();
    }

    binder::Status NotificationBinderService::registerNotificationCallback(const ::android::sp<::android::notification::INotificationGatewayCallback>& callback) {
        std::lock_guard < std::mutex > guard(mutex_);
        if (callback_.get()) {
            ALOGD("Notification>>Failed to register callback, already registered");
            return binder::Status::fromStatusT(ALREADY_EXISTS);
        }
        ALOGD("Notification>>Success to register callback, already registered");
        callback_ = callback;
        IInterface::asBinder(callback_)->linkToDeath(this);
        return binder::Status::ok();
    }

    //callback and pass on to binder client
    void NotificationBinderService::onClickNotification(const ::android::String16& notificationid) {
        if (!callback_.get()) {
            ALOGD("Notification>>INotificationGatewayCallback callback_ is null notificationid:%s",notificationid.string());
            return;
        }
        ALOGD("Notification>>onClickNotification");
        binder::Status status = callback_->onClickNotification(notificationid);
    }

    void NotificationBinderService::onDelNotification(const ::android::String16& notificationid) {
        if (!callback_.get()) {
            ALOGD("Notification>>INotificationGatewayCallback callback_ is null notificationid:%s",notificationid.string());
            return;
        }
        ALOGD("Notification>>onDelNotification");
        binder::Status status = callback_->onDelNotification(notificationid);
    }

    void NotificationBinderService::binderDied(const wp<IBinder>& /* who */) {
        std::lock_guard < std::mutex > guard(mutex_);
        callback_ = nullptr;
    }
    }
    }

(3)编译main.cpp方法,用来运行注册service

    #include "NotificationBinderService.h"

    int main(int argc, char **argv)
    {
        android::sp<ProcessState> proc(ProcessState::self());
        android::sp<NotificationBinderService> server = new NotificationBinderService();
        android::sp<android::IServiceManager> sm(android::defaultServiceManager());
        android::status_t service_status = sm->addService(android::String16(INotificationGatewayService::SERVICE_NAME()), server, false);

        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();

        return 0;
    }

四、native 实现Binder client

    int
    main() {

        android::sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder = sm->getService(String16(INotificationGatewayService::SERVICE_NAME());
        sp<INotificationBinderService> cs = interface_cast<INotificationBinderService>(binder);
        cs->onClickNotification(String16("10"));//调用service里面的方法
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    return 0;
    }

五、java client调用native service

这个跟二java实现client是一样的,

1.添加aidl文件

根据C++的aidl文件,同样的复制一份,放到android文件中编译,(注意这里的aidl文件一定要相同,否则在调用的时候会出现方法不统一而调用出错的问题)
我是aidl统一放到相同的位置,C++或者framework要调用的时候,都直接去引用就行了
根据一种方法,添加aidl到framework/base下的Android.mk中

    LOCAL_SRC_FILES += \
    ***
    ../../vendor/cns_gateway_utils/aidl/com/cns/android/gateway/IGatewaySystemService.aidl \
    ../../vendor/cns_gateway_utils/aidl/com/cns/android/gateway/IGatewaySystemCallback.aidl \

编译framework/base/Android.mk

2.调用Service

IBinder notificationBinder = ServiceManager.getService("notificationservice");
    INotificationGatewayService notificationGatewayService = INotificationGatewayService.Stub.asInterface(notificationBinder);
    INotificationGatewayCallback notificationGatewayCallback callback = new NotificationGatewayCallback(context);
     try {
                notificationGatewayService.registerNotificationCallback(callback);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }

六、native client调用java service

跟native client调用native service是一样的

       sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder = sm->getService(String16(INotificationGatewayService::SERVICE_NAME());
        sp<INotificationBinderService> cs = interface_cast<INotificationBinderService>(binder);
        cs->onClickNotification(String16("10"));//调用service里面的方法

Binder 的学习已经接近尾声了,我们已经研究了Binder Driver, C/C++的实现,就差最后一个部分了,Binder在Java端的实现了。Java端的实现与Native端类似,我们用下面的表格和类图概括他们的关系
BpXXX、BnXXX同时实现一个接口IXXX。BpXXX主要是用来处理java层传下来的服务请求,然后通过transact将处理请求传给BnXXX(通过binder)。BpINTERFACE是client端的代理接口,BnINTERFACE是server端的代理接口。

BpBinder(Binder Proxy):主要功能是负责client向Bn发送调用请求的数据。它是client端binder通信的核心对象,通过调用transact函数,client就可以向Bn发送调用请求和数据。

Native

Java

Note

IBinder

IBinder

IInterface

IInterface

IXXX

IXXX

aidl文件定义

BBinder

Binder

通过JavaBBinder类作为桥梁

BpBinder

BinderProxy

通过JNI访问Native的实现

BnInterface

N/A

BpInterface

N/A

BnXXX Stub

aidl工具自动生成

server端

BpXXX

Proxy

aidl工具自动生成client端

七、app调用java service

注意如果需要app调用到系统Manager或者Service的话,因为原生的sdk是没有我们新加的类的,所以我们需要用以下方法来获取系统Service

1.获取系统Manager GatewaySystemManager

GatewaySystemManager的包名是package com.cns.android.gateway;
所以,要在app下建立相同的包名和类名
在app中新建包package com.cns.android.gateway;
并且新建GatewaySystemManager方法
然后按照系统GatewaySystemManager方法 写入空方法

      public GatewaySystemManager(Context context,IGatewaySystemService service) {
    }

    //开启log
    public void beginLog(){

    }
    //关闭log
    public void endLog(){

    }


    //注册回调
    public void registerGatewaySystemCallbackCallback(IGatewaySystemCallback callback){

    }
    //解除注册
    public void unregisterGatewaySystemCallbackCallback(IGatewaySystemCallback callback){

    }
}
app会先去framework中找相应包名和类名的方法,并调用里面的方法

八、app调用native service

也是同样道理,需要复制一份aidl文件到app中,然后根据java 调用native service的方法

    INotificationGatewayService notificationGatewayService = INotificationGatewayService.Stub.asInterface(notificationBinder);
    INotificationGatewayCallback notificationGatewayCallback callback = new NotificationGatewayCallback(context);
     try {
                    notificationGatewayService.registerNotificationCallback(callback);
                } catch (RemoteException e) {
                    e.printStackTrace();
        }