01-18-04 AIDL接口定义语言

AIDL是什么

AIDL(Android Interface Definition Language)是Android的接口定义语言,用于定义跨进程通信的接口。

核心作用

  • 定义客户端和服务端通信的接口
  • 自动生成Binder代理代码
  • 实现进程间通信(IPC)

为什么需要AIDL

跨进程通信场景

应用A进程                    系统服务进程
  ↓                            ↓
想获取应用列表         →    PackageManagerService
  ↓                            ↓
需要跨进程通信         ←    返回应用列表

问题

  • 不同进程内存隔离,无法直接调用
  • 需要序列化数据传递
  • 需要处理异步调用

解决方案:Binder + AIDL

AIDL基础语法

1. 定义AIDL接口

// IBookManager.aidl
package com.example.bookstore;

import com.example.bookstore.Book;

interface IBookManager {
    // 获取书籍列表
    List<Book> getBookList();

    // 添加书籍
    void addBook(in Book book);

    // 删除书籍
    void removeBook(in Book book);

    // 根据ID查询
    Book getBookById(int bookId);

    // 注册监听器
    void registerListener(IBookListener listener);

    // 取消监听器
    void unregisterListener(IBookListener listener);
}

2. 定义数据类型

// Book.aidl
package com.example.bookstore;

parcelable Book;
// Book.kt - 必须实现Parcelable
package com.example.bookstore

import android.os.Parcel
import android.os.Parcelable

data class Book(
    val id: Int,
    val name: String,
    val author: String,
    val price: Float
) : Parcelable {

    constructor(parcel: Parcel) : this(
        parcel.readInt(),
        parcel.readString() ?: "",
        parcel.readString() ?: "",
        parcel.readFloat()
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(id)
        parcel.writeString(name)
        parcel.writeString(author)
        parcel.writeFloat(price)
    }

    override fun describeContents() = 0

    companion object CREATOR : Parcelable.Creator<Book> {
        override fun createFromParcel(parcel: Parcel) = Book(parcel)
        override fun newArray(size: Int): Array<Book?> = arrayOfNulls(size)
    }
}

3. 定义回调接口

// IBookListener.aidl
package com.example.bookstore;

import com.example.bookstore.Book;

interface IBookListener {
    // 书籍添加通知
    void onBookAdded(in Book book);

    // 书籍删除通知
    void onBookRemoved(in Book book);
}

AIDL生成的代码

自动生成的Stub类

// 编译后生成:IBookManager.java
public interface IBookManager extends android.os.IInterface {

    // Stub类:服务端继承
    public static abstract class Stub extends android.os.Binder
            implements com.example.bookstore.IBookManager {

        private static final java.lang.String DESCRIPTOR = "com.example.bookstore.IBookManager";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        // 将IBinder转换为接口
        public static com.example.bookstore.IBookManager asInterface(android.os.IBinder obj) {
            if (obj == null) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (iin != null && iin instanceof com.example.bookstore.IBookManager) {
                // 同进程,直接返回
                return (com.example.bookstore.IBookManager) iin;
            }
            // 跨进程,返回代理
            return new com.example.bookstore.IBookManager.Stub.Proxy(obj);
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
            switch (code) {
                case TRANSACTION_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    // 调用实际实现
                    java.util.List<com.example.bookstore.Book> result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    com.example.bookstore.Book book;
                    if (data.readInt() != 0) {
                        book = com.example.bookstore.Book.CREATOR.createFromParcel(data);
                    } else {
                        book = null;
                    }
                    this.addBook(book);
                    reply.writeNoException();
                    return true;
                }
                // ... 其他方法
            }
            return super.onTransact(code, data, reply, flags);
        }

        // Proxy类:客户端使用
        private static class Proxy implements com.example.bookstore.IBookManager {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public java.util.List<com.example.bookstore.Book> getBookList()
                    throws android.os.RemoteException {
                android.os.Parcel data = android.os.Parcel.obtain();
                android.os.Parcel reply = android.os.Parcel.obtain();
                java.util.List<com.example.bookstore.Book> result;
                try {
                    data.writeInterfaceToken(DESCRIPTOR);
                    // 发起跨进程调用
                    mRemote.transact(Stub.TRANSACTION_getBookList, data, reply, 0);
                    reply.readException();
                    result = reply.createTypedArrayList(com.example.bookstore.Book.CREATOR);
                } finally {
                    reply.recycle();
                    data.recycle();
                }
                return result;
            }

