028.AIDL 关键字 in out inout oneway 解析
2025/10/6大约 7 分钟
关键字的作用
in out inout 是 aidl 中的 directional tag
,表示了在跨进程通信中数据的流向,oneway 用于标识方法是同步还是异步:
- in 表示数据只能由客户端流向服务端,服务端会获取到客户端完整的数据,但客户端不会同步服务端你对该对象的修改,不写的话,默认的 tag 就是 in
- out 表示数据只能由服务端流向客户端,从服务端接受该对象不为空,但字段内容为空,服务端修改对象后,binder 远程调用返回后,客户端会收到修改后的对象。
- inout 则表示数据可在服务端与客户端之间双向流通。
- 默认情况下,我们在 AIDL 中定义的接口方法是同步的,如果 AIDL 中的接口方法被 oneway 修饰了,那么这些方法就变成异步的了。
Java 中的 AIDL 关键字解析
修改Binder 程序示例之 Java 篇中的示例程序:
项目整体结构如下:
BinderJavaDemo
└── com
└── yuandaima
├── Android.bp
├── Book.aidl
├── Book.java
├── Client.java
├── HelloService.java
├── IHelloService.aidl
├── IHelloService.java
└── Server.java
其中 Book.java
:
package com.yuandaima;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable{
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
private String name;
private int price;
public Book(){}
public Book(Parcel in) {
name = in.readString();
price = in.readInt();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(price);
}
/**
* 参数是一个Parcel,用它来存储与传输数据
* @param dest
*/
public void readFromParcel(Parcel dest) {
//注意,此处的读值顺序应当是和writeToParcel()方法中一致的
name = dest.readString();
price = dest.readInt();
}
//方便打印数据
@Override
public String toString() {
return "name : " + name + " , price : " + price;
}
}
Book.aidl
内容如下:
package com.yuandaima;
parcelable Book;
接着修改 IHelloService.aidl
:
package com.yuandaima;
import com.yuandaima.Book;
interface IHelloService
{
int sayhelloin(in Book book);
int sayhelloout(out Book book);
int sayhelloinout(inout Book book);
oneway void sayhellooneway(in Book book);
}
接下来在项目目录下执行 aidl 编译命令:
aidl -I . IHelloService.aidl
执行完该命令后生成对应的 IHelloService.java
源码文件,我们来看下内部的 Proxy 类的实现:
private static class Proxy implements com.yuandaima.IHelloService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
//in 表示数据从客户端传递给服务端
@Override public int sayhelloin(com.yuandaima.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0); //数据写入 Parcel 对象
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_sayhelloin, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().sayhelloin(book);
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//out 表示数据从服务端回传给客户端
@Override public int sayhelloout(com.yuandaima.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
//发送前不会向 Parcel 写入数据
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_sayhelloout, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().sayhelloout(book);
}
_reply.readException();
_result = _reply.readInt();
if ((0!=_reply.readInt())) {
book.readFromParcel(_reply); //从返回数据中读出 book
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
// inout 表示数据从客户端传递给服务端,同时服务端也会传回客户端
@Override public int sayhelloinout(com.yuandaima.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0); // 数据写入 Parcel 对象
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_sayhelloinout, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().sayhelloinout(book);
}
_reply.readException();
_result = _reply.readInt();
if ((0!=_reply.readInt())) {
book.readFromParcel(_reply); //从返回数据中读出 book
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void sayhellooneway(com.yuandaima.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
//发送数据时,最后一个参数是 FLAG_ONEWAY,表示调用是异步的
boolean _status = mRemote.transact(Stub.TRANSACTION_sayhellooneway, _data, null, android.os.IBinder.FLAG_ONEWAY);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().sayhellooneway(book);
return;
}
}
finally {
_data.recycle();
}
}
public static com.yuandaima.IHelloService sDefaultImpl;
}
接着我们在看先服务端 onTransact 中是如何处理数据的:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_sayhelloin:
{
data.enforceInterface(descriptor);
com.yuandaima.Book _arg0;
if ((0!=data.readInt())) {
//从 Parcel 中读出数据
_arg0 = com.yuandaima.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
int _result = this.sayhelloin(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_sayhelloout:
{
data.enforceInterface(descriptor);
com.yuandaima.Book _arg0;
_arg0 = new com.yuandaima.Book();
int _result = this.sayhelloout(_arg0);
reply.writeNoException();
reply.writeInt(_result);
if ((_arg0!=null)) {
reply.writeInt(1);
// 将数据写入需要返回的 Parcel 对象中
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_sayhelloinout:
{
data.enforceInterface(descriptor);
com.yuandaima.Book _arg0;
if ((0!=data.readInt())) {
//读取数据
_arg0 = com.yuandaima.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
int _result = this.sayhelloinout(_arg0);
reply.writeNoException();
reply.writeInt(_result);
if ((_arg0!=null)) {
reply.writeInt(1);
//写入数据
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_sayhellooneway:
{
data.enforceInterface(descriptor);
com.yuandaima.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.yuandaima.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.sayhellooneway(_arg0);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
从源码我们可以看出,in out 的实现是通过是否从 Parcel 对象中读写数据实现的。oneway 是通过将 transact 方法最后一个参数设置为 FLAG_ONEWAY 实现的。
C++ 中的 AIDL 关键字解析
修改AIDL 数据类型详解之 C++ 篇中的示例程序:
修改项目中的 IHello.aidl:
package com.yuandaima;
import com.yuandaima.Student;
interface IHello
{
void hello();
int sum(int x, int y);
// int printList(in List<String> strs);
// int printMap(in Map maps);
int printStudent(in Student student);
int printStudent1(out Student student);
int printStudent2(inout Student student);
oneway void printStudent3(in Student student);
}
接着编译 aidl 文件:
aidl-cpp -I . com/yuandaima/IHello.aidl ./ ./IHello.cpp
接着我们看下生成的客户端代码:
::android::binder::Status BpHello::printStudent(const ::com::yuandaima::Student& student, int32_t* _aidl_return) {
::android::Parcel _aidl_data;
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//发送前向 Parcel 写入数据 student
_aidl_ret_status = _aidl_data.writeParcelable(student);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* printStudent */, _aidl_data, &_aidl_reply);
if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IHello::getDefaultImpl())) {
return IHello::getDefaultImpl()->printStudent(student, _aidl_return);
}
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
if (!_aidl_status.isOk()) {
return _aidl_status;
}
_aidl_ret_status = _aidl_reply.readInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}
::android::binder::Status BpHello::printStudent1(::com::yuandaima::Student* student, int32_t* _aidl_return) {
::android::Parcel _aidl_data;
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//发送前,不会将 student 写入 Parcel
_aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* printStudent1 */, _aidl_data, &_aidl_reply);
if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IHello::getDefaultImpl())) {
return IHello::getDefaultImpl()->printStudent1(student, _aidl_return);
}
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
if (!_aidl_status.isOk()) {
return _aidl_status;
}
_aidl_ret_status = _aidl_reply.readInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}
::android::binder::Status BpHello::printStudent2(::com::yuandaima::Student* student, int32_t* _aidl_return) {
::android::Parcel _aidl_data;
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//发送前向 Parcel 写入数据 student
_aidl_ret_status = _aidl_data.writeParcelable(*student);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 4 /* printStudent2 */, _aidl_data, &_aidl_reply);
if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IHello::getDefaultImpl())) {
return IHello::getDefaultImpl()->printStudent2(student, _aidl_return);
}
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
if (!_aidl_status.isOk()) {
return _aidl_status;
}
_aidl_ret_status = _aidl_reply.readInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//从返回的数据中读出 student
_aidl_ret_status = _aidl_reply.readParcelable(student);
if (( (_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}
::android::binder::Status BpHello::printStudent3(const ::com::yuandaima::Student& student) {
::android::Parcel _aidl_data;
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_ret_status = _aidl_data.writeParcelable(student);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//通过函数最后一个参数 FLAG_ONEWAY 指明远程调用是异步的
_aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 5 /* printStudent3 */, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IHello::getDefaultImpl())) {
return IHello::getDefaultImpl()->printStudent3(student);
}
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}
从源码中可以看出 native 代码和 Java 层是一样的:in out 的实现是通过是否从 Parcel 对象中读写数据实现的。oneway 是通过将 transact 函数最后一个参数设置为 FLAG_ONEWAY 实现的。
接着我们在看先服务端 onTransact 中是如何处理数据的:
::android::status_t BnHello::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
::android::status_t _aidl_ret_status = ::android::OK;
switch (_aidl_code) {
case ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* hello */:
{
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
::android::binder::Status _aidl_status(hello());
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
}
break;
case ::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* sum */:
{
int32_t in_x;
int32_t in_y;
int32_t _aidl_return;
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
_aidl_ret_status = _aidl_data.readInt32(&in_x);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_data.readInt32(&in_y);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
::android::binder::Status _aidl_status(sum(in_x, in_y, &_aidl_return));
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
_aidl_ret_status = _aidl_reply->writeInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
}
break;
// int printStudent(in Student student);
case ::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* printStudent */:
{
::com::yuandaima::Student in_student;
int32_t _aidl_return;
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
//从 Parcel 中读出 Student
_aidl_ret_status = _aidl_data.readParcelable(&in_student);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
::android::binder::Status _aidl_status(printStudent(in_student, &_aidl_return));
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
_aidl_ret_status = _aidl_reply->writeInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
}
break;
//int printStudent1(out Student student);
case ::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* printStudent1 */:
{
::com::yuandaima::Student out_student;
int32_t _aidl_return;
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
::android::binder::Status _aidl_status(printStudent1(&out_student, &_aidl_return));
//将 Student 写入 Parcel
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
_aidl_ret_status = _aidl_reply->writeInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_reply->writeParcelable(out_student);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
}
break;
// int printStudent2(inout Student student);
case ::android::IBinder::FIRST_CALL_TRANSACTION + 4 /* printStudent2 */:
{
::com::yuandaima::Student in_student;
int32_t _aidl_return;
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
// 从 Parcel 中读出 Student
_aidl_ret_status = _aidl_data.readParcelable(&in_student);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
::android::binder::Status _aidl_status(printStudent2(&in_student, &_aidl_return));
// 将 Student 写入 Parcel
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
_aidl_ret_status = _aidl_reply->writeInt32(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
_aidl_ret_status = _aidl_reply->writeParcelable(in_student);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
}
break;
case ::android::IBinder::FIRST_CALL_TRANSACTION + 5 /* printStudent3 */:
{
::com::yuandaima::Student in_student;
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
_aidl_ret_status = _aidl_data.readParcelable(&in_student);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
::android::binder::Status _aidl_status(printStudent3(in_student));
}
break;
default:
{
_aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags);
}
break;
}
if (_aidl_ret_status == ::android::UNEXPECTED_NULL) {
_aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply);
}
return _aidl_ret_status;
}
} // namespace yuandaima
} // namespace com