bindService過程

afxstarx發表於2018-09-08
       有了前面一篇《Service啟動過程》,bindService應該很好分析了。但不用看程式碼也能估計出來,AMS需要快取BinderProxy並轉發給Client,跟Provider一樣。
       如果是程式內,ActivityThread中直接返回的是ContentProviderNative物件,即程式內直接呼叫ContentProvider函式而不是RPC。如果是程式外,那麼ActiviyThread會找AMS要ContentProviderHolder,最終得到的ContentProviderProxy。
       對於程式內和程式外,bindService的過程也會一樣嗎?我們估計,程式內得到的是一個Binder,而程式外得到的是一個BInderProxy。

1747    @Override
1748    public boolean bindService(Intent service, ServiceConnection conn,
1749            int flags) {
1751        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
1752    }複製程式碼

1761    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
1762            UserHandle user) {
1763        IServiceConnection sd;

1767        if (mPackageInfo != null) {
1768            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
1769                    mMainThread.getHandler(), flags);
1770        } else {
1772        }
1774        try {
1775            IBinder token = getActivityToken();
1782            int res = ActivityManagerNative.getDefault().bindService(
1783                mMainThread.getApplicationThread(), getActivityToken(),
1784                service, service.resolveTypeIfNeeded(getContentResolver()),
1785                sd, flags, user.getIdentifier());
1790            return res != 0;
1791        } catch (RemoteException e) {
1792            return false;
1793        }
1794    }複製程式碼
關注一下引數有三個:第一個是Intent,第二個是連線監聽,第三個是bindService的flags。
首先是構造了一個IServiceConnection,其次呼叫了AMS的startService。

957    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
958            Context context, Handler handler, int flags) {
959        synchronized (mServices) {
960            LoadedApk.ServiceDispatcher sd = null;
961  ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map=mServices.get(context)
965            if (sd == null) {
966                sd = new ServiceDispatcher(c, context, handler, flags);
967                if (map == null) {
968                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
969                    mServices.put(context, map);
970                }
971                map.put(c, sd);
972            } 
975            return sd.getIServiceConnection();
976        }
977    }複製程式碼
原來ServiceConnection就是一個純粹的介面,要為其加一層皮用於跨程式通訊,通訊用的倒不是ServiceDispatcher而是其中的通訊代表IServiceConnection.Stub。ServiceDispatcher畫個uml圖記憶一下,服務連線和斷開訊息的釋出者。
mServices的key是Context這說明一個Context只能bindService一次(同時)。返回值是ServiceDispatcher的內部類InnerConnection extends IServiceConnection.Stub。

還有個釋放ServiceConnection的函式也看看:

979    public final IServiceConnection forgetServiceDispatcher(Context context,
980            ServiceConnection c) {
981        synchronized (mServices) {
982            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
983                    = mServices.get(context);
984            LoadedApk.ServiceDispatcher sd = null;
985            if (map != null) {
986                sd = map.get(c);
987                if (sd != null) {
988                    map.remove(c);
989                    sd.doForget();
990                    if (map.size() == 0) {
991                        mServices.remove(context);
992                    }
993                    if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
994                        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
995                                = mUnboundServices.get(context);
996                        if (holder == null) {
997                            holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
998                            mUnboundServices.put(context, holder);
999                        }
1002                        ex.fillInStackTrace();
1003                        sd.setUnbindLocation(ex);
1004                        holder.put(c, sd);
1005                    }
1006                    return sd.getIServiceConnection();
1007                }
1008            }
1009            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
1010                    = mUnboundServices.get(context);
1011            if (holder != null) {
1012                sd = holder.get(c);
1013                if (sd != null) {
1014                    RuntimeException ex = sd.getUnbindLocation();
1018                }
1019            }
1026        }
1027    }複製程式碼
------------------------------------------------------------------------------------------------
開始要執行AMS.bindService了

14907    public int bindService(IApplicationThread caller, IBinder token,
14908            Intent service, String resolvedType,
14909            IServiceConnection connection, int flags, int userId) {
14916
14917        synchronized(this) {
14918            return mServices.bindServiceLocked(caller, token, service, resolvedType,
14919                    connection, flags, userId);
14920        }
14921    }複製程式碼