            @Override
            public void addBook(com.example.bookstore.Book book)
                    throws android.os.RemoteException {
                android.os.Parcel data = android.os.Parcel.obtain();
                android.os.Parcel reply = android.os.Parcel.obtain();
                try {
                    data.writeInterfaceToken(DESCRIPTOR);
                    if (book != null) {
                        data.writeInt(1);
                        book.writeToParcel(data, 0);
                    } else {
                        data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, data, reply, 0);
                    reply.readException();
                } finally {
                    reply.recycle();
                    data.recycle();
                }
            }

            // ... 其他方法
        }

        // 方法ID常量
        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        // ...
    }

    // 接口方法声明
    public java.util.List<com.example.bookstore.Book> getBookList() throws android.os.RemoteException;
    public void addBook(com.example.bookstore.Book book) throws android.os.RemoteException;
    // ...
}

服务端实现

1. 实现AIDL接口

class BookManagerService : Service() {

    // 书籍列表(线程安全)
    private val bookList = CopyOnWriteArrayList<Book>()

    // 监听器列表
    private val listenerList = RemoteCallbackList<IBookListener>()

    // Binder对象
    private val binder = object : IBookManager.Stub() {

        override fun getBookList(): List<Book> {
            // 可能被多个客户端同时调用,注意线程安全
            return ArrayList(bookList)
        }

        override fun addBook(book: Book?) {
            book ?: return

            synchronized(bookList) {
                // 检查是否已存在
                if (bookList.any { it.id == book.id }) {
                    return
                }

                bookList.add(book)

                // 通知所有监听器
                notifyBookAdded(book)
            }
        }

        override fun removeBook(book: Book?) {
            book ?: return

            synchronized(bookList) {
                bookList.removeAll { it.id == book.id }

                // 通知所有监听器
                notifyBookRemoved(book)
            }
        }

        override fun getBookById(bookId: Int): Book? {
            return bookList.find { it.id == bookId }
        }

        override fun registerListener(listener: IBookListener?) {
            listener ?: return
            listenerList.register(listener)
        }

        override fun unregisterListener(listener: IBookListener?) {
            listener ?: return
            listenerList.unregister(listener)
        }
    }

    override fun onBind(intent: Intent?): IBinder {
        return binder
    }

