有了前面一篇《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驅動程式碼。