bindService流程源碼分析

bindService流程源碼分析

一、簡介

bindService是應用用來與service進行綁定的。該方式啓動的service系統認爲只有在調用者的context存在時service纔有必要運行,比如在activity中調用該方法且該activity處於stopped狀態,那麼其綁定的服務在activity返回前臺前不會運行。
還有就是不能在未註冊的BroadcastReceiver調用該方法(只能通過startService來啓動service),通過registerReceiver註冊的廣播可以調用因爲此時BroadcastReceiver的生命週期已經和註冊對象綁定了。

二、源碼分析

bindService是在Context類中定義的具體實現則是在ContextImpl類中。

public abstract boolean bindService(@RequiresPermission Intent service,
        @NonNull ServiceConnection conn, @BindServiceFlags int flags);

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

ContextImpl類中的bindService調用了bindServiceCommon做進一步處理。注意下傳入的mMainThread.getHandler()參數,mMainThread是一個ActivityThread實例,所以此處獲取的是ActivityThread所在線程的Handler,後面我們就可以通過這個handler把消息分發到ActivityThread線程的消息隊列中。

在bindServiceCommon中主要做了兩件事一是獲取一個IServiceConnection接口,二是調用AMS的遠程接口bindService

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
        handler, UserHandle user) {
    // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
    IServiceConnection sd;
    //1、調用getServiceDispatcher來獲取一個IServiceConnection接口
    if (mPackageInfo != null) {
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    } else {
        throw new RuntimeException("Not supported in system context");
    }
    try {
     //2、調用AMS的bindService
        service.prepareToLeaveProcess(this);
        int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
        return res != 0;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

我們來分析下getServiceDispatcher獲取IServiceConnection接口的過程。
getServiceDispatcher主要做了以下事情:
根據傳入的context在mServices中查找是否已經存在對應的ServiceDispatcher實例,如果沒有則創建並存入mServices,最後調用getIServiceConnection返回一個IServiceConnection,此處實際是一個InnerConnection實例,它是一個binder對象,後續AMS會用它和ServiceConnection通信

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
                                                     Context context, Handler handler, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        //1、根據傳入的context在mServices中查找是否已經存在對應的ServiceDispatcher實例
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
        if (map != null) {
            if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
            sd = map.get(c);
        }
        if (sd == null) {
            //2、mServices中沒有對應的ServiceDispatcher實例創建新實例
            sd = new ServiceDispatcher(c, context, handler, flags);
            if (DEBUG) Slog.d(TAG, “Creating new dispatcher “ + sd + “ for conn “ + c);
            if (map == null) {
                map = new ArrayMap<>();
                //3、存入mServices
                mServices.put(context, map);
            }
            map.put(c, sd);
        } else {
            sd.validate(context, handler);
        }
        //4、getIServiceConnection返回一個IServiceConnection,此處實際是一個InnerConnection實例,它是一個binder對象後續AMS會用它和ServiceConnection通信
        return sd.getIServiceConnection();
    }
}

我們繼續看下ServiceDispatcher的getIServiceConnection,他返回的是ServiceDispatcher.InnerConnection實例,這個是在ServiceDispatcher構造函數內創建的。

static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
//….
IServiceConnection getIServiceConnection() {
    return mIServiceConnection;
}

ServiceDispatcher(ServiceConnection conn,
        Context context, Handler activityThread, int flags) {
    mIServiceConnection = new InnerConnection(this);//創建InnerConnection實例
    mConnection = conn;
    mContext = context;
    mActivityThread = activityThread;
    mLocation = new ServiceConnectionLeaked(null);
    mLocation.fillInStackTrace();
    mFlags = flags;
}

}

最後貼下InnerConnection

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, boolean dead)
            throws RemoteException {
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            sd.connected(name, service, dead);
        }
    }
}

getServiceDispatcher之後就是調用AMS的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);
    }
}