    /**
     * 通知所有监听器:书籍已添加
     */
    private fun notifyBookAdded(book: Book) {
        val count = listenerList.beginBroadcast()
        for (i in 0 until count) {
            try {
                listenerList.getBroadcastItem(i).onBookAdded(book)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
        listenerList.finishBroadcast()
    }

    /**
     * 通知所有监听器:书籍已删除
     */
    private fun notifyBookRemoved(book: Book) {
        val count = listenerList.beginBroadcast()
        for (i in 0 until count) {
            try {
                listenerList.getBroadcastItem(i).onBookRemoved(book)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
        listenerList.finishBroadcast()
    }
}

2. 注册Service

<!-- AndroidManifest.xml -->
<service
    android:name=".BookManagerService"
    android:process=":remote"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.bookstore.IBookManager"/>
    </intent-filter>
</service>

客户端调用

1. 绑定Service

class MainActivity : AppCompatActivity() {

    private var bookManager: IBookManager? = null
    private var isBound = false

    // ServiceConnection
    private val connection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            // 获取服务接口
            bookManager = IBookManager.Stub.asInterface(service)
            isBound = true

            // 注册监听器
            registerListener()

            // 使用服务
            loadBooks()
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            bookManager = null
            isBound = false
        }
    }

    // 监听器实现
    private val listener = object : IBookListener.Stub() {
        override fun onBookAdded(book: Book?) {
            book ?: return
            // 在Binder线程调用,需要切换到主线程
            runOnUiThread {
                Toast.makeText(this@MainActivity, "新书:${book.name}", Toast.LENGTH_SHORT).show()
                loadBooks()
            }
        }

        override fun onBookRemoved(book: Book?) {
            book ?: return
            runOnUiThread {
                Toast.makeText(this@MainActivity, "删除:${book.name}", Toast.LENGTH_SHORT).show()
                loadBooks()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 绑定服务
        bindBookService()
    }

    private fun bindBookService() {
        val intent = Intent().apply {
            action = "com.example.bookstore.IBookManager"
            setPackage(packageName)  // Android 5.0+需要显式指定包名
        }
        bindService(intent, connection, Context.BIND_AUTO_CREATE)
    }

    private fun registerListener() {
        try {
            bookManager?.registerListener(listener)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    private fun loadBooks() {
        try {
            val books = bookManager?.getBookList()
            // 更新UI
            updateBookList(books)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    fun onAddBookClick(view: View) {
        val book = Book(
            id = System.currentTimeMillis().toInt(),
            name = "Android开发艺术探索",
            author = "任玉刚",
            price = 79f
        )

        try {
            bookManager?.addBook(book)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    override fun onDestroy() {
        super.onDestroy()

        // 取消监听器
        if (isBound) {
            try {
                bookManager?.unregisterListener(listener)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
            unbindService(connection)
        }
    }

    private fun updateBookList(books: List<Book>?) {
        // 更新RecyclerView
    }
}

AIDL参数定向标记

in、out、inout的区别

interface IDataManager {
    // in:数据从客户端流向服务端(默认)
    void setData(in Data data);

    // out:数据从服务端流向客户端
    void getData(out Data data);

    // inout:双向传递
    void processData(inout Data data);
}

性能影响

  • in:只序列化一次(客户端→服务端)
  • out:只序列化一次(服务端→客户端)
  • inout:序列化两次(往返)

最佳实践

// [通过] 使用in(默认)
void addBook(in Book book);

// [未通过] 不必要的inout
// void addBook(inout Book book);

AIDL支持的数据类型

1. 基本类型

interface IDataManager {
    void setInt(int value);
    void setLong(long value);
    void setFloat(float value);
    void setDouble(double value);
    void setBoolean(boolean value);
    void setString(String value);
}

2. 集合类型

interface IDataManager {
    List<String> getStringList();
    Map<String, String> getStringMap();
}

3. Parcelable对象

// 需要单独的.aidl文件声明
parcelable Book;

4. 其他AIDL接口

interface IBookManager {
    void registerListener(IBookListener listener);
}

常见问题

问题1:RemoteException处理

// [未通过] 忘记处理RemoteException
fun getBooks() {
    val books = bookManager?.getBookList()  // 可能抛RemoteException
}

// [通过] 正确处理
fun getBooks() {
    try {
        val books = bookManager?.getBookList()
        // 处理数据
    } catch (e: RemoteException) {
        e.printStackTrace()
        // 处理异常:可能服务已崩溃
    }
}

问题2:Binder线程切换

// [未通过] 在Binder线程更新UI
private val listener = object : IBookListener.Stub() {
    override fun onBookAdded(book: Book?) {
        // 在Binder线程,不能直接更新UI
        textView.text = book?.name  // 崩溃!
    }
}

// [通过] 切换到主线程
private val listener = object : IBookListener.Stub() {
    override fun onBookAdded(book: Book?) {
        book ?: return
        runOnUiThread {
            textView.text = book.name
        }
    }
}

问题3:监听器泄漏

// [通过] 取消监听器
override fun onDestroy() {
    super.onDestroy()
    try {
        bookManager?.unregisterListener(listener)
    } catch (e: RemoteException) {
        e.printStackTrace()
    }
    unbindService(connection)
}

问题4:权限控制

// 服务端检查权限
private val binder = object : IBookManager.Stub() {

    override fun addBook(book: Book?) {
        // 检查调用者权限
        if (checkCallingPermission("com.example.BOOK_PERMISSION") !=
            PackageManager.PERMISSION_GRANTED) {
            throw SecurityException("No permission")
        }

        // 业务逻辑
        bookList.add(book)
    }
}

总结

AIDL核心概念

  1. AIDL接口:定义跨进程通信的契约
  2. Stub类:服务端实现,处理请求
  3. Proxy类:客户端代理,发起请求
  4. Binder:底层IPC机制

使用流程

  1. 定义AIDL接口
  2. 实现Stub(服务端)
  3. 绑定Service获取代理(客户端)
  4. 调用接口方法
  5. 处理RemoteException

最佳实践

  • 使用in参数(默认)
  • 处理RemoteException
  • Binder线程切换到主线程
  • 取消监听器避免泄漏
  • 服务端检查权限

Android 16 (API 36) AIDL变化

稳定AIDL语言进一步推广

更多系统服务迁移到稳定AIDL

// Android 16:更多系统服务使用稳定AIDL定义
// 取代传统非稳定AIDL接口
@VintfStability
interface IActivityTaskManager {
    // 稳定接口,保证长期兼容性
    int startActivity(in Intent intent, String resolvedType,
        IBinder resultTo, String resultWho, int requestCode,
        int startFlags, in ProfilerInfo profilerInfo, in Bundle options);
}

AIDL生成的代码优化

Kotlin AIDL支持增强

// Android 16:AIDL 对 Kotlin 的默认参数支持更好
// 生成的 Stub 代码更加 Kotlin 友好
interface IBookManager {
    // 支持 default 参数值
    void addBook(in Book book, boolean notifyListener = true);
}

性能优化

Android 16 的 Binder 事务处理优化:
- 减少跨进程调用的序列化开销
- 优化的 Parcel 读写性能
- 更好的 Binder 线程池调度
- 支持更大的事务缓冲区

关键要点:AIDL是Android跨进程通信的标准方案,理解其生成的代码有助于掌握Binder机制

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