Android aidl

2022-12-30/2022-12-30

通常我们在做开发时,实现进程间通信用的最多的就是 AIDL。当我们定义好 AIDL 文件,在编译时编译器会帮我们生成代码实现 IPC 通信。借助 AIDL 编译以后的代码能帮助我们进一步理解 Binder IPC 的通信原理。

但是无论是从可读性还是可理解性上来看,编译器生成的代码对开发者并不友好。比如一个 BookManager.aidl 文件对应会生成一个 BookManager.java 文件,这个 java 文件包含了一个 BookManager 接口、一个 Stub 静态的抽象类和一个 Proxy 静态类。Proxy 是 Stub 的静态内部类,Stub 又是 BookManager 的静态内部类,这就造成了可读性和可理解性的问题。

aidl

IBinder : IBinder 是一个接口,代表了一种跨进程通信的能力。只要实现了这个借口,这个对象就能跨进程传输。

IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)

Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象。BinderProxy 类是 Binder 类的一个内部类,它代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。

Stub : AIDL 的时候,编译工具会给我们生成一个名为 Stub 的静态内部类;这个类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;Stub 是一个抽象类,具体的 IInterface 的相关实现需要开发者自己实现。

示例code:

IInterface 代表服务端进程具备的能力

/**
 * 这个类用来定义服务端 RemoteService 具备什么样的能力
 */
public interface BookManager extends IInterface {

    void addBook(Book book) throws RemoteException;
}

Stub 继承 Binder, 说明它是一个 Binder 本地对象;实现 IInterface 接口,表明具有 Server 承诺给 Client 的能力;Stub 是一个抽象类,具体的 IInterface 的相关实现需要调用方自己实现。

public abstract class Stub extends Binder implements BookManager {

    ...
    
   //通过asInterface将IBinder转化为BookManager这个IInterface对象
   //service会在onServiceConnected时传给client一个IBinder对象
   //接下来通过asInterface进行转换就可以进行IPC了
    public static BookManager asInterface(IBinder binder) {
        if (binder == null)
            return null;
        IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
        if (iin != null && iin instanceof BookManager)
            return (BookManager) iin;
        return new Proxy(binder);
    }

    ...

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {

            case INTERFACE_TRANSACTION:
                reply.writeString(DESCRIPTOR);
                return true;

            case TRANSAVTION_addBook:
                data.enforceInterface(DESCRIPTOR);
                Book arg0 = null;
                if (data.readInt() != 0) {
                    arg0 = Book.CREATOR.createFromParcel(data);
                }
                this.addBook(arg0);
                reply.writeNoException();
                return true;

        }
        return super.onTransact(code, data, reply, flags);
    }

    ...
}

asInterface会去调用 binder.queryLocalInterface() 去查找 Binder 本地对象,如果找到了就说明 Client 和 Server 在同一进程,那么这个 binder 本身就是 Binder 本地对象,可以直接使用。否则说需要我们创建一个代理对象 Proxy,通过这个代理对象来是实现远程访问。

public class Proxy implements BookManager {
    
    ...

    //IBinder是onServiceConnected服务端传进来的
    public Proxy(IBinder remote) {
        this.remote = remote;
    }

    @Override
    public void addBook(Book book) throws RemoteException {

        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            if (book != null) {
                data.writeInt(1);
                book.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            remote.transact(Stub.TRANSAVTION_addBook, data, replay, 0);
            replay.readException();
        } finally {
            replay.recycle();
            data.recycle();
        }
    }

    ...
}

我们看看 addBook() 的实现;在 Stub 类中,addBook(Book book) 是一个抽象方法,Client 端需要继承并实现它。

由于queryLocalInterface的存在,如果 Client 和 Server 在同一个进程,那么直接就是调用这个方法,如果是远程调用,Client 想要调用 Server 的方法就需要通过 Proxy来实现

在 Proxy 中的 addBook() 方法中首先将数据序列化,然后调用 remote.transact()。这里的 remote 是个 BinderProxy 对象。最终通过一系列的函数调用,Client 进程通过系统调用陷入内核态,Client 进程中执行 addBook() 的线程挂起等待返回;驱动完成一系列的操作之后唤醒 Server 进程,调用 Server 进程本地对象的 onTransact()。最终又走到了 Stub 中的 onTransact() 中,onTransact() 根据函数编号调用相关函数(在 Stub 类中为 BookManager 接口中的每个函数中定义了一个编号,只不过上面的源码中我们简化掉了;在跨进程调用的时候,不会传递函数而是传递编号来指明要调用哪个函数);我们这个例子里面,调用了 Binder 本地对象的 addBook() 并将结果返回给驱动,驱动唤醒 Client 进程里刚刚挂起的线程并将结果返回。这样一次跨进程调用就完成了。

