第3章 Service端Binder实现与注册:继承Binder类、重写onTransact、注册到ServiceManager与导出Service

本章聚焦Binder通信体系中Service端的核心实现环节。Service端需要完成四个关键步骤:继承Binder类(或原生BBinder)获得IPC能力,重写onTransact处理客户端请求,注册到ServiceManager让客户端可查询,以及导出Service使跨进程访问生效。这四个步骤构成Binder服务端骨架,理解其实现细节是掌握跨进程调用的基础。

3.1 原理剖析:Binder服务端角色与职责

在Binder机制中,Service端是实际提供功能的进程。每个Service端对应一个Binder实体对象(通常继承android.os.Binder或原生BBinder),该对象拥有唯一的handle,由Binder驱动分配。ServiceManager维护一张名称 → Binder引用的表,允许客户端通过名称获取远程Binder代理。Service端通过addService将自身注册到ServiceManager,同时通过Android的权限机制(如AndroidManifest中的android:exported或SEAndroid策略)控制外部访问。

关键概念表
组件职责与本章关系
Binder实体接收IPC请求并执行通过继承Binder/BBinder创建
onTransact分发请求代码,解析Parcel数据需重写此方法处理业务逻辑
ServiceManager全局服务注册表调用addService注册服务名称
导出Service使服务对外部进程可见系统服务依赖selinux,应用服务依赖exported属性

3.2 实现流程

  1. 继承Binder类:在Java端继承android.os.Binder,在C++端继承BBinder。原生实现需实现onTransact方法。
  2. 重写onTransact:根据code(请求标识整数)分发处理,从dataParcel读取参数,将结果写入replyParcel。
  3. 创建实例并注册到ServiceManager:调用defaultServiceManager()->addService(String16("my_service"), serviceBinder)(C++)或ServiceManager.addService("my_service", binder)(Java)。
  4. 导出Service:系统服务需在Android.bp或rc文件中声明,并配置SEAndroid策略;应用服务在AndroidManifest中设置android:exported="true"。
Service端Binder实现与注册流程 继承Binder/BBinder 重写onTransact (处理code, data/reply) 实例化Binder对象 addService("my_service", binder) (注册到ServiceManager) 导出Service (manifest/selinux/rc) 正向流程:继承 → 重写onTransact → 实例化 → addService注册 → 导出(客户端才能找到并连接)

3.3 核心代码实现

3.3.1 C++原生Binder实现(系统服务典型)

// MyService.h
#include <binder/BBinder.h>
#include <binder/Parcel.h>
#include <binder/IServiceManager.h>

using namespace android;

class MyService : public BBinder {
public:
    MyService() : BBinder() {}
    virtual status_t onTransact(uint32_t code,
                                const Parcel& data,
                                Parcel* reply,
                                uint32_t flags) override;
};

status_t MyService::onTransact(uint32_t code,
                               const Parcel& data,
                               Parcel* reply,
                               uint32_t flags) {
    switch (code) {
        case 1: { // 自定义获取字符串
            int32_t param = data.readInt32();
            reply->writeInt32(param * 2);
            return NO_ERROR;
        }
        case 2: { // 获取服务描述
            reply->writeCString("Hello from MyService");
            return NO_ERROR;
        }
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

3.3.2 注册到ServiceManager

// main.cpp
int main(int argc, char** argv) {
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    
    sp<MyService> service = new MyService();
    sm->addService(String16("my_service"), service);
    
    // 挂起,保持服务运行
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

3.3.3 Java端实现(应用服务)

public class MyService extends android.app.Service {
    private final IBinder mBinder = new MyBinder();

    private class MyBinder extends Binder {
        @Override
        protected boolean onTransact(int code, Parcel data,
                                     Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case 1:
                    int input = data.readInt();
                    reply.writeInt(input * 2);
                    return true;
                case 2:
                    reply.writeString("Hello from Java Service");
                    return true;
                default:
                    return super.onTransact(code, data, reply, flags);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

在AndroidManifest.xml中导出Service:

<service android:name=".MyService"
         android:exported="true">
    <intent-filter>
        <action android:name="com.example.ACTION_MY_SERVICE" />
    </intent-filter>
</service>

3.4 调试方法

  • 查看注册的服务:adb shell service list 列出所有已注册服务,检查是否有 my_service。
  • 验证onTransact返回值:若客户端调用返回 FAILED_TRANSACTION,检查onTransact返回错误码或未处理code。
  • 日志跟踪:在onTransact中加入ALOGD打印code与参数。
  • Binder统计信息:cat /d/binder/transactions 或 dumpsys binderservice --binder-domain。

3.5 部署与验证

  1. 将编译得到的可执行文件(如my_service)push到设备/system/bin/。
  2. 赋予执行权限:adb shell chmod 755 /system/bin/my_service。
  3. 后台启动:adb shell /system/bin/my_service &。
  4. 验证注册:adb shell service check my_service 应返回 Service my_service: found。
注意:系统服务需在init.rc中定义为service,并添加seclabel,否则可能受SEAndroid限制无法注册成功。

3.6 常见错误与规避

错误现象根因解决方案
onTransact后客户端收到DEAD_OBJECT服务进程崩溃或未正确挂起确保调用了joinThreadPool;检查Binder线程池启动
service list看不到服务addService调用失败或权限不足检查logcat中ServiceManager的错误;确认进程有ADD_SERVICE权限
客户端调用返回FAILED_TRANSACTIONonTransact未处理该code或返回错误在onTransact中增加default分支调用父类;打印调用code
SEAndroid拒绝注册服务进程没有对应的service_manager域添加SEPolicy:allow my_service service_manager:service_manager add;
Binder内存泄露Parcel未正确清理,尤其是大型数据避免在onTransact中持有Parcel引用;使用局部变量

3.7 性能与稳定性优化

  • 控制事务大小:Binder传输数据量建议小于512KB,否则触发额外内存拷贝。
  • 同步vs异步:复杂耗时操作应使用TF_ONE_WAY标志(客户端不等待返回),或另开线程处理。
  • 减少onTransact中的锁竞争:若多个客户端并发请求,内部数据结构需线程安全。
  • 使用服务缓存:避免频繁addService/removeService,服务注册后应常驻。
  • 引用计数管理:C++端使用sp<>智能指针,防止Binder对象提前释放。
关键实践提醒:在重写onTransact时,务必确保所有路径都调用基类的BBinder::onTransact处理未识别的code,否则Binder协议校验会失败导致进程被kill。

3.8 本章小结

Service端Binder实现的核心在于正确继承并注册:继承Binder/BBinder提供IPC框架,重写onTransact定义业务接口,addService注册到全局命名空间,导出Service赋予外部访问权限。这四个步骤环环相扣,任何一个环节出错都会导致跨进程通信失败。掌握本章内容后,即可构建可被任意客户端调用的Binder服务,为后续的代理端实现和复杂IPC模式打下基础。