android aidl --支持类型?同步还是异步?

本文深入探讨了Android中AIDL(Android Interface Definition Language)和Binder机制的工作原理,包括它们的作用、支持的数据类型、同步与异步通信的区别,以及如何通过AIDL实现进程间通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

一、作用

aidl用于android中进程间通信,远程服务端的接口方法在aidl中声明,当客户端 绑定服务器成功后返回的binder对象转成aidl支持的类型并调用之前声明的接口方法即可实现客户端与远程服务器的跨进程通信。

其实不提供aidl文件也可以实现Binder,之所以提供aidl文件,是为了方便系统为我们生成代码,我们也可以手动写一个Binder。

 

二、支持类型

 

aidl支持如下数据类型:

1、基本数据类型
2、String和CharSequence
3、ArrayList(里面的每个元素必须支持aidl)
4、HashMap(里面的每个元素必须支持aidl,包括key和value)
5、Parcelable

 

6、aidl本身

 

值得注意的是除了基本类型,其他类型参数需要加上流向:in(只能客户端流向服务端),out(只能服务端流向客户端),inout(可以在客户端和服务端双向流动)

三、同步or异步

1、绑定过程

之前在startService过程中介绍了startService的启动过程,其实bindService方法与startService有很多相通之处。先说结论,bindService方法是异步的,可以看下面的log打印,bindFaceUnlockService success在FaceUnlock connected打印之前,所以bindService方法并不等待ServiceConnection 连接成功与否。

private void bindKeyguardService() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                LogUtil.d("---bindFaceUnlokService start");
                Intent localIntent = new Intent();
                localIntent.setClassName(Const.KEYGUARD_PACKAGE, Const.KEYGUARD_CLASS);
                if (bindService(localIntent, mServiceConn, Context.BIND_AUTO_CREATE)) {
                    LogUtil.d("---bindFaceUnlockService success---");
                } else {
                    LogUtil.d("---bindFaceUnlokService failed---");
                }
                LogUtil.d("---bindFaceUnlokService end");
            }
        }).start();
    }

    private ServiceConnection mServiceConn = new ServiceConnection() {

        public void onServiceConnected(ComponentName paramAnonymousComponentName, IBinder binder) {
            LogUtil.v("*** FaceUnlock connected (yay!)");
            mService = IService.Stub.asInterface(binder);            
        }

        public void onServiceDisconnected(ComponentName paramAnonymousComponentName) {
            LogUtil.d("*** FaceUnlock onServiceDisconnected");
            mService = null;
        }
    };

log打印如下:

05-25 18:18:35.352 7944-7966: (FaceUnlockService.java:568)run->---bindFaceUnlokService start
05-25 18:18:35.359 7944-7966: (FaceUnlockService.java:572)run->---bindFaceUnlockService success---
    (FaceUnlockService.java:576)run->---bindFaceUnlokService end
05-25 18:18:35.428 7944-7944: (FaceUnlockService.java:584)onServiceConnected->*** FaceUnlock connected (yay!)

知道了结果,那么我们从源码角度看下为什么是异步把。

bindService方法调用了ContextWrapper.bindService方法,在该方法里面调用了mBase的bindService方法,mBase是什么呢?startService过程一文中有讲过mBase是在ActivityThread.java中通过createBaseContextForActivity方法创建的ContextImpl 实例,并调用ContextWrapper.attachBaseContext方法传递过来的,所以这里的mBase就是一个ContextImpl 实例。

   //ContextWrapper.java

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

看下ContextImpl.java中bindService的具体实现调用了bindServiceCommon方法,在bindServiceCommon方法对conn、handler、excutor做了一些参数检查后,最终调用了AMS的bindIsolatedService方法,到目前为止方法都是同步的,继续跟进。

//ContextImpl.java

