Android Binder 用法详解
Binder 是 Android 系统中的一种进程间通信(IPC)机制,它允许不同进程之间进行高效通信。Binder 在 Android 系统中被广泛使用,例如在 Activity 与 Service 的交互中。
Binder 的基本组成
实现 Binder 通信通常包含以下几个关键部分:
- AIDL 接口定义:通过 Android Interface Definition Language 定义接口
- 服务端实现:实现 AIDL 接口并在 Service 中提供服务
- 客户端调用:绑定服务并调用远程方法
下面通过一个完整的示例来展示 Binder 的使用方法。
示例:创建一个计算器服务
第一步:定义 AIDL 接口
创建文件 ICalculator.aidl
:
// ICalculator.aidl
package com.example.binderexample;
interface ICalculator {
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
int divide(int a, int b);
}
第二步:创建服务端 Service
// CalculatorService.java
package com.example.binderexample;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class CalculatorService extends Service {
private static final String TAG = "CalculatorService";
// Binder 实现
private final ICalculator.Stub mBinder = new ICalculator.Stub() {
@Override
public int add(int a, int b) throws RemoteException {
Log.d(TAG, "add() called with: a = [" + a + "], b = [" + b + "]");
return a + b;
}
@Override
public int subtract(int a, int b) throws RemoteException {
Log.d(TAG, "subtract() called with: a = [" + a + "], b = [" + b + "]");
return a - b;
}
@Override
public int multiply(int a, int b) throws RemoteException {
Log.d(TAG, "multiply() called with: a = [" + a + "], b = [" + b + "]");
return a * b;
}
@Override
public int divide(int a, int b) throws RemoteException {
Log.d(TAG, "divide() called with: a = [" + a + "], b = [" + b + "]");
if (b == 0) {
throw new RemoteException("Division by zero");
}
return a / b;
}
};
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind: Service bound");
return mBinder;
}
}
第三步:在 AndroidManifest.xml 中注册服务
<service
android:name=".CalculatorService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.binderexample.ICalculator" />
</intent-filter>
</service>
第四步:客户端实现
// MainActivity.java
package com.example.binderexample;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private EditText mNum1EditText, mNum2EditText;
private TextView mResultTextView;
private Button mAddButton, mSubtractButton, mMultiplyButton, mDivideButton;
private ICalculator mCalculator;
private boolean mBound = false;
// 服务连接对象
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mCalculator = ICalculator.Stub.asInterface(service);
mBound = true;
Log.d(TAG, "onServiceConnected: Service connected");
Toast.makeText(MainActivity.this, "Calculator Service Connected", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mCalculator = null;
mBound = false;
Log.d(TAG, "onServiceDisconnected: Service disconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化 UI 组件
mNum1EditText = findViewById(R.id.editText_num1);
mNum2EditText = findViewById(R.id.editText_num2);
mResultTextView = findViewById(R.id.textView_result);
mAddButton = findViewById(R.id.button_add);
mSubtractButton = findViewById(R.id.button_subtract);
mMultiplyButton = findViewById(R.id.button_multiply);
mDivideButton = findViewById(R.id.button_divide);
// 添加按钮点击事件
mAddButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
performOperation("add");
}
});
mSubtractButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
performOperation("subtract");
}
});
mMultiplyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
performOperation("multiply");
}
});
mDivideButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
performOperation("divide");
}
});
}
private void performOperation(String operation) {
if (!mBound) {
Toast.makeText(this, "Service not bound", Toast.LENGTH_SHORT).show();
return;
}
try {
// 获取输入值
int num1 = Integer.parseInt(mNum1EditText.getText().toString());
int num2 = Integer.parseInt(mNum2EditText.getText().toString());
int result = 0;
// 执行远程操作
switch (operation) {
case "add":
result = mCalculator.add(num1, num2);
break;
case "subtract":
result = mCalculator.subtract(num1, num2);
break;
case "multiply":
result = mCalculator.multiply(num1, num2);
break;
case "divide":
result = mCalculator.divide(num1, num2);
break;
}
// 显示结果
mResultTextView.setText("结果: " + result);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException: " + e.getMessage());
Toast.makeText(this, "Remote exception: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} catch (NumberFormatException e) {
Toast.makeText(this, "Please enter valid numbers", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onStart() {
super.onStart();
// 绑定服务
Intent intent = new Intent();
intent.setAction("com.example.binderexample.ICalculator");
intent.setPackage(getPackageName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 解绑服务
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
第五步:布局文件
<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/editText_num1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入第一个数字"
android:inputType="number" />
<EditText
android:id="@+id/editText_num2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入第二个数字"
android:inputType="number" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/button_add"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="+" />
<Button
android:id="@+id/button_subtract"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="-" />
<Button
android:id="@+id/button_multiply"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="×" />
<Button
android:id="@+id/button_divide"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="÷" />
</LinearLayout>
<TextView
android:id="@+id/textView_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="结果: "
android:textSize="18sp" />
</LinearLayout>
Binder 工作原理解释
-
AIDL 编译:编译时,Android 工具会根据 AIDL 文件生成相应的 Java 接口,其中包含一个内部抽象类 Stub,继承自 Binder 并实现了该接口
-
Stub 类:
- 服务端继承并实现 Stub 类的抽象方法
- Stub 类拥有 asInterface() 静态方法,用于将 IBinder 转换为接口类型
-
通信过程:
- 客户端调用 bindService() 绑定服务
- 服务端返回 Binder 对象
- 客户端通过 Stub.asInterface() 将 Binder 对象转换为接口
- 客户端调用接口方法,实际上是通过 Binder 驱动进行跨进程通信
高级用法:传输复杂对象
如果需要传输复杂对象,需要实现 Parcelable 接口:
// Person.java
package com.example.binderexample;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
protected Person(Parcel in) {
name = in.readString();
age = in.readInt();
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
然后在 AIDL 文件中引用这个类:
// Person.aidl
package com.example.binderexample;
parcelable Person;
// IPersonService.aidl
package com.example.binderexample;
import com.example.binderexample.Person;
interface IPersonService {
void addPerson(in Person person);
List<Person> getAllPersons();
}
Android C++ 中的 Binder 使用
在 Android C++ 层也可以使用 Binder 进行进程间通信。实际上,Android 框架中的核心 Binder 实现就是用 C++ 编写的,位于 native 层。C++ 中的 Binder 框架是 Java Binder 框架的基础。
Android Native Binder 主要组件
在 C++ 层使用 Binder 主要涉及以下几个关键类:
- IBinder:表示一个 Binder 对象的基类
- BpBinder:代理端的 Binder 实现(客户端)
- BBinder:本地端的 Binder 实现(服务端)
- BnInterface:服务端接口模板类
- BpInterface:客户端接口模板类
- IInterface:Binder 接口的基类
- ProcessState:管理进程的 Binder 状态
- IPCThreadState:管理线程的 Binder 状态
C++ Binder 实现示例
下面是一个完整的 C++ Binder 示例,包括服务端和客户端。
第一步:定义接口
首先,我们需要定义一个计算器服务的接口:
// ICalculator.h
#ifndef ICALCULATOR_H
#define ICALCULATOR_H
#include <binder/IInterface.h>
#include <binder/Parcel.h>
namespace android {
// 接口标识符
enum {
CALCULATOR_ADD = IBinder::FIRST_CALL_TRANSACTION,
CALCULATOR_SUBTRACT,
CALCULATOR_MULTIPLY,
CALCULATOR_DIVIDE
};
// 接口定义
class ICalculator : public IInterface {
public:
DECLARE_META_INTERFACE(Calculator); // 声明接口元信息
// 纯虚函数,需要子类实现
virtual int32_t add(int32_t a, int32_t b) = 0;
virtual int32_t subtract(int32_t a, int32_t b) = 0;
virtual int32_t multiply(int32_t a, int32_t b) = 0;
virtual int32_t divide(int32_t a, int32_t b) = 0;
};
// 服务端接口
class BnCalculator : public BnInterface<ICalculator> {
public:
// onTransact 函数处理来自客户端的请求
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
};
} // namespace android
#endif // ICALCULATOR_H
第二步:实现接口
接下来,我们需要实现这个接口:
// ICalculator.cpp
#include "ICalculator.h"
namespace android {
// 实现元接口宏
IMPLEMENT_META_INTERFACE(Calculator, "android.calculator.ICalculator");
// 处理远程调用请求
status_t BnCalculator::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
case CALCULATOR_ADD: {
CHECK_INTERFACE(ICalculator, data, reply);
int32_t a = data.readInt32();
int32_t b = data.readInt32();
int32_t result = add(a, b);
reply->writeInt32(result);
return NO_ERROR;
}
case CALCULATOR_SUBTRACT: {
CHECK_INTERFACE(ICalculator, data, reply);
int32_t a = data.readInt32();
int32_t b = data.readInt32();
int32_t result = subtract(a, b);
reply->writeInt32(result);
return NO_ERROR;
}
case CALCULATOR_MULTIPLY: {
CHECK_INTERFACE(ICalculator, data, reply);
int32_t a = data.readInt32();
int32_t b = data.readInt32();
int32_t result = multiply(a, b);
reply->writeInt32(result);
return NO_ERROR;
}
case CALCULATOR_DIVIDE: {
CHECK_INTERFACE(ICalculator, data, reply);
int32_t a = data.readInt32();
int32_t b = data.readInt32();
if (b == 0) {
return BAD_VALUE; // 除数为零错误
}
int32_t result = divide(a, b);
reply->writeInt32(result);
return NO_ERROR;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
// 客户端代理实现
class BpCalculator : public BpInterface<ICalculator> {
public:
BpCalculator(const sp<IBinder>& impl) : BpInterface<ICalculator>(impl) {}
virtual int32_t add(int32_t a, int32_t b) {
Parcel data, reply;
data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
data.writeInt32(a);
data.writeInt32(b);
remote()->transact(CALCULATOR_ADD, data, &reply);
return reply.readInt32();
}
virtual int32_t subtract(int32_t a, int32_t b) {
Parcel data, reply;
data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
data.writeInt32(a);
data.writeInt32(b);
remote()->transact(CALCULATOR_SUBTRACT, data, &reply);
return reply.readInt32();
}
virtual int32_t multiply(int32_t a, int32_t b) {
Parcel data, reply;
data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
data.writeInt32(a);
data.writeInt32(b);
remote()->transact(CALCULATOR_MULTIPLY, data, &reply);
return reply.readInt32();
}
virtual int32_t divide(int32_t a, int32_t b) {
Parcel data, reply;
data.writeInterfaceToken(ICalculator::getInterfaceDescriptor());
data.writeInt32(a);
data.writeInt32(b);
status_t status = remote()->transact(CALCULATOR_DIVIDE, data, &reply);
if (status != NO_ERROR) {
return -1; // 错误处理
}
return reply.readInt32();
}
};
} // namespace android
第三步:实现服务端
服务端需要实现 ICalculator 接口,并提供一个服务:
// CalculatorService.h
#ifndef CALCULATOR_SERVICE_H
#define CALCULATOR_SERVICE_H
#include "ICalculator.h"
namespace android {
class CalculatorService : public BnCalculator {
public:
static void instantiate(); // 用于注册服务
// 实现ICalculator接口的方法
virtual int32_t add(int32_t a, int32_t b);
virtual int32_t subtract(int32_t a, int32_t b);
virtual int32_t multiply(int32_t a, int32_t b);
virtual int32_t divide(int32_t a, int32_t b);
};
} // namespace android
#endif // CALCULATOR_SERVICE_H
// CalculatorService.cpp
#include "CalculatorService.h"
#include <binder/IServiceManager.h>
#include <utils/Log.h>
namespace android {
void CalculatorService::instantiate() {
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16("calculator"), new CalculatorService());
ALOGI("Calculator service started");
}
int32_t CalculatorService::add(int32_t a, int32_t b) {
ALOGI("add() called with: a = %d, b = %d", a, b);
return a + b;
}
int32_t CalculatorService::subtract(int32_t a, int32_t b) {
ALOGI("subtract() called with: a = %d, b = %d", a, b);
return a - b;
}
int32_t CalculatorService::multiply(int32_t a, int32_t b) {
ALOGI("multiply() called with: a = %d, b = %d", a, b);
return a * b;
}
int32_t CalculatorService::divide(int32_t a, int32_t b) {
ALOGI("divide() called with: a = %d, b = %d", a, b);
return a / b;
}
} // namespace android
第四步:服务端主程序
编写服务端主程序,用于启动服务:
// server_main.cpp
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "CalculatorService.h"
using namespace android;
int main() {
sp<ProcessState> proc(ProcessState::self());
// 实例化并注册服务
CalculatorService::instantiate();
// 启动线程池处理请求
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
第五步:客户端实现
客户端程序示例:
// client_main.cpp
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <iostream>
#include "ICalculator.h"
using namespace android;
using namespace std;
int main() {
sp<IServiceManager> sm = defaultServiceManager();
// 获取计算器服务
sp<IBinder> binder = sm->getService(String16("calculator"));
if (binder == nullptr) {
ALOGE("Failed to get calculator service");
return -1;
}
// 创建代理对象
sp<ICalculator> calculator = interface_cast<ICalculator>(binder);
// 使用计算器服务
int a = 10, b = 5;
cout << "Addition: " << a << " + " << b << " = " << calculator->add(a, b) << endl;
cout << "Subtraction: " << a << " - " << b << " = " << calculator->subtract(a, b) << endl;
cout << "Multiplication: " << a << " * " << b << " = " << calculator->multiply(a, b) << endl;
cout << "Division: " << a << " / " << b << " = " << calculator->divide(a, b) << endl;
return 0;
}
编译和构建
在 Android Native 代码中,通常会在 Android.bp
或 Android.mk
文件中配置编译规则:
// Android.bp
cc_binary {
name: "calculator_service",
srcs: [
"ICalculator.cpp",
"CalculatorService.cpp",
"server_main.cpp",
],
shared_libs: [
"libutils",
"libbinder",
"liblog",
],
}
cc_binary {
name: "calculator_client",
srcs: [
"ICalculator.cpp",
"client_main.cpp",
],
shared_libs: [
"libutils",
"libbinder",
"liblog",
],
}
Native Binder 与 Java Binder 的区别
C++ Binder 和 Java Binder 的主要区别:
-
API 差异:
- C++ 使用 BBinder、BpBinder、BnInterface 等类
- Java 使用 Binder、BinderProxy、IInterface.Stub 等类
-
内存管理:
- C++ 使用 sp<>(强指针)进行引用计数
- Java 依赖于 JVM 的垃圾回收
-
接口定义:
- C++ 需要手动定义和实现接口类和代理类
- Java 使用 AIDL 自动生成接口代码
-
错误处理:
- C++ 使用状态码(status_t)
- Java 使用异常机制(RemoteException)
与 C++ 服务绑定的 Java 客户端
Java 应用也可以通过 JNI 调用 C++ 层的 Binder 服务:
// 在 Java 中获取本地服务
public class NativeBinderHelper {
static {
System.loadLibrary("nativebinderhelper");
}
// 本地方法声明
public static native int addNumbers(int a, int b);
public static native int subtractNumbers(int a, int b);
}
// JNI 实现
#include <jni.h>
#include <binder/IServiceManager.h>
#include "ICalculator.h"
using namespace android;
// JNI 函数实现
extern "C" JNIEXPORT jint JNICALL
Java_com_example_NativeBinderHelper_addNumbers(JNIEnv* env, jclass clazz, jint a, jint b) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("calculator"));
if (binder == nullptr) {
return -1;
}
sp<ICalculator> calculator = interface_cast<ICalculator>(binder);
return calculator->add(a, b);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_example_NativeBinderHelper_subtractNumbers(JNIEnv* env, jclass clazz, jint a, jint b) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("calculator"));
if (binder == nullptr) {
return -1;
}
sp<ICalculator> calculator = interface_cast<ICalculator>(binder);
return calculator->subtract(a, b);
}
实际应用场景
C++ Binder 在 Android 系统中广泛应用于:
- 系统服务:如 SurfaceFlinger、AudioFlinger 等系统服务
- HAL 接口:硬件抽象层接口通常使用 Binder
- 高性能需求:需要高性能 IPC 的场景
总结
Android C++ 层的 Binder 机制是 Android IPC 系统的基础,它提供了:
- 完整的 IPC 框架:支持跨进程方法调用
- 类型安全:通过接口定义保证类型安全
- 高性能:直接在 native 层实现,避免了 JNI 开销
- 安全性:支持身份验证和访问控制
虽然 C++ Binder 的使用相对 Java Binder 更复杂,需要手动实现更多代码,但它在性能和系统集成方面具有优势,特别适合系统级服务和对性能要求高的应用场景。