server进程 Service类

public class RemoteService extends Service {

    private List<Book> books = new ArrayList<>();

    public RemoteService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();

        Book book = new Book();
        book.setName("三体");
        book.setPrice(88);
        books.add(book);
    }

    //在这里返回给client IBinder对象
    @Override
    public IBinder onBind(Intent intent) {
        return bookManager;
    }

    private final Stub bookManager = new Stub() {
        @Override
        public List<Book> getBooks() throws RemoteException {
            synchronized (this) {
                if (books != null) {
                    return books;
                }
                return new ArrayList<>();
            }
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            synchronized (this) {
                if (books == null) {
                    books = new ArrayList<>();
                }

                if (book == null)
                    return;

                book.setPrice(book.getPrice() * 2);
                books.add(book);

                Log.e("Server", "books: " + book.toString());
            }
        }
    };
}

client的使用

private BookManager bookManager;
	private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnection = true;
            bookManager = Stub.asInterface(service);
            if (bookManager != null) {
                try {
                    List<Book> books = bookManager.getBooks();
                    Log.d("ClientActivity", books.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isConnection = false;
        }
    };

AMS里的IPC

AOSP21

以AOSP21 的finish Activity为例

Activity类

/**
     * Finishes the current activity and specifies whether to remove the task associated with this
     * activity.
     */
    private void finish(boolean finishTask) {
        if (mParent == null) {
            int resultCode;
            Intent resultData;
            synchronized (this) {
                resultCode = mResultCode;
                resultData = mResultData;
            }
            if (false) Log.v(TAG, "Finishing self: token=" + mToken);
            try {
                if (resultData != null) {
                    resultData.prepareToLeaveProcess();
                }
                //在这里调用了ActivityManagerNative.getDefault()
                if (ActivityManagerNative.getDefault()
                        .finishActivity(mToken, resultCode, resultData, finishTask)) {
                    mFinished = true;
                }
            } catch (RemoteException e) {
                // Empty
            }
        } else {
            mParent.finishFromChild(this);
        }
    }

调用ActivityManagerNative.getDefault()返回结果后然后调用finishActivity,这个过程就是一个IPC过程,最终会调用到ActivityManagerService的finishActivity

来看看ActivityManagerNative.getDefault()

/**
     * Retrieve the system's default/global activity manager.
     */
    static public IActivityManager getDefault() {
        return gDefault.get();
    }

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

Singleton类是一个用来保存单例数据的类,泛型即为需要保存的单例对象

这里保存的为IActivityManager对象,定义了客户端和服务端方法调用的协议

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * System private API for talking with the activity manager service.  This
 * provides calls from the application back to the activity manager.
 *
 * {@hide}
 */
public interface IActivityManager extends IInterface {
    public boolean finishActivity(IBinder token, int code, Intent data, boolean finishTask)
            throws RemoteException;

    /** Information returned after waiting for an activity start. */
    public static class WaitResult implements Parcelable {
        public int result;
        public boolean timeout;
        public ComponentName who;
        public long thisTime;
        public long totalTime;

        public WaitResult() {
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(result);
            dest.writeInt(timeout ? 1 : 0);
            ComponentName.writeToParcel(who, dest);
            dest.writeLong(thisTime);
            dest.writeLong(totalTime);
        }

        public static final Parcelable.Creator<WaitResult> CREATOR
                = new Parcelable.Creator<WaitResult>() {
            @Override
            public WaitResult createFromParcel(Parcel source) {
                return new WaitResult(source);
            }

            @Override
            public WaitResult[] newArray(int size) {
                return new WaitResult[size];
            }
        };

        private WaitResult(Parcel source) {
            result = source.readInt();
            timeout = source.readInt() != 0;
            who = ComponentName.readFromParcel(source);
            thisTime = source.readLong();
            totalTime = source.readLong();
        }
    }

    String descriptor = "android.app.IActivityManager";

    // Remaining non-native transaction codes.
    int FINISH_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+10;
  
}

在create方法里,ServiceManager.getService会返回对应名字的远端服务进程的Stub对象,再通过asInterface进行转换

/**
     * Cast a Binder object into an activity manager interface, generating
     * a proxy if needed.
     */
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ActivityManagerProxy(obj);
    }