bindService做了一些檢查後調用ActiveServices的bindServiceLocked。
bindServiceLocked比較長我們只看關鍵部分。它的主要操作可以分爲4步具體可以看下面的註釋。

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                      String resolvedType, final IServiceConnection connection, int flags,
                      String callingPackage, final int userId) throws TransactionTooLargeException {
    //…
    //1、首先會根據token找到其對應的ActivityRecord,我們之前說過ActivityRecord表示的是一個activity記錄,此處指的是調用bindService的activity
    ActivityRecord activity = null;
    if (token != null) {
        activity = ActivityRecord.isInStackLocked(token);
        if (activity == null) {
            Slog.w(TAG, “Binding with unknown activity: “ + token);
            return 0;
        }
    }
    //…
    //2、調用retrieveServiceLocked解析傳入的intent等參數獲得一個ServiceRecord對象
    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
    ServiceRecord s = res.record;

    //...
    //3、把傳入的connection封裝成一個ConnectionRecord對象,connection就是步驟3獲得的InnerConnection,
    // 因爲後續AMS需要使用它來告訴activity service已經啓動起來了,所以要把它保存起來,這裏保存在好幾個地方
    //AppBindRecord中存儲了當前ServiceRecord, intent以及發起方的進程信息。
    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是ServiceRecord.connections的成員變量
    clist.add(c);
     //b是指AppBindRecord
    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);

    //...
    //4、最初綁定service時傳入的flag是BIND_AUTO_CREATE,所以此處符合條件進而調用bringUpServiceLocked啓動要綁定的service
    if ((flags&Context.BIND_AUTO_CREATE) != 0) {
        s.lastActivity = SystemClock.uptimeMillis();
        if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                permissionsReviewRequired) != null) {
            return 0;
        }
    }
    //…
    if (s.app != null) {
            if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                s.app.treatLikeActivity = true;
            }
            //5、更新service所在進程的優先級
            mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                    || s.app.treatLikeActivity, b.client);
            mAm.updateOomAdjLocked(s.app);
        }

        if (s.app != null && b.intent.received) {
            try {
                //6、Service已經正在運行,則調用InnerConnection的代理對象
                c.conn.connected(s.name, b.intent.binder);
            } catch (Exception e) {
                ...
            }
            //7、當第一個app連接到該binding, 且之前已被bind過, 則回調onRebind()方法
            if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                requestServiceBindingLocked(s, b.intent, callerFg, true);
            }
        } else if (!b.intent.requested) {
            //8、最終回調onBind()方法
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }
    return 1;
}

bindServiceLocked做的事情比較多,我們再來梳理一下,首先在註釋1處查找請求綁定的Activity是否存在,之後在註釋2處通過retrieveServiceLocked查找對應的service。在註釋3處創建AppBindRecord和ConnectionRecord,AppBindRecord記錄着當前ServiceRecord, intent以及發起方的進程信息,ConnectionRecord則是對connection進行封裝。創建完成後會把ConnectionRecord存到ServiceRecord和AppBindRecord中。註釋4處通過bringUpServiceLocked來啓動service,之後在註釋5處更新service所在進程的優先級,在註釋6處Service已經正在運行,調用InnerConnection的代理對象。註釋7處判斷是否回調onRebind方法。註釋8處requestServiceBindingLocked最終回調onBind()方法。

我們先來看下retrieveServiceLocked查找對應的service的過程,然後再看service綁定過程,至於service啓動過程我們之前在startService的源碼分析中已經說到過,具體可以參考startService過程源碼分析.md

retrieveServiceLocked如下所示:

    private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
             ServiceRecord r = null;
                if (comp != null) {
            //根據service名稱查找ServiceRecord
            r = smap.mServicesByName.get(comp);
            if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
        }
        ...
         if (r == null && !isBindExternal) {
            Intent.FilterComparison filter = new Intent.FilterComparison(service);
            //根據Intent查找相應的ServiceRecord
            r = smap.mServicesByIntent.get(filter);
            if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
        }
        ...
         //通過PKMS來查詢相應的service
                ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId, callingUid);
                        
           ...
           //創建ServiceRecord對象
           r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
           res.setService(r);
           smap.mServicesByName.put(name, r);
           smap.mServicesByIntent.put(filter, r);
           
           ...
           
            //各種權限檢查,不滿足條件則返回爲null的service
            if (mAm.checkComponentPermission(r.permission,
                    callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
                //當exported=false則不允許啓動
                if (!r.exported) {
                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                            + " from pid=" + callingPid
                            + ", uid=" + callingUid
                            + " that is not exported from uid " + r.appInfo.uid);
                    return new ServiceLookupResult(null, "not exported from uid "
                            + r.appInfo.uid);
                }
                
  }

Service查找過程:

  1. 根據服務名從ServiceMap.mServicesByName中查找相應的ServiceRecord,如果沒有找到,則往下執行;
  2. 根據Intent從ServiceMap.mServicesByIntent中查找相應的ServiceRecord,如果還是沒有找到,則往下執行;
  3. 通過PKMS來查詢相應的ServiceInfo,如果仍然沒有找到,則不再往下執行。

接下來看下service的綁定:service的啓動最終是在realStartServiceLocked裏

private final void realStartServiceLocked(ServiceRecord r,
                                          ProcessRecord app, boolean execInFg) throws RemoteException {
    //…
    //1、創建service
    app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
            app.repProcState);
    //...
    //2、調用requestServiceBindingsLocked
    requestServiceBindingsLocked(r, execInFg);

    //...

}

requestServiceBindingsLocked調用requestServiceBindingLocked來進一步處理,通過bindService方式啓動的服務, 那麼該serviceRecord的bindings則一定不會空。requestServiceBindingLocked裏依次調用requestServiceBindingLocked。

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;
        }
    }
}