@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
            getUser());
}

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        if (conn == null) { //判断conn是否为null,为null则返回参数异常
            throw new IllegalArgumentException("connection is null");
        }
        if (handler != null && executor != null) {
            throw new IllegalArgumentException("Handler and Executor both supplied");
        }
        if (mPackageInfo != null) {
            if (executor != null) {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags); //这个sd就是一个IServiceConnection对象,最后通过IServiceConnection调用conn的onServiceConnected方法
            } else {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
        //最终调用了AMS的bindIsolatedService方法
            int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

AMS的bindIsolatedService方法前面忽略部分是一些参数检查,最终调用了ActiveServices.java的方法。

//ActivityManagerService.java  

public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String instanceName,
            String callingPackage, int userId) throws TransactionTooLargeException {
        enforceNotIsolatedCaller("bindService");

……

        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    }

ActiveServices.bindServiceLocked前面省略号部分是一些参数与权限检查,然后创建对象保存调用者信息,先调用调用了bringUpServiceLocked来创建service,后面再通过requestServiceBindingLocked方法绑定service。

//ActiveServices.java   

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
 ……

            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);

            IBinder binder = connection.asBinder();
            s.addConnection(binder, c);
            b.connections.add(c);
            if (activity != null) {
                activity.addConnection(c);
            }
            b.client.connections.add(c);
           ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);
//一般bindService时候第三个参数都选择BIND_AUTO_CREATE,所以这个if条件一般是成立的
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
   //先创建service
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
……
//然后绑定service
        requestServiceBindingLocked(s, b.intent, callerFg, false);
        return 1;
    }

startService过程一文中我们讲到过bringUpServiceLocked方法会调用realStartServiceLocked方法,realStartServiceLocked调用ActivityThread.java中的内部类ApplicationThread类的scheduleCreateService方法发送创建service的消息,后面的流程startService过程有介绍,就不多说了。

   //ActiveServices.java   

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
……
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            r.postNotification();
            created = true;
 ……
    }

同理,requestServiceBindingLocked方法调用ActivityThread.java中的内部类ApplicationThread类scheduleBindService方法。

   //ActiveServices.java     

 private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
        }
        if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
                + " rebind=" + rebind);
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//发送绑定service消息
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.getReportedProcState());
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
                // Keep the executeNesting count accurate.
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                throw e;
            } catch (RemoteException e) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                return false;
            }
        }
        return true;
    }

由于bringUpServiceLocked方法和requestServiceBindingLocked方法都是发消息的异步方法,所以最终bindservice是异步的。

知道了bindservice异步的,那么绑定service的ServiceConnection内部类的onServiceConnected方法什么时候执行呢,继续看下具体流程。

    //ActivityThread$ApplicationThread.java

 public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;

            if (DEBUG_SERVICE)
                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());

            sendMessage(H.BIND_SERVICE, s);
        }

发送的消息最后在名称为H的handler中处理,然后调用了AMS的publishService方法。

       //ActivityThread$H.java

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
             ……
                case CREATE_SERVICE:
                    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                                ("serviceCreate: " + String.valueOf(msg.obj)));
                    }
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                  //具体绑定服务
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
         ……
    }


  private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {//是否是第一次绑定
                        IBinder binder = s.onBind(data.intent);
                       //订阅分发
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {//重新绑定
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

AMS调用了publishService方法接着调用了ActiveServices.publishServiceLocked方法,然后c.conn.connected被调用,c.conn是一个IServiceConnection对象,该对象是在ContextImpl.bindServiceCommon方法中调用LoadedApk.java的getServiceDispatcher方法创建的。

// ActiveServices.java

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                    + " " + intent + ": " + service);
            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
                    for (int conni = connections.size() - 1; conni >= 0; conni--) {
                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Not publishing to: " + c);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Published intent: " + intent);
                                continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            try {
                               //绑定连接成功
                                c.conn.connected(r.name, service, false);
                            } catch (Exception e) {
                                Slog.w(TAG, "Failure sending service " + r.shortInstanceName
                                      + " to connection " + c.conn.asBinder()
                                      + " (in " + c.binding.client.processName + ")", e);
                            }
                        }
                    }
                }

                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

最终app端的ServiceConnection类中回调得到执行。

//LoadedApk.java      

public void doConnected(ComponentName name, IBinder service, boolean dead) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

            synchronized (this) {
                if (mForgotten) {
                    // We unbound before receiving the connection; ignore
                    // any connection received.
                    return;
                }
                old = mActiveConnections.get(name);
                if (old != null && old.binder == service) {
                    // Huh, already have this one.  Oh well!
                    return;
                }

                if (service != null) {
                    // A new service is being connected... set it all up.
                    info = new ConnectionInfo();
                    info.binder = service;
                    info.deathMonitor = new DeathMonitor(name, service);
                    try {
                        service.linkToDeath(info.deathMonitor, 0);
                        mActiveConnections.put(name, info);
                    } catch (RemoteException e) {
                        // This service was dead before we got it...  just
                        // don't do anything with it.
                        mActiveConnections.remove(name);
                        return;
                    }

                } else {
                    // The named service is being disconnected... clean up.
                    mActiveConnections.remove(name);
                }

                if (old != null) {
                    old.binder.unlinkToDeath(old.deathMonitor, 0);
                }
            }

            // If there was an old service, it is now disconnected.
            if (old != null) {
//连接断开
                mConnection.onServiceDisconnected(name);
            }
            if (dead) {
//连接消亡
                mConnection.onBindingDied(name);
            }
            // If there is a new viable service, it is now connected.
            if (service != null) {
//连接建立
                mConnection.onServiceConnected(name, service);
            } else {
                // The binding machinery worked, but the remote returned null from onBind().
                mConnection.onNullBinding(name);
            }
        }

2、方法调用过程

客户端和服务器进行方法通信分为两个场景:(1)客户端和服务器处于相同的进程; (2)客户端和服务器处于不同的进程。

客户端调用远程服务默认是同步的,对于场景(1)处于相同进程的场景,如果想达到异步的效果,那么只能开启一个线程去处理了;对于场景(2)客户端和服务器处于不同进程则可以通过在定义aidl接口时增加oneway关键字来解决问题。

// IMyAidlInterface.aidl
package com.example.myapplication.serviceTest;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    int plus(int a,int b);  //同步
    String toUpperCase(String str); //同步
    oneway void asyDo();  //挂进程可以实现异步
}

可以看下as自动生成的代码:

//app\build\generated\aidl_source_output_dir\debug\out\com\example\myapplication\serviceTest\IMyAidlInterface.java    

 @Override public int plus(int a, int b) 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);
          _data.writeInt(a);
          _data.writeInt(b);
          boolean _status = mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0); //默认0,同步方式
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().plus(a, b);
          }
          _reply.readException();
          _result = _reply.readInt();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.lang.String _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeString(str);
          boolean _status = mRemote.transact(Stub.TRANSACTION_toUpperCase, _data, _reply, 0); //默认0,同步方式
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().toUpperCase(str);
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void asyDo() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_asyDo, _data, null, android.os.IBinder.FLAG_ONEWAY); //可以跨进程异步
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().asyDo();
            return;
          }
        }
        finally {
          _data.recycle();
        }
      }
      public static com.example.myapplication.serviceTest.IMyAidlInterface sDefaultImpl;
    }

如上面文字注释关键是mRemote.transact(Stub.TRANSACTION_exec, _data, _reply, 0)方法的最后一个参数,那么看下 android.os.IBinder.FLAG_ONEWAY的解释,里面解释到只有客户端和服务器处于不同线程才可以异步调用。
客户端连接远程服务成功后执行远程服务方法默认也是同步的,第四个参数flags为0 

transact(int code, Parcel data, Parcel reply, int flags)

如果接口用oneway修饰,那么参数变为1,接收远程服务方法是异步的

mRemote.transact(int code, Parcel data, Parcel reply,  android.os.IBinder.FLAG_ONEWAY);
 /**
     * Flag to {@link #transact}: this is a one-way call, meaning that the
     * caller returns immediately, without waiting for a result from the
     * callee. Applies only if the caller and callee are in different
     * processes.
     *
     * <p>The system provides special ordering semantics for multiple oneway calls
     * being made to the same IBinder object: these calls will be dispatched in the
     * other process one at a time, with the same order as the original calls.  These
     * are still dispatched by the IPC thread pool, so may execute on different threads,
     * but the next one will not be dispatched until the previous one completes.  This
     * ordering is not guaranteed for calls on different IBinder objects or when mixing
     * oneway and non-oneway calls on the same IBinder object.</p>
     */
    int FLAG_ONEWAY             = 0x00000001;

demo传送门 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值