重点看ActivityManagerProxy,这里定义了client如何远程调用server的方法

class ActivityManagerProxy implements IActivityManager
{
    	public ActivityManagerProxy(IBinder remote)
    	{
        	mRemote = remote;
    	}

    	public IBinder asBinder()
    	{
        	return mRemote;
    	}
    
      	public boolean finishActivity(IBinder token, int resultCode, Intent resultData, boolean finishTask)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        data.writeInt(resultCode);
        if (resultData != null) {
            data.writeInt(1);
            resultData.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        data.writeInt(finishTask ? 1 : 0);
        mRemote.transact(FINISH_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        boolean res = reply.readInt() != 0;
        data.recycle();
        reply.recycle();
        return res;
    }
}

接下来Client 进程通过系统调用陷入内核态,Client 进程中执行 finishActivity() 的线程挂起等待返回;驱动完成一系列的操作之后唤醒 Server 进程,调用 Server 进程本地对象的 onTransact()。最终又走到了 Stub 中的 onTransact() 中

这里的server即为ActivityManagerService,真正执行命令在ActivityManagerService的finishActivity方法

public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    /**
     * This is the internal entry point for handling Activity.finish().
     *
     * @param token The Binder token referencing the Activity we want to finish.
     * @param resultCode Result code, if any, from this Activity.
     * @param resultData Result data (Intent), if any, from this Activity.
     * @param finishTask Whether to finish the task associated with this Activity.  Only applies to
     *            the root Activity in the task.
     *
     * @return Returns true if the activity successfully finished, or false if it is still running.
     */
    @Override
    public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
            boolean finishTask) {
        // Refuse possible leaked file descriptors
        if (resultData != null && resultData.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            ActivityRecord r = ActivityRecord.isInStackLocked(token);
            if (r == null) {
                return true;
            }
            // Keep track of the root activity of the task before we finish it
            TaskRecord tr = r.task;
            ActivityRecord rootR = tr.getRootActivity();
            // Do not allow task to finish in Lock Task mode.
            if (tr == mStackSupervisor.mLockTaskModeTask) {
                if (rootR == r) {
                    mStackSupervisor.showLockTaskToast();
                    return false;
                }
            }
            if (mController != null) {
                // Find the first activity that is not finishing.
                ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
                if (next != null) {
                    // ask watcher if this is allowed
                    boolean resumeOK = true;
                    try {
                        resumeOK = mController.activityResuming(next.packageName);
                    } catch (RemoteException e) {
                        mController = null;
                        Watchdog.getInstance().setActivityController(null);
                    }

                    if (!resumeOK) {
                        return false;
                    }
                }
            }
            final long origId = Binder.clearCallingIdentity();
            try {
                boolean res;
                if (finishTask && r == rootR) {
                    // If requested, remove the task that is associated to this activity only if it
                    // was the root activity in the task.  The result code and data is ignored because
                    // we don't support returning them across task boundaries.
                    res = removeTaskByIdLocked(tr.taskId, 0);
                } else {
                    res = tr.stack.requestFinishActivityLocked(token, resultCode,
                            resultData, "app-request", true);
                }
                return res;
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }
}

分析一下如果我们要手动通过client端的AMS来finish Activity怎么做

override fun finishLaunchActivity(message: Message) {
        try {
            val activityClientRecord = message.obj
            val tokenField = activityClientRecord.javaClass.getDeclaredField("token")
            tokenField.isAccessible = true
            val binder = tokenField[activityClientRecord] as IBinder
            finish(binder)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
    }

	private fun finish(binder: IBinder) {
        //这里的binder即为识别activity的token
        val activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative")
        val getDefaultMethod = activityManagerNativeClass.getDeclaredMethod("getDefault")
        val activityManager = getDefaultMethod.invoke(null)
        val finishActivityMethod = activityManager.javaClass.getDeclaredMethod(
            "finishActivity",
            IBinder::class.java,
            Int::class.javaPrimitiveType,
            Intent::class.java,
            Boolean::class.javaPrimitiveType
        )
        finishActivityMethod.invoke(
            activityManager,
            binder, Activity.RESULT_CANCELED, null, false
        )
    }

AOSP 30

/**
     * Finishes the current activity and specifies whether to remove the task associated with this
     * activity.
     */
    @UnsupportedAppUsage
    private void finish(int finishTask) {
        if (mParent == null) {
            int resultCode;
            Intent resultData;
            synchronized (this) {
                resultCode = mResultCode;
                resultData = mResultData;
            }
            if (false) Log.v(TAG, "Finishing self: token=" + mToken);
            try {
                if (resultData != null) {
                    resultData.prepareToLeaveProcess(this);
                }
                //在这里finish Activity
                if (ActivityTaskManager.getService()
                        .finishActivity(mToken, resultCode, resultData, finishTask)) {
                    mFinished = true;
                }
            } catch (RemoteException e) {
                // Empty
            }
        } else {
            mParent.finishFromChild(this);
        }

        // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
        // be restored now.
        if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
            restoreAutofillSaveUi();
        }
    }

接着分析ActivityTaskManager

@SystemService(Context.ACTIVITY_TASK_SERVICE)
public class ActivityTaskManager {
    /** @hide */
    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }
    
    @UnsupportedAppUsage(trackingBug = 129726065)
    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };
}