requestServiceBindingLocked函數如下所示:

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 ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
           //發送bind開始的消息
            bumpServiceExecutingLocked(r, execInFg, "bind");
            //調用ApplicationThread的scheduleBindService進入bind流程
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.repProcState);
        } catch (TransactionTooLargeException e) {
          //...               
        } catch (RemoteException e) {
            //… 
        }
    }
    return true;
}

我們看到它先發送了bind消息然後調用了ApplicationThread的scheduleBindService進入bind流程。

scheduleBindService如下所示:

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;
    //發送BIND_SERVICE message
    sendMessage(H.BIND_SERVICE, s);
}

public void handleMessage(Message msg) {
    case BIND_SERVICE:
    //BIND_SERVICE消息處理
    handleBindService((BindServiceData) msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}

在函數中發送了BIND_SERVICE消息,該消息的的處理是在handleBindService函數中,如下所示

private void handleBindService(BindServiceData data) {
    //1、根據token獲取要綁定的service
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    //2、回調service的onBind
                    IBinder binder = s.onBind(data.intent);
                    //3、把步驟2得到的binder(即onBind的返回值)傳遞給AMS
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
                } else {
                    s.onRebind(data.intent);
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
                ensureJitEnabled();
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } catch (Exception e) {
           //…
        }
    }
}

在該函數中首先根據token獲取要綁定的service,之後回調service的onBind拿到一個binder對象(這個binder就是onBind的返回值),最後傳遞給AMS。

AMS的publishService如下所示:

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

調用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—) {
                    //1、從ServiceRecord.connections中取出ConnectionRecord
                    ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                    for (int I=0; I<clist.size(); I++) {
                        ConnectionRecord c = clist.get(i);
                        try {
                            //2、調用ConnectionRecord.conn.connected,此處的ConnectionRecord.conn是之前創建的LoadedApk.ServiceDispatcher.InnerConnection對象
                            c.conn.connected(r.name, service, false);
                        } catch (Exception e) {
                            //...
                        }
                    }
                }
            }
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

InnerConnection的connected函數如下所示:

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, boolean dead)
            throws RemoteException {
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            //調用ServiceDispatcher的connected
            sd.connected(name, service, dead);
        }
    }
}

它調用了ServiceDispatcher的connected,connected如下所示

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

此處的mActivityThread就是主線程的Handler,通過該Handler post消息。

RunConnection的run如下

private final class RunConnection implements Runnable {
    RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
        mName = name;
        mService = service;
        mCommand = command;
        mDead = dead;
    }

    public void run() {
        if (mCommand == 0) {
            //調用doConnected進行綁定
            doConnected(mName, mService, mDead);
        } else if (mCommand == 1) {
            doDeath(mName, mService);
        }
    }

    final ComponentName mName;
    final IBinder mService;
    final int mCommand;
    final boolean mDead;
} 

doConnected函數如下:

public void doConnected(ComponentName name, IBinder service, boolean dead) {

 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 service, it is now connected.
            if (service != null) {
            //回調onServiceConnected,至此我們就在綁定端的onServiceConnected回調函數中拿到service返回的binder了
                mConnection.onServiceConnected(name, service);
            }
}

在doConnected函數中首先會創建死亡監聽對象並建立死亡通知,之後會回調onServiceConnected。

至此bindService的過程就結束了,總結來整個過程大概分爲以下幾步:
1、首先調用bindService通知AMS綁定service,AMS會先啓動service回調其onCreate函數。
2、AMS啓動service完成之後繼續調用service的onBind函數,獲取service返回的binder。
3、AMS把上一步獲得的Binder對象通過綁定時傳入的ServiceConnection的onServiceConnected函數傳給調用端,這樣調用端就可以通過binder來調用service提供的相關方法。

  1. Client進程: 通過getServiceDispatcher獲取Client進程的匿名Binder服務端,即LoadedApk.ServiceDispatcher.InnerConnection,該對象繼承於IServiceConnection.Stub; 再通過bindService調用到system_server進程;
  2. system_server進程: 依次通過scheduleCreateService和scheduleBindService方法, 遠程調用到target進程;
  3. target進程: 依次執行onCreate()和onBind()方法; 將onBind()方法的返回值IBinder(作爲target進程的binder服務端)通過publishService傳遞到system_server進程;
  4. system_server進程: 利用IServiceConnection代理對象向Client進程發起connected()調用, 並把target進程的onBind返回Binder對象的代理端傳遞到Client進程;
  5. Client進程: 回調到onServiceConnection()方法, 該方法的第二個參數便是target進程的binder代理端. 到此便成功地拿到了target進程的代理, 可以暢通無阻地進行交互.

參考:

bindService啓動過程分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章