Service啓動流程總結-bind和unbind

回顧

Service啓動系列總結:

《Service啓動流程總結-start和stop service》

概述

在開發中我們使用Context#bindService和Context#unbindService來綁定和解綁Service,通過綁定來啓動Service,可以方便的調用Service提供的API。Service的bind、unbind過程和start、stop過程類似,比較大的區別是多了Binder的傳遞過程。

基本使用

  1. 定義AIDL文件
// ISpeaker.aidl
package com.cdh.study;

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

interface ISpeaker {
    String sayHello();
}
  1. 定義Server端
public class SpeakerService extends Service {

    // 創建由aidl文件自動生成的Stub實例
    private final ISpeaker.Stub mSpeakerBinder = new ISpeaker.Stub() {
        @Override
        public String sayHello() throws RemoteException {
            return "hello!";
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // 返回Stub實例
        return mSpeakerBinder;
    }
}

在Service的onBind回調中返回創建的ISpeaker.Stub實例,Stub繼承Binder和ISpeaker。Client端在成功連接後便可通過其調用Server端的sayHello方法。

  1. 定義Client端
// Server端API接口,若Client和Server處於同一進程則返回的即是Server端binder實例,否則是Server端binder代理
private ISpeaker mISpeaker;

// 創建ServiceConnection實例,用作回調接口
private final ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // 連接回調,service即Server端onBind返回的IBinder
        mISpeaker = ISpeaker.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        // 斷連回調
        mISpeaker = null;
    }
};

public void bind() {
    // 綁定Server
    mContext.bindService(new Intent(mContext, SpeakerService.class), mConnection, Context.BIND_AUTO_CREATE);
}

public void unbind() {
    // 解綁Server,需要傳入綁定時的ServiceConnection接口(內部以ServiceConnection作爲key)
    mContext.unbindService(mConnection);
}
  1. 調用Server端提供的API
public void requestHello() {
    if (mISpeaker != null) {
        try {
            // 調用Service方法,會返回"hello!"
            mISpeaker.sayHello();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

Client端首先進行綁定Service,成功綁定後會回調ServiceConnection的onServiceConnected方法,在這裏獲取Server端binder實例或binder代理,之後便可通過binder來調用Server端API。

以上是一個bind service的簡單例子,接下來跟蹤源碼調用看看bind service的整體流程。

源碼探究

文中源碼基於 Android 10.0

bind過程

Caller發起bind

Caller指調用方,發起bind service,將會調用ContextImpl的bindService方法:

[ContextImpl#bindService]

public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    warnIfCallingFromSystemProcess();
    // 傳入意圖、ServiceConnection實例、BIND_AUTO_CREATE(表示目標Service未啓動時自動創建)和主線程Handler和當前用戶具柄
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
            getUser());
}

[ContextImpl#bindServiceCommon]

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        String instanceName, Handler handler, Executor executor, UserHandle user) {
    // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
    // binder通信接口,用於AMS向Caller進程通信
    IServiceConnection sd;
    // ···
    if (mPackageInfo != null) {
        if (executor != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
        } else {
            // 此時executor是null,執行這個case獲取IServiceConnection
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        }
    } else {
        throw new RuntimeException("Not supported in system context");
    }
    // 省略顯示意圖校驗 ···
    try {
        IBinder token = getActivityToken();
        // ···
        // 請求AMS進行bind流程
        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();
    }
}

該方法中先獲取IServiceConnection,然後調用AMS的bindIsolatedService方法。

IServiceConnection說明

在前面的基本使用例子中,Client端通過ServiceConnection接口回調獲取Server端binder。但ServiceConnection只是一個普通接口,不支持跨進程通信。因此這裏利用IServiceConnection進行AMS向Caller進程調用時的binder通信接口。

sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);

上文通過這個方法獲取IServiceConnection,mPackageInfo是LoadedApk,進入方法看看。

[LoadedApk#getServiceDispatcher]

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
        Context context, Handler handler, int flags) {
    return getServiceDispatcherCommon(c, context, handler, null, flags);
}

[LoadedApk#getServiceDispatcherCommon]

private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
        Context context, Handler handler, Executor executor, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        // ···
        if (sd == null) {
            if (executor != null) {
                sd = new ServiceDispatcher(c, context, executor, flags);
            } else {
                // 創建ServiceDispatcher
                sd = new ServiceDispatcher(c, context, handler, flags);
            }
            // ···
        } else {
            // ···
        }
        // 返回其中的mIServiceConnection成員
        return sd.getIServiceConnection();
    }
}