671    int bindServiceLocked(IApplicationThread caller, IBinder token,
672            Intent service, String resolvedType,
673            IServiceConnection connection, int flags, int userId) {
677        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
685        ActivityRecord activity = null;
686        if (token != null) {
687            activity = ActivityRecord.isInStackLocked(token);
688            if (activity == null) {
690                return 0;
691            }
692        }
720
721        final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
722
723        ServiceLookupResult res =
724            retrieveServiceLocked(service, resolvedType,
725                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
732        ServiceRecord s = res.record;
733
734        final long origId = Binder.clearCallingIdentity();
735
736        try {
754            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
755            ConnectionRecord c = new ConnectionRecord(b, activity,
756                    connection, flags, clientLabel, clientIntent);
757
758            IBinder binder = connection.asBinder();
759            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
760            if (clist == null) {
761                clist = new ArrayList<ConnectionRecord>();
762                s.connections.put(binder, clist);
763            }
779            clist = mServiceConnections.get(binder);
780            if (clist == null) {
781                clist = new ArrayList<ConnectionRecord>();
782                mServiceConnections.put(binder, clist);
783            }
784            clist.add(c);
785
786            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
787                s.lastActivity = SystemClock.uptimeMillis();
788                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
789                    return 0;
790                }
791            }
807            // 這裡開始不會走的,因為IBinder還沒有釋出,即沒有快取到AMS中
808            if (s.app != null && b.intent.received) {
811                try {
812                    c.conn.connected(s.name, b.intent.binder);
813                } catch (Exception e) {
817                }
818
822                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
823                    requestServiceBindingLocked(s, b.intent, callerFg, true);
824                }
825            } else if (!b.intent.requested) {
826                requestServiceBindingLocked(s, b.intent, callerFg, false);
827            }
828
829            getServiceMap(s.userId).ensureNotStartingBackground(s);
830
831        } finally {
833        }
834
835        return 1;
836    }複製程式碼
取得IBinder放到了b.intent.binder中,即放到了AppBindRecord中,而AppBinderRecord繫結了Intent資訊,且存放到了ServiceRecord.bindings中。從c.conn.connected來看最終呼叫了IServiceConnection.connected,這個是在Client應用層程式碼中的,所以基本可以斷定bringUpServiceLocked這一步坑定準備好了AppBindRecord.IntentBindRecord.binder
------------------------------------------------------------------------------------------------
看看如何取到IBinder的

1430    private final void realStartServiceLocked(ServiceRecord r,
1431            ProcessRecord app, boolean execInFg) throws RemoteException {
1440
1446        boolean created = false;
1447        try {
1448            String nameTerm;
1449            int lastPeriod = r.shortName.lastIndexOf('.');
1460            app.thread.scheduleCreateService(r, r.serviceInfo,
1461                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
1462                    app.repProcState);
1463            r.postNotification();
1464            created = true;
1465        } catch (DeadObjectException e) {
1467            mAm.appDiedLocked(app);
1468        } finally {
1469            if (!created) {
1470                app.services.remove(r);
1471                r.app = null;
1472                scheduleServiceRestartLocked(r, false);
1473                return;
1474            }
1475        }
1477        requestServiceBindingsLocked(r, execInFg);
1489        sendServiceArgsLocked(r, execInFg, true);
1505    }複製程式碼


1121    private final boolean requestServiceBindingLocked(ServiceRecord r,
1122            IntentBindRecord i, boolean execInFg, boolean rebind) {
1127        if ((!i.requested || rebind) && i.apps.size() > 0) {
1128            try {
1130                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
1131                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
1132                        r.app.repProcState);
1138            } catch (RemoteException e) {
1140                return false;
1141            }
1142        }
1143        return true;
1144    }複製程式碼


2748    private void handleBindService(BindServiceData data) {
2749        Service s = mServices.get(data.token);
2752        if (s != null) {
2753            try {
2756                try {
2757                    if (!data.rebind) {
2758                        IBinder binder = s.onBind(data.intent);
2759                        ActivityManagerNative.getDefault().publishService(
2760                                data.token, data.intent, binder);
2761                    } else {
2762                        s.onRebind(data.intent);
2765                    }
2767                } catch (RemoteException ex) {
2768                }
2769            } catch (Exception e) {
2775            }
2776        }
2777    }複製程式碼

14929    public void publishService(IBinder token, Intent intent, IBinder service) {
14934
14935        synchronized(this) {
14939            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
14940        }
14941    }複製程式碼

838    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
839        final long origId = Binder.clearCallingIdentity();
840        try {
843            if (r != null) {
844                Intent.FilterComparison filter
845                        = new Intent.FilterComparison(intent);
846                IntentBindRecord b = r.bindings.get(filter);
847                if (b != null && !b.received) {
848                    b.binder = service;
849                    b.requested = true;849                     // 這裡下次不需要再找Client要IBinder了
850                    b.received = true;
851                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
852                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
853                        for (int i=0; i<clist.size(); i++) {
854                            ConnectionRecord c = clist.get(i);
855                            if (!filter.equals(c.binding.intent.intent)) {
862                                continue;
863                            }
865                            try {
866                                c.conn.connected(r.name, service);
867                            } catch (Exception e) {
871                            }
872                        }
873                    }
874                }
877            }
878        } finally {
880        }
881    }複製程式碼
------------------------------------------------------------------------------------------------
從程式碼來看,不管怎樣bindService都會穿越到AMS中,AMS中記錄了BindProxy。當在程式內bindService時,AMS將BindProxy傳遞到程式內部,會轉化為Binder,最終就程式內直接呼叫了;如果是程式外bindService,那麼從AMS中拿到的還是BinderProxy,依然是RPC。IBinder在建立程式中變為Binder,在其他程式變為BinderProxy,這得去讀一下Binder機制原始碼,如果要徹底理解需要看看Binder驅動程式碼。

相關文章