最终会调用到ActivityTaskManagerService的finishActivity

/**
     * This is the internal entry point for handling Activity.finish().
     *
     * @param token The Binder token referencing the Activity we want to finish.
     * @param resultCode Result code, if any, from this Activity.
     * @param resultData Result data (Intent), if any, from this Activity.
     * @param finishTask Whether to finish the task associated with this Activity.
     *
     * @return Returns true if the activity successfully finished, or false if it is still running.
     */
    @Override
    public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
            int finishTask) {
        // Refuse possible leaked file descriptors
        if (resultData != null && resultData.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        final ActivityRecord r;
        synchronized (mGlobalLock) {
            r = ActivityRecord.isInStackLocked(token);
            if (r == null) {
                return true;
            }
        }

        // Carefully collect grants without holding lock
        final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo);

        synchronized (mGlobalLock) {
            // Sanity check in case activity was removed before entering global lock.
            if (!r.isInHistory()) {
                return true;
            }

            // Keep track of the root activity of the task before we finish it
            final Task tr = r.getTask();
            final ActivityRecord rootR = tr.getRootActivity();
            if (rootR == null) {
                Slog.w(TAG, "Finishing task with all activities already finished");
            }
            // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
            // finish.
            if (getLockTaskController().activityBlockedFromFinish(r)) {
                return false;
            }

            // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked
            // We should consolidate.
            if (mController != null) {
                // Find the first activity that is not finishing.
                final ActivityRecord next =
                        r.getRootTask().topRunningActivity(token, INVALID_TASK_ID);
                if (next != null) {
                    // ask watcher if this is allowed
                    boolean resumeOK = true;
                    try {
                        resumeOK = mController.activityResuming(next.packageName);
                    } catch (RemoteException e) {
                        mController = null;
                        Watchdog.getInstance().setActivityController(null);
                    }

                    if (!resumeOK) {
                        Slog.i(TAG, "Not finishing activity because controller resumed");
                        return false;
                    }
                }
            }

            // note down that the process has finished an activity and is in background activity
            // starts grace period
            if (r.app != null) {
                r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis());
            }

            final long origId = Binder.clearCallingIdentity();
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity");
            try {
                boolean res;
                final boolean finishWithRootActivity =
                        finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
                if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
                        || (finishWithRootActivity && r == rootR)) {
                    // If requested, remove the task that is associated to this activity only if it
                    // was the root activity in the task. The result code and data is ignored
                    // because we don't support returning them across task boundaries. Also, to
                    // keep backwards compatibility we remove the task from recents when finishing
                    // task with root activity.
                    mStackSupervisor.removeTask(tr, false /*killProcess*/,
                            finishWithRootActivity, "finish-activity");
                    res = true;
                    // Explicitly dismissing the activity so reset its relaunch flag.
                    r.mRelaunchReason = RELAUNCH_REASON_NONE;
                } else {
                    r.finishIfPossible(resultCode, resultData, resultGrants,
                            "app-request", true /* oomAdj */);
                    res = r.finishing;
                    if (!res) {
                        Slog.i(TAG, "Failed to finish by app-request");
                    }
                }
                return res;
            } finally {
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                Binder.restoreCallingIdentity(origId);
            }
        }
    }
评论
发表评论
       
       
取消