这个例子由一个 Activity 组成,它绑定一个 Service (Java) 并将 IBinder 对象传递给 C++ JNI 层。使用 NDK Binder API 在 JNI 层中与 Service 进行通信。
AIDL。
src/main/aidl/com/example/IMyService.aidl
package com.example;
import com.example.ComplexType;
interface IMyService
{
ComplexType returnComplexType(int anInt,
long aLong, boolean aBoolean,
float aFloat, double aDouble,
String aString);
}
src/main/aidl/com/example/ComplexType.aidl
package com.example;
parcelable ComplexType cpp_header "ComplexType.h";
build.gradle 文件有一个 Gradle 任务 (compileAidlNdk) 为 IMyService.aidl 自动生成 NDK C++ binder 源文件。
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
buildToolsVersion '29.0.3'
defaultConfig {
minSdkVersion 29
externalNativeBuild {
cmake {
cppFlags "-std=c++17"
}
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
...
}
task compileAidlNdk() {
doLast {
def aidlCpp = [android.sdkDirectory,
'build-tools',
android.buildToolsVersion,
'aidl'].join(File.separator)
def outDir = [projectDir.absolutePath,
'src', 'main', 'cpp', 'aidl'].join(File.separator)
def headerOutDir = [projectDir.absolutePath,
'src', 'main', 'cpp', 'includes'].join(File.separator)
def searchPathForImports = [projectDir.absolutePath,
'src', 'main', 'aidl'].join(File.separator)
def aidlFile = [projectDir.absolutePath,
'src', 'main', 'aidl',
'com', 'example', 'IMyService.aidl'].join(File.separator)
exec {
executable(aidlCpp)
args('--lang=ndk',
'-o', outDir,
'-h', headerOutDir,
'-I', searchPathForImports,
aidlFile)
}
}
}
afterEvaluate {
preBuild.dependsOn(compileAidlNdk)
}
src/main/java/com/example/ndkbinderclient/MainActivity.java
package com.example.ndkbinderclient;
public class MainActivity extends AppCompatActivity implements ServiceConnection
{
static
{
System.loadLibrary("native-lib");
}
private volatile boolean mIsServiceConnected = false;
private final ConditionVariable mServiceConnectionWaitLock = new ConditionVariable();
public native void onServiceConnected(IBinder binder);
public native void onServiceDisconnected();
public native void talkToService();
@Override
protected void onResume()
{
super.onResume();
Intent intent = new Intent();
intent.setClassName("com.example",
"com.example.javabinderservice.MyService");
bindService(intent, this, BIND_AUTO_CREATE);
new Thread(new Runnable()
{
@Override
public void run()
{
// Not connected to service yet?
while(!mIsServiceConnected)
{
// waits for service connection
mServiceConnectionWaitLock.block();
}
talkToService();
}
}).start();
}
@Override
protected void onPause()
{
unbindService(this);
mIsServiceConnected = false;
onServiceDisconnected();
super.onPause();
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
{
onServiceConnected(iBinder);
mIsServiceConnected = true;
// breaks service connection waits
mServiceConnectionWaitLock.open();
}
@Override
public void onServiceDisconnected(ComponentName componentName)
{
mIsServiceConnected = false;
onServiceDisconnected();
}
}
src/main/cpp/native-lib.cpp
#include <jni.h>
#include <aidl/com/example/IMyService.h>
#include <android/binder_ibinder_jni.h>
std::shared_ptr<IMyService> g_spMyService;
extern "C" JNIEXPORT void JNICALL
Java_com_example_ndkbinderclient_MainActivity_onServiceConnected(
JNIEnv* env,
jobject /* this */,
jobject binder)
{
AIBinder* pBinder = AIBinder_fromJavaBinder(env, binder);
const ::ndk::SpAIBinder spBinder(pBinder);
g_spMyService = IMyService::fromBinder(spBinder);
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_ndkbinderclient_MainActivity_onServiceDisconnected(
JNIEnv* env,
jobject /* this */)
{
g_spMyService = nullptr;
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_ndkbinderclient_MainActivity_talkToService(
JNIEnv* env,
jobject /* this */)
{
ComplexType returnedComplexObject;
ScopedAStatus returnComplexTypeResult = g_spMyService->returnComplexType(2021,
65535000, true, 3.14f, 3.141592653589793238,
"Hello, World!", &returnedComplexObject);
}
src/main/cpp/includes/ComplexType.h
#pragma once
#include <android/binder_status.h>
class ComplexType
{
public:
int i_Int;
long l_Long;
bool b_Boolean;
float f_Float;
double d_Double;
std::string s_String;
public:
binder_status_t readFromParcel(const AParcel* pParcel)
{
int32_t iNotNull;
AParcel_readInt32(pParcel, &iNotNull);
AParcel_readInt32(pParcel, &i_Int);
AParcel_readInt64(pParcel, &l_Long);
AParcel_readBool(pParcel, &b_Boolean);
AParcel_readFloat(pParcel, &f_Float);
AParcel_readDouble(pParcel, &d_Double);
ndk::AParcel_readString(pParcel, &s_String);
return STATUS_OK;
}
binder_status_t writeToParcel(AParcel* pParcel) const
{
int32_t iNotNull = 1;
AParcel_writeInt32(pParcel, iNotNull);
AParcel_writeInt32(pParcel, i_Int);
AParcel_writeInt64(pParcel, l_Long);
AParcel_writeBool(pParcel, b_Boolean);
AParcel_writeFloat(pParcel, f_Float);
AParcel_writeDouble(pParcel, d_Double);
ndk::AParcel_writeString(pParcel, s_String);
return STATUS_OK;
}
};
src/main/cpp/CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
add_library (
native-lib
SHARED
native-lib.cpp
aidl/com/example/IMyService.cpp
)
target_include_directories (
native-lib
PRIVATE
includes
)
target_link_libraries (
native-lib
binder_ndk
)
src/main/java/com/example/ndkbinderservice/MyService.java
package com.example.javabinderservice;
public class MyService extends Service
{
private IBinder mBinder;
@Override
public void onCreate()
{
super.onCreate();
mBinder = new MyServiceBinder();
}
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
private static class MyServiceBinder extends IMyService.Stub
{
@Override
public ComplexType returnComplexType(int anInt,
long aLong, boolean aBoolean,
float aFloat, double aDouble,
String aString) throws RemoteException
{
return new ComplexType(anInt, aLong, aBoolean, aFloat,
aDouble, aString);
}
}
}
src/main/java/com/example/ComplexType.java
public class ComplexType implements Parcelable
{
public final int mInt;
public final long mLong;
public final boolean mBoolean;
public final float mFloat;
public final double mDouble;
public final String mString;
protected ComplexType(Parcel in)
{
mInt = in.readInt();
mLong = in.readLong();
mBoolean = in.readBoolean();
mFloat = in.readFloat();
mDouble = in.readDouble();
mString = in.readString();
}
@Override
public void writeToParcel(Parcel parcel, int i)
{
parcel.writeInt(mInt);
parcel.writeLong(mLong);
parcel.writeBoolean(mBoolean);
parcel.writeFloat(mFloat);
parcel.writeDouble(mDouble);
parcel.writeString(mString);
}
...
}
src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example">
<application>
<activity android:name=".ndkbinderclient.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ndkbinderservice.MyService"
android:exported="true">
</service>
</application>
</manifest>
完整的源代码可以在https://github.com/lakinduboteju/AndroidNdkBinderExamples找到