這裏省略了判斷緩存的部分,若沒有緩存,則新建ServiceDispatcher包裝傳入的參數。

接着看ServiceDispatcher構造方法:

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

ServiceDispatcher會持有InnerConnection和ServiceConnection。

InnerConnection繼承IServiceConnection.Stub,它實現了IServiceConnection的connected方法:

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

    InnerConnection(LoadedApk.ServiceDispatcher sd) {
        // 利用弱引用持有ServiceDispatcher
        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
            sd.connected(name, service, dead);
        }
    }
}

InnerConnection持有ServiceDispatcher,當綁定Server端成功時,AMS會調用其connected方法,在該方法中將參數轉發給ServiceDispatcher。

AMS處理bind請求

回到ContextImpl#bindServiceCommon方法中,再獲取到IServiceConnection後,便調用AMS#bindIsolatedService方法:

[ActivityManagerService#bindIsolatedService]

public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String instanceName,
        String callingPackage, int userId) throws TransactionTooLargeException {
    // ···

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

調用ActiveServices的bindServiceLocked方法:
[ActiveServices#bindServiceLocked]

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

    // 用於保存發起方Activity和Service的連接信息
    ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
    if (token != null) {
        // 將token強轉爲Token,然後獲取它內部通過弱引用持有的ActivityRecord,最後創建ActivityServiceConnectionsHolder保存ActivityRecord返回
        activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
        if (activity == null) {
            // 如果查找ActivityRecord失敗,則bind失敗
            Slog.w(TAG, "Binding with unknown activity: " + token);
            return 0;
        }
    }
    
    // ···
    
    final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
    final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
    final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;

    // 從查找或新建可用ServiceRecord
    ServiceLookupResult res =
        retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
                callerFg, isBindExternal, allowInstant);
    if (res == null) {
        return 0;
    }
    if (res.record == null) {
        return -1;
    }
    ServiceRecord s = res.record;
    
    // ···
    
    final long origId = Binder.clearCallingIdentity();

    try {
        // ···
        
        // AppBindRecord記錄一個綁定了Server的Caller信息
        // 保存ServiceRecord(在運行的Service信息)、IntentBindRecord(綁定意圖信息)、ProcessRecord(發起方進程信息)
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        // ConnectionRecord記錄一個Caller和Service綁定的連接信息,保存綁定相關參數
        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);
        c.startAssociationIfNeeded();
        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 ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
            s.setHasBindingWhitelistingBgActivityStarts(true);
        }
        if (s.app != null) {
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
        // mServiceConnections中存儲着所有ConnectionRecord
        ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
        if (clist == null) {
            clist = new ArrayList<>();
            mServiceConnections.put(binder, clist);
        }
        // 添加本次綁定連接信息
        clist.add(c);
        
        // 發起bind時通常會設置BIND_AUTO_CREATE
        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            // bringUpServiceLocked中會判斷是否已啓動Service,若未啓動會先啓動,遇到錯誤會返回描述原因字符串
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                    permissionsReviewRequired) != null) {
                return 0;
            }
        }
        
        // 省略更新Service所在進程優先級和oom_adj部分 ···
        
        if (s.app != null && b.intent.received) {
            // Service is already running, so we can immediately
            // publish the connection.
            try {
                // Service已經啓動,則回調Caller端connected
                c.conn.connected(s.name, b.intent.binder, false);
            } catch (Exception e) {
                Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                        + " to connection " + c.conn.asBinder()
                        + " (in " + c.binding.client.processName + ")", e);
            }

            // If this is the first app connected back to this binding,
            // and the service had previously asked to be told when
            // rebound, then do so.
            if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                // 若之前unbind過且返回true,則再次bind時會執行Service的onRebind回調
                requestServiceBindingLocked(s, b.intent, callerFg, true);
            }
        } else if (!b.intent.requested) {
            // 若前面bringUpServiceLocked方法中沒有執行bind,則這裏再次嘗試執行Service的onBind回調
            requestServiceBindingLocked(s, b.intent, callerFg, false);
        }
        
        // ···
    } finally {
        Binder.restoreCallingIdentity(origId);
    }

    return 1;
}

該方法中會檢查Caller是否是有效的Activity,然後從緩存查找或新建ServiceRecord,然後利用ActivityServiceConnectionsHolder、AppBindRecord、ConnectionRecord、mServiceConnections保存本次綁定連接Service的相關參數信息。接着調用bringUpServiceLocked方法(flags設置了BIND_AUTO_CREATE)進行啓動Service(若未啓動)和綁定流程。

bringUpServiceLocked方法的主要邏輯在《Service啓動流程總結-start和stop service》中簡單總結過,其中又會調用realStartServiceLocked方法,這裏看和bind相關的部分:

[ActiveServices#realStartServiceLocked]

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    // ···
    
    try {
        // ···
        // 啓動Service
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                app.getReportedProcState());
        // ···
    } catch (DeadObjectException e) {
        Slog.w(TAG, "Application dead when creating service " + r);
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        // ···
    }
    
    // ···
    
    // 進一步執行bind流程
    requestServiceBindingsLocked(r, execInFg);
    
    // ···
    
    // 內部會判斷pendingStarts集合中元素個數,通過start啓動Service時會觸發onStartCommand回調,bind流程可忽略。
    sendServiceArgsLocked(r, execInFg, true);
    
    // ···
}

進入requestServiceBindingsLocked方法:
[ActiveServices#requestServiceBindingsLocked]

private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
        throws TransactionTooLargeException {
    for (int i=r.bindings.size()-1; i>=0; i--) {
        // 依次取出ServiceRecord中保存的IntentBindRecord
        IntentBindRecord ibr = r.bindings.valueAt(i);
        // 進一步執行bind流程,若bind失敗會返回false
        if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
            break;
        }
    }
}

看requestServiceBindingLocked方法:
[ActiveServices#requestServiceBindingLocked]

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    // ···
    if ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
            bumpServiceExecutingLocked(r, execInFg, "bind");
            r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 調度Service執行bind回調
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.getReportedProcState());
            if (!rebind) {
                // 將requested成員置爲true,那麼在ActiveServices#bindServiceLocked方法結尾不會再執行requestServiceBindingLocked
                i.requested = true;
            }
            i.hasBound = true;
            i.doRebind = false;
        } catch (TransactionTooLargeException e) {
            // 省略異常處理部分 ···
        } catch (RemoteException e) {
            // 省略異常處理部分 ···
        }
    }
    return true;
}

該方法中通過IApplicationThread調度Service所在進程執行bind操作。

Service處理bind請求

接下來便來到Service所在進程,ActivityThread會發送BIND_SERVICE消息至主線程,執行handleBindService方法,直接看這個方法:

[ActivityThread#handleBindService]

private void handleBindService(BindServiceData data) {
    // 獲取緩存的Service實例(啓動時會將創建的Service保存在mServices中)
    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) {
                    // 觸發Service的onBind回調
                    IBinder binder = s.onBind(data.intent);
                    // 通知AMS發佈Service,並傳送IBinder
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
                } else {
                    // 觸發Service的onRebind回調
                    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);
            }
        }
    }
}

**這裏從mServices取出之前啓動創建時保存的Service實例,然後調用它的onBind生命週期回調方法。**在開頭例子中,返回了Server端binder實例ISpeaker.Stub。

接下來便請求ActivityManagerService,將binder傳送給Caller端。

AMS發佈Service

Server端在執行完Service的onBind後,需要將創建的binder傳給Caller,以便Caller通過binder調用Service提供的API,因此需要通過publishService方法通知AMS。

接下來看ActivityManagerService的publishService方法,在該方法中又調用了ActiveServices的publishServiceLocked方法:

[ActiveServices#publishServiceLocked]

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    final long origId = Binder.clearCallingIdentity();
    try {
        // 省略DEBUG信息 ···
        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++) {
                        // 依次取出bind目標Service的Caller連接信息
                        ConnectionRecord c = clist.get(i);
                        if (!filter.equals(c.binding.intent.intent)) {
                            // 省略DEBUG信息 ···
                            continue;
                        }
                        // 省略DEBUG信息 ···
                        try {
                            // conn是Caller發起bind時傳過來的IServiceConnection
                            c.conn.connected(r.name, service, false);
                        } catch (Exception e) {
                            // 省略DEBUG信息 ···
                        }
                    }
                }
            }

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

該方法中,會依次取出bind目標Service的等待中的Caller的ConnectionRecord,通過ConnectionRecord保存的IServiceConnection的connected方法調度到Caller進程。

Caller處理連接回調

AMS在處理publishService時,又會通過IServiceConnection調度Caller端,將會執行InnerConnection的connected方法,該方法中又會調用ServiceDispatcher的connected方法:

[ServiceDispatcher#connected]

public void connected(ComponentName name, IBinder service, boolean dead) {
    if (mActivityExecutor != null) {
        // mActivityExecutor默認爲null
        mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
    } else if (mActivityThread != null) {
        // mActivityThread是構造時傳入的主線程handler
        mActivityThread.post(new RunConnection(name, service, 0, dead));
    } else {
        doConnected(name, service, dead);
    }
}

該方法中通過主線程handler切換到主線程執行connect回調。

RunConnection#run中會執行doConnected方法:
[ServiceDispatcher#doConnected]

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.
            // 已經執行unbind
            return;
        }
        // mActiveConnections中緩存已經完成連接的ConnectionInfo
        old = mActiveConnections.get(name);
        if (old != null && old.binder == service) {
            // Huh, already have this one.  Oh well!
            // 已經連接過一樣的Service
            return;
        }

        if (service != null) {
            // A new service is being connected... set it all up.
            // ConnectionInfo保存連接信息
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
                // 設置Service死亡監聽
                service.linkToDeath(info.deathMonitor, 0);
                // 添加mActiveConnections集合保存
                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) {
        // 執行ServiceConnection接口的onServiceConnected回調
        mConnection.onServiceConnected(name, service);
    } else {
        // The binding machinery worked, but the remote returned null from onBind().
        mConnection.onNullBinding(name);
    }
}

在該方法中,會執行mConnection的onServiceConnected回調,mConnection即我們創建的ServiceConnection接口實例。在onServiceConnected回調中保存Service->AMS->Caller傳來的IBinder,若Caller與Service屬於同一進程則保存的是Server端binder實例,否則是binder代理。

至此便完成了Caller向Service的綁定過程,也拿到了Service提供的binder接口,後續就可以提供binder很方便地調用Service提供的API。

unbind過程

當Caller發起綁定時的Activtiy退出或者主動調用unbindService方法時,會開始解綁流程。

進入ContextImpl的unbindService方法:
[ContextImpl#unbindService]

public void unbindService(ServiceConnection conn) {
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    if (mPackageInfo != null) {
        // 獲取緩存的IServiceConnection
        IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                getOuterContext(), conn);
        try {
            // 請求AMS進行解綁
            ActivityManager.getService().unbindService(sd);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } else {
        throw new RuntimeException("Not supported in system context");
    }
}

該方法中首先從LoadedApk獲取緩存的IServiceConnection,然後請求AMS調度解綁。

forgetServiceDispatcher方法中從mServices集合中移除當前context和ServiceConnection對應的ServiceDispatcher,然後轉存到mUnboundServices集合中,最後返回ServiceDispatcher持有的InnerConnection實例。

接着來到AMS側,在ActivityManagerService#unbindService方法中又調用ActiveServices#unbindServiceLocked方法:
[ActiveServices#unbindServiceLocked]

boolean unbindServiceLocked(IServiceConnection connection) {
    IBinder binder = connection.asBinder();
    // ···

    final long origId = Binder.clearCallingIdentity();
    try {
        // clist中保存着IServiceConnection對應的所有連接信息
        while (clist.size() > 0) {
            // 依次取出ConnectionRecord
            ConnectionRecord r = clist.get(0);
            // 移除連接相關信息和解綁操作
            removeConnectionLocked(r, null, null);
            if (clist.size() > 0 && clist.get(0) == r) {
                // In case it didn't get removed above, do it now.
                Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
                // 未移除的話,這裏立即移除
                clist.remove(0);
            }

            // ···
        }

        mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);

    } finally {
        Binder.restoreCallingIdentity(origId);
    }

    return true;
}

該方法中取出緩存的ConnectionRecord,然後進一步執行解綁操作。

進入removeConnectionLocked方法:
[ActiveServices#removeConnectionLocked]

void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
        ActivityServiceConnectionsHolder skipAct) {
    IBinder binder = c.conn.asBinder();
    // 開始清理相關信息
    AppBindRecord b = c.binding;
    ServiceRecord s = b.service;
    ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            s.removeConnection(binder);
        }
    }
    b.connections.remove(c);
    c.stopAssociation();
    if (c.activity != null && c.activity != skipAct) {
        c.activity.removeConnection(c);
    }
    if (b.client != skipApp) {
        b.client.connections.remove(c);
        if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
            b.client.updateHasAboveClientLocked();
        }
        // If this connection requested whitelist management, see if we should
        // now clear that state.
        if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
            s.updateWhitelistManager();
            if (!s.whitelistManager && s.app != null) {
                updateWhitelistManagerLocked(s.app);
            }
        }
        // And do the same for bg activity starts whitelisting.
        if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
            s.updateHasBindingWhitelistingBgActivityStarts();
        }
        if (s.app != null) {
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
    }
    clist = mServiceConnections.get(binder);
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            mServiceConnections.remove(binder);
        }
    }

    mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid,
            s.appInfo.longVersionCode, s.instanceName, s.processName);

    if (b.connections.size() == 0) {
        b.intent.apps.remove(b.client);
    }

    if (!c.serviceDead) {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
                + ": shouldUnbind=" + b.intent.hasBound);
        if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                && b.intent.hasBound) {
            try {
                bumpServiceExecutingLocked(s, false, "unbind");
                if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
                        && s.app.setProcState <= ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
                    // If this service's process is not already in the cached list,
                    // then update it in the LRU list here because this may be causing
                    // it to go down there and we want it to start out near the top.
                    mAm.updateLruProcessLocked(s.app, false, null);
                }
                mAm.updateOomAdjLocked(s.app, true,
                        OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                b.intent.hasBound = false;
                // Assume the client doesn't want to know about a rebind;
                // we will deal with that later if it asks for one.
                b.intent.doRebind = false;
                // 調用Service端執行unbind
                s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
            } catch (Exception e) {
                Slog.w(TAG, "Exception when unbinding service " + s.shortInstanceName, e);
                serviceProcessGoneLocked(s);
            }
        }

        // If unbound while waiting to start, remove the pending service
        mPendingServices.remove(s);

        if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
            boolean hasAutoCreate = s.hasAutoCreateConnections();
            if (!hasAutoCreate) {
                if (s.tracker != null) {
                    s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
                            SystemClock.uptimeMillis());
                }
            }
            // 該方法中會判斷unbind後是否執行銷燬Service
            bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
        }
    }
}

該方法中會清理之前緩存的綁定相關的連接信息,然後調度Service端執行scheduleUnbindService觸發onUnbind回調。

在ActivityThread的scheduleUnbindService方法中通過發送UNBIND_SERVICE消息至主線程,執行handleUnbindService方法:
[ActivityThread#handleUnbindService]

private void handleUnbindService(BindServiceData data) {
    // 取出緩存的Service實例
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            // 執行Service的onUnbind回調方法
            boolean doRebind = s.onUnbind(data.intent);
            try {
                // 判斷onUnbind返回的結果,默認爲false
                if (doRebind) {
                    // 請求AMS支持reBind
                    ActivityManager.getService().unbindFinished(
                            data.token, data.intent, doRebind);
                } else {
                    // 通知unbind完成
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            // ···
        }
    }
}

該方法中取出緩存的Service實例,調用它的onUnbind生命週期回調方法,最後再通知AMS。

至此解綁流程便已完成。注意,可以看到解綁流程中沒有調用ServiceConnection的onServiceDisconnected回調,onServiceDisconnected的回調時機是在綁定時判斷舊連接時觸發和Caller通過binder死亡監聽監聽到Service端進程死亡時觸發。

總結

bind流程:
bind

unbind流程:
unbind

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