Binder機制(1)-從framework分析AIDL生成文件

主目錄見:Android高級進階知識(這是總目錄索引)
?為什么要突然講這一章呢?因為后面要開始講Framework的代碼,有太多應用到AIDL機制了。所以想在這里給大家介紹清楚這個,但是我不能保證我講的很清楚,不過希望大家自己能學懂,為后面的打下基礎,下面可能有塊硬骨頭要啃,我們上圖休息一下:

Relax

一.目標

今天講這個的原因前面已經講了,我們今天的目標就是搞懂AIDL的生成文件,然后明白調用過程,所以目標如下:
1.清楚AIDL生成文件的代碼結構;
2.從bindService的過程來了解調用過程。

二.AIDL生成文件分析

?為了分析AIDL生成文件,我們首先得來看看AIDL要怎么應用,就是怎么個寫法,我們這里還是以[LRouter]項目中的跨進程部分來講。首先我們來看看我們是怎么寫的:
1.首先要編寫aidl文件用于自動生成代碼

package com.lenovohit.lrouter_api;
import com.lenovohit.lrouter_api.core.LRouterRequest;

interface IRemoteRouterAIDL {
    boolean stopRouter(String processName);
    boolean checkIfLocalRouterAsync(String processName,in LRouterRequest routerRequset);
    String navigation(String processName,in LRouterRequest routerRequest);
}

2.接著我們要編寫一個服務,然后把Stub綁定到這個服務上

public final class RemoteRouterService extends Service {
    private static final String TAG = "RemoteRouterService";
    public static final String PROCESS_NAME = "process_name";

    @Override
    public void onCreate() {
        super.onCreate();
        if (!(getApplication() instanceof LRouterAppcation)) {
            throw new LRException("請檢查你的AndroidManifest.xml和applicaiton是LRouterApplicaiton");
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_NOT_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
.....
          return mStub;
    }

    IRemoteRouterAIDL.Stub mStub = new IRemoteRouterAIDL.Stub() {
//省略實現的方法
......
    };
}

3.編寫ServiceConnection在onServiceConnected得到遠程服務代理對象

 private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mRemoteRouterAIDL = IRemoteRouterAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mRemoteRouterAIDL = null;
        }
    };

4.最后綁定服務

        Intent bindRemoteRouterServiceIntent = new Intent(mLRouterAppcation,RemoteRouterService.class);
        bindRemoteRouterServiceIntent.putExtra(RemoteRouterService.PROCESS_NAME,processName);
        mLRouterAppcation.bindService(bindRemoteRouterServiceIntent,mServiceConnection, BIND_AUTO_CREATE);

到這里我們的使用就已經完成了,當然有些小細節沒有說,不過沒關系,這篇不是為了講具體的使用方法的,大家應該要已經知道怎么使用了。

1.bindService

要想把這一整套流程都講清楚就得從綁定服務開始,這里不像系統服務的啟動和注冊需要ServiceManager管理。這里我們應用的服務直接從bindService開始講就可以。我們看到前面綁定服務的時候是Application里面的bindService()方法,但是查找的時候會發現這里面沒有這個方法,而且在基類ContextWrapper中:

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

這里的mBase是個ContextImpl對象,于是調用ContextImpl的bindService方法:

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

我們看到這里調用了bindServiceCommon()方法:

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
       ....
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
       .....
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

前面的mMainThread是一個ActivityThread對象,通過他的getHandler()方法得到一個Handler對象,有了這個Handler對象,就可以把消息發送到ActivityThread所在線程的消息隊列中了。然后我們看到最終會把這個handler放進ServiceDispatcher中去。這里的mPackageInfo就是我們的LoadedApk對象,所以我們看到LoadedApk的getServiceDispatcher()方法:

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (map == null) {
                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

我們看到這里主要就是將ServiceConnection的對象,handler等傳給ServiceDispatcher對象,我們看下ServiceDispatcher類是長啥樣的:

 static final class ServiceDispatcher {
        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        private final ServiceConnection mConnection;
        private final Context mContext;
        private final Handler mActivityThread;
        private final ServiceConnectionLeaked mLocation;
        private final int mFlags;

        private RuntimeException mUnbindLocation;

        private boolean mForgotten;

        private static class ConnectionInfo {
            IBinder binder;
            IBinder.DeathRecipient deathMonitor;
        }

        private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }

            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }
.......
        ServiceDispatcher(ServiceConnection conn,
                Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);
            mConnection = conn;
            mContext = context;
            mActivityThread = activityThread;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
        }
.......
}

?我們看到ServiceDispatcher內部還創建了一個InnerConnection對象,這是一個Binder對象,一會是要傳遞給ActivityManagerService的,ActivityManagerServic后續就是要通過這個Binder對象和ServiceConnection通信的。
?函數getServiceDispatcher最后就是返回了一個InnerConnection對象給ContextImpl.bindService函數。回到ContextImpl.bindService函數中,它接著就要調用ActivityManagerService的遠程接口來進一步處理了。接著我們程序會調用 ActivityManagerNative.getDefault().bindService()方法來訪問遠程服務:

  public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags,  String callingPackage, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeStrongBinder(token);
        service.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(connection.asBinder());
        data.writeInt(flags);
        data.writeString(callingPackage);
        data.writeInt(userId);
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        data.recycle();
        reply.recycle();
        return res;
    }

這個函數通過Binder驅動程序就進入到ActivityManagerService的bindService函數去了。我們緊接著看ActivityManagerService.bindService方法:

    public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
......
        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }

我們看到這個方法最后直接調用了mServices.bindServiceLocked()方法,這個mServices就是ActiveServices類:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
.......
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
......
        ActivityRecord activity = null;
        if (token != null) {
            activity = ActivityRecord.isInStackLocked(token);
.......
        }

        int clientLabel = 0;
        PendingIntent clientIntent = null;
        final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;
.....
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
 .....

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

            IBinder binder = connection.asBinder();
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }
            clist.add(c);
            b.connections.add(c);
            if (activity != null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                s.whitelistManager = true;
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
.........
        return 1;
    }

?首先傳進來的token就是Application在AcitivityManagerService中的令牌,通過token就可以將對應的ActivityRecord取回。
?接著通過retrieveServiceLocked函數,得到一個ServiceRecord,這個ServiceReocrd描述的是一個Service對象,這個service這里就是說的我們的RemoteRouterService對象。這是根據傳進來的參數service的內容獲得的。我們前面說的綁定服務那里可以看出:

        Intent bindRemoteRouterServiceIntent = new Intent(mLRouterAppcation,RemoteRouterService.class);
        bindRemoteRouterServiceIntent.putExtra(RemoteRouterService.PROCESS_NAME,processName);
        mLRouterAppcation.bindService(bindRemoteRouterServiceIntent,mServiceConnection, BIND_AUTO_CREATE);

?這里的參數service,就是上面的bindIntent了,它里面設置了RemoteRouterService類的信息(RemoteRouterService.class),因此,這里可以通過它來把RemoteRouterService的信息取出來,并且保存在ServiceRecord對象s中。
?接下來,就是把傳進來的參數connection封裝成一個ConnectionRecord對象。注意,這里的參數connection是一個Binder對象,它的類型是LoadedApk.ServiceDispatcher.InnerConnection,后續ActivityManagerService就是要通過它來告訴Application,RemoteRouterService已經啟動起來了,因此,這里要把這個ConnectionRecord變量c保存下來,它保在在好幾個地方,都是為了后面要用時方便地取回來的,這里就不仔細去研究了,只要知道ActivityManagerService要使用它時就可以方便地把它取出來就可以了,具體后面我們再分析。
?最后,傳進來的參數flags的位Context.BIND_AUTO_CREATE為1。最后程序會調用ActiveServices類的bringUpServiceLocked繼續處理:

  private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
.......
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        ProcessRecord app;

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        .....
           if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }
             }
        } else {
            app = r.isolatedProc;
        }
        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {
.......           
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }
.......
        return null;
    }

我們如果在AndroidManifest.xml中有設置process的話,那么這里procName就會是我們設置的字符串。如果沒有的話就會默認是包名。配合這uid會獲取到ProcessRecord對象。如果這個ProcessRecord為null的話就是說還沒有這個進程存在,所以后面會調用startProcessLocked()方法來創建一個新的進程然后在這個進程里面把這個服務啟動。不然就調用realStartServiceLocked()方法在應用程序進程中啟動應用Service,我們來看下這個方法:

  private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
......
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        .......

        boolean created = false;
        try {
......
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
.....
        } catch (DeadObjectException e) {
     .....
        } finally {
     .....
        }
.....
        requestServiceBindingsLocked(r, execInFg);
.....
    }

這個方法里面有兩個重要的方法scheduleCreateService和requestServiceBindingsLocked,這兩個方法分別是啟動服務和綁定服務(會調用Service的onBind方法)操作。

2.scheduleCreateService啟動服務

我們看到上面程序調用了 app.thread的scheduleCreateService方法,這里的app.thread是一個bind遠程對象,類型為ApplicationThreadProxy,每一個Android應用程序進程里面都有一個ActivtyThread對象和一個ApplicationThread對象,其中是ApplicationThread對象是ActivityThread對象的一個成員變量,是ActivityThreadActivityManagerService之間用來執行進程間通信的。所以我們看看這個ApplicationThreadProxy(這個類在ApplicationThreadNative里面)的scheduleCreateService干了什么:

 public final void scheduleCreateService(IBinder token, ServiceInfo info,
            CompatibilityInfo compatInfo, int processState) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeStrongBinder(token);
        info.writeToParcel(data, 0);
        compatInfo.writeToParcel(data, 0);
        data.writeInt(processState);
        try {
            mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
                    IBinder.FLAG_ONEWAY);
        } catch (TransactionTooLargeException e) {
            Log.e("CREATE_SERVICE", "Binder failure starting service; service=" + info);
            throw e;
        }
        data.recycle();
    }

這里通過了Bind機制就調用到了ActivityThread的scheduleCreateService函數中去了:

   public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }

這里可以看到主要是發送了一個消息,消息最終會調用到這個sendMessage()方法:

 private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

我們這個消息是發送到mH中了,這個mH又是什么呢?這里是H類,我們看他里面的handleMessage()方法:

 public void handleMessage(Message msg) {
     switch (msg.what) {
....
           case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
......
    }
}

我們看到這個主要就是調用handleCreateService()方法,這個方法就是創建的Service了:

 private void handleCreateService(CreateServiceData data) {
        unscheduleGcIdler();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
......
        try {
......
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
      .....
        }
    }

我們看到這個方法用類加載器把service加載進內存,然后調用了service的onCreate()方法,到這里我們的服務已經啟動起來了。我們接下來看看服務的綁定。

3.requestServiceBindingsLocked 服務的綁定

?前面我們的服務已經啟動且調用了Service的onCreate方法,那么接下來綁定的過程就會調用服務的onBind()方法,那么我們接下來來看綁定的方法即ActiveServices的requestServiceBindingsLocked:

  private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

 private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
........
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
.........
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
........
            } catch (TransactionTooLargeException e) {
.........
            } catch (RemoteException e) {
.........
            }
        }
        return true;
    }

?這里傳進來的ServiceRecord就是我們的RemoteRouterService服務,函數requestServiceBindingsLocked調用了requestServiceBindingLocked函數來處理綁定服務的操作,然后requestServiceBindingLocked方法會調用r.app.thread.scheduleBindService來綁定服務,跟上面的啟動過程類似。我們就直接跳到ActivityThread的handleBindService來講解:

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
.......   
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
.......
            }
        }
    }

?執行ActivityThread.handleCreateService函數中,已經將這個RemoteRouterService實例保存在mServices中,因此,這里首先通過data.token值將它取回來,保存在本地變量s中,接著執行了兩個操作,一個操作是調用s.onBind,即RemoteRouterService.onBind獲得一個Binder對象,另一個操作就是把這個Binder對象傳遞給ActivityManagerService。
?到這里我們Service的onCreate和onBind都已經調用完畢,onBind返回的是我們的IRemoteRouterAIDL#Stub(),得到這個對象之后程序就調用publishService()方法,同樣的,這里是調用ActivityManagerProxy的publishService通知mLRouterAppcation(Application對象),Service已經啟動完畢:

  public void publishService(IBinder token,
            Intent intent, IBinder service) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        intent.writeToParcel(data, 0);
        data.writeStrongBinder(service);
        mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }

這里通過Binder驅動程序就進入到ActivityManagerService的publishService函數中去了:

    public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

我們看到這個方法里面主要是調用了mServices即ActiveServices對象,所以我們跟進ActiveServices的publishServiceLocked()方法:

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
........    
            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;
                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
......
                                   continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            try {
                                c.conn.connected(r.name, service);
                            } catch (Exception e) {
.......
                            }
                        }
                    }
                }

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

在之前ActiveServices的bindServiceLocked()方法的時候,我們已經將一個ConnectionRecord對象放進ServiceRecord.connections列表中了:

          ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            IBinder binder = connection.asBinder();
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }
            clist.add(c);
            b.connections.add(c);

publishServiceLocked()里面就是將這個ConnectionRecord取出來,然后調用他的connected()方法。那么這里的ConnectionRecord的conn又是什么呢?這個是我們之前ServiceDispatcher的InnerConnection對象,因此,這里執行c.conn.connected函數后就會進入到ServiceDispatcher.InnerConnection#connected函數中去了:

  private static class InnerConnection extends IServiceConnection.Stub {  
            ......  
  
            public void connected(ComponentName name, IBinder service) throws RemoteException {  
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();  
                if (sd != null) {  
                    sd.connected(name, service);  
                }  
            }  
            ......  
        }  
}

這里轉發給了ServiceDispatcher的connected方法:

       public void connected(ComponentName name, IBinder service) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0));
            } else {
                doConnected(name, service);
            }
        }

這里的mActivityThread 是之前通過ActivityThread.getHandler函數得到的,因此,調用它的post函數后,就會把一個消息放到ActivityThread的消息隊列中去了。如果不明白消息機制的建議看下Handler,MessageQueue,與Looper三者關系分析,我們最終post的消息會調用到RunConnection中的run方法:

     public void run() {
                if (mCommand == 0) {
                    doConnected(mName, mService);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

這里的mCommand值為0,于是就執行ServiceDispatcher的doConnected方法來進一步操作了:

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

            synchronized (this) {
        .......

          // If there was an old service, it is now disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            // If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }
        }

到這里我們可以看到我們調用了mConnection的onServiceConnected()方法。這個mConnection就是我們bindService之前傳進來的ServiceConnection對象mServiceConnection:

  private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mRemoteRouterAIDL = IRemoteRouterAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mRemoteRouterAIDL = null;
        }
    };

所以我們這里就到了onServiceConnected方法里面,我們這里調用了IRemoteRouterAIDL.Stub.asInterface(service),終于我們要開始AIDL生成的源碼的分析了。

4.asInterface

我們看到綁定完成會回調ServiceConnection的onServiceConnected方法然后會調用這個方法,這個方法在AIDL文件生成的源碼中:

public static com.lenovohit.lrouter_api.IRemoteRouterAIDL asInterface(android.os.IBinder obj)
{
     if ((obj==null)) {
         return null;
     }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.lenovohit.lrouter_api.IRemoteRouterAIDL))) {
         return ((com.lenovohit.lrouter_api.IRemoteRouterAIDL)iin);
    }
     return new com.lenovohit.lrouter_api.IRemoteRouterAIDL.Stub.Proxy(obj);
}

這個方法主要用于將服務端的Binder對象轉換成客戶端所需的AIDL接口類型的對象,這種轉換過程是區分進程的 [如果客戶端和服務端位于同一進程,那么此方法返回的就是服務端的Stub對象本身,否則返回的是系統封裝后的Stub.proxy對象]。所以如果我們客戶端要跨進程調用遠程服務的時候,我們都是通過這個proxy代理來訪問,這里舉例我們要調用stopRouter方法,我們的代理是怎么訪問的呢?

@Override public boolean stopRouter(java.lang.String processName) throws android.os.RemoteException
{
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    boolean _result;
   try {
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeString(processName);
        mRemote.transact(Stub.TRANSACTION_stopRouter, _data, _reply, 0);
         _reply.readException();
        _result = (0!=_reply.readInt());
     }
      finally {
         _reply.recycle();
         _data.recycle();
         }
      return _result;
}

我們看到這里這個方法通過Binder機制調用遠程RemoteRouterService的stopRouter()方法,因為mRemote就是綁定服務時候傳回來的IRemoteRouterAIDL.Stub()的IBinder對象。然后服務端接受到消息的時候就會調用生成文件里面的onTransact方法里面對應的方法:

case TRANSACTION_stopRouter:
{
      data.enforceInterface(DESCRIPTOR);
       java.lang.String _arg0;
      _arg0 = data.readString();
      boolean _result = this.stopRouter(_arg0);
      reply.writeNoException();
      reply.writeInt(((_result)?(1):(0)));
       return true;
}

到這里就會調用到了RemoteRouterServiceIRemoteRouterAIDL.Stub的stopRouter()方法了。好了到這里我們整個流程也就講完了,其實AIDL文件生成的代碼并不難,難的是要明白整個調用過程。
總結:今天講的內容還是比較多的,結合了bindService的過程來把整個AIDL生成的源代碼的流程串了起來,如果感覺比較費勁的話就只要明白這里面的幾個角色就行了,不需要整個流程明白,希望我們后面的framework之旅愉快。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378

推薦閱讀更多精彩內容