第九章-四大組件的工作過程(Service的工作過程-基於Android8.1源碼)

我們將介紹Service的啓動過程和綁定過程,在分析Service的工作過程之前,我們先來了解一下如何使用Service。Service分爲兩種工作狀態,一種是啓動狀態,主要用於執行後臺計算;另一種是綁定狀態,主要用於其他組件和Service的交互。需要注意的是,這兩種狀態是可以共存的。

  • 啓動
Intent intent = new Intent(this, MyService.class);
startService(intent);
  • 綁定
Intent intent = new Intent(this, MyService.class);
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);

一、啓動服務示例
我們先寫個demo示例,再來源碼分析。

MyService.java

package com.example.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {
    private static final String TAG = "MyService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate || thread = " + Thread.currentThread().getName());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"onStartCommand || thread = " + Thread.currentThread().getName());
        return super.onStartCommand(intent, flags, startId);
    }


    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBind || thread = " + Thread.currentThread().getName());
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestroy || thread = " + Thread.currentThread().getName());
    }
}

在AndroidManifest.xml中註冊這個服務

<service android:name="com.example.service.MyService"/>

測試Activity

package com.example.service;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.example.test.R;

public class TestServiceActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_service);
    }

    //啓動服務
    Intent startIintent;
    public void startService(View view) {
        startIintent = new Intent(this,MyService.class);
        startService(startIintent);
    }

    public void stopService(View view) {
        if(startIintent != null){
            stopService(startIintent);
        }
    }

    public void bindService(View view) {
        if(startIintent != null){
            stopService(startIintent);
        }
    }

}

佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.service.TestServiceActivity"
    android:orientation="vertical"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="啓動Service"
        android:onClick="startService"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="停止Service"
        android:onClick="stopService"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="綁定Service"
        android:onClick="bindService"
        />

</LinearLayout>

點擊啓動和停止服務打印如下:

2020-04-09 16:28:19.286 6157-6157/com.example.test D/MyService: onCreate || thread = main
2020-04-09 16:28:19.287 6157-6157/com.example.test D/MyService: onStartCommand || thread = main
2020-04-09 16:28:21.670 6157-6157/com.example.test D/MyService: onStartCommand || thread = main  //第二次點擊啓動
2020-04-09 16:28:24.852 6157-6157/com.example.test D/MyService: onDestroy || thread = main

可以看到,onStartCommand會調用多次。回調都是運行在主線程

備註:下面都是基於Androidd8.1的源碼進行分析的。

二、Service的啓動過程

下面從代碼層面分析Service的啓動過程。(其實和Activity的啓動過程類似,也是IPC過程。調用到AMS中 >
ApplicationThread中 > 發消息 > 切換到ActivityThread中 > 調用service的生命週期方法)

Service的啓動過程從ContextWrapper的startService開始,如下所示

    @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

上面的代碼中,mBase是ContextImpl類型,Activity啓動分析知道,在Activity被創建的時候會通過attach方法將一個ContextImpl對象關聯起來,這個ContextImpl對象就是上述代碼的mBase
從ContextWrapper的實現可以看出,其大部分操作都在mBase裏實現,在設計模式中這是一種典型的橋接模式。

========疑問解答,mBase是怎麼賦值的?

//android.content.ContextWrapper
Context mBase;

//android.app.ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	...
	 ContextImpl appContext = createBaseContextForActivity(r);
	 ...
	activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
						
	...
}

//android.app.Activity
final void attach(Context context, ActivityThread aThread,
		Instrumentation instr, IBinder token, int ident,
		Application application, Intent intent, ActivityInfo info,
		CharSequence title, Activity parent, String id,
		NonConfigurationInstances lastNonConfigurationInstances,
		Configuration config, String referrer, IVoiceInteractor voiceInteractor,
		Window window, ActivityConfigCallback activityConfigCallback) {
	attachBaseContext(context);
	...
}


@Override
protected void attachBaseContext(Context newBase) {
	super.attachBaseContext(newBase);//調用父類的ContextThemeWrapper.attachBaseContext方法
	newBase.setAutofillClient(this);
}

//android.view.ContextThremeWrapper
public ContextThemeWrapper(Context base, Resources.Theme theme) {
	super(base);//調用父類ContextWrapper的構造
	mTheme = theme;
}

//android.content.ContextWrapper
public ContextWrapper(Context base) {
	mBase = base;//可以看到前面創建的ContextImpl實例就賦值給了這個mBase的全局變量了。
}

總結:Activity繼承ContextThremeWrapper,ContextThremeWrapper繼承ContextWrapper,所以在activity調用startService就直接調用到了ContextWrapper中的startService,又通過mBase.startService將代碼邏輯交給了ContextImpl處理了。
========疑問已解答

下面我們繼續來看ContextImpl的startService實現:

	@Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, mUser);
    }

    private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess();
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            return null;
        }
    }

在ContextImpl中,startService方法會調用startServiceCommon方法,而startServiceCommon方法又是通過ActivityManagerNative.getDefault().startService的對象來啓動一個服務的,對於ActivityManagerNative.getDefault()這個對象,實際就是個AMS(IPC通信前面介紹過了,這裏不重複)。AMS的startService方法實現如下:

    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        if (DEBUG_SERVICE)
            Slog.v(TAG, "startService: " + service + " type=" + resolvedType);
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
			//final ActiveServices mServices;
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, userId);//調用了這個方法
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

在這段代碼中,我們會調用mServices的startServiceLocked方法來啓動,mServices對象的類型是ActiveServices,ActiveServices是一個輔助AMS進行Service管理的類,包含Service的啓動,停止,綁定和停止等。在ActiveServices的startServiceLocked的尾部會調用startServiceInnerLocked,startServiceInnerLocked的實現如下:

	ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
            ServiceRecord r, boolean callerFg, boolean addToStarting) {
        ProcessStats.ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);//調用了這個方法
        if (error != null) {
            return new ComponentName("!!", error);
        }

        if (r.startRequested && addToStarting) {
            boolean first = smap.mStartingBackground.size() == 0;
            smap.mStartingBackground.add(r);
            r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
            if (DEBUG_DELAYED_SERVICE) {
                RuntimeException here = new RuntimeException("here");
                here.fillInStackTrace();
                Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
            } else if (DEBUG_DELAYED_STARTS) {
                Slog.v(TAG, "Starting background (first=" + first + "): " + r);
            }
            if (first) {
                smap.rescheduleDelayedStarts();
            }
        } else if (callerFg) {
            smap.ensureNotStartingBackground(r);
        }

        return r.name;
    }

在這裏插入圖片描述

	//ActiveServices#bringUpServiceLocked
	private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
        ...

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            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);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {
        ...

        return null;
    }
    
//ActiveServices#realStartServiceLocked
	private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (DEBUG_MU)
            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                    + ", ProcessRecord.uid = " + app.uid);
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            ...
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);//調用到這個方法,這裏就將邏輯通過IPC調用到了ApplicationThread#scheduleCreateService,追蹤最後會調用到我們Server的onCreate方法
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            ...
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        ...

        sendServiceArgsLocked(r, execInFg, true);//注意下這個方法,這個方法裏面也會通過IPC回調到ApplicationThread#scheduleServiceArgs,最終會調用到我們Server的onStartCommand方法

        ...
    }	

在這裏插入圖片描述

	//ApplicationThread#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);//和之前分析的一樣,發送一個消息。因爲ApplicationThread是一個Binder,這個方法是運行在Binder線程池中的。所以通過Handler將代碼邏輯切換到我們的主線程ActivityThread中。
	}
	
	//Handler片段
	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方法
	private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        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();//1、通過類加載器創建Service實例
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//2、創建Application
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());//3、將ContextImpl和Service建立關係
            service.onCreate();////4、onCreate方法在此調用
            mServices.put(data.token, service);//5、將服務存儲到ArrayMap列表中
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

handleCreateService主要完成了如下幾件事:
在這裏插入圖片描述
========疑問,如何調用handleServiceArgs這個方法的,其實在上面有提到過。
我們看AMS中的ActiveServices#realStartServiceLocked方法後面。會調用sendServiceArgsLocked

//ActiveServices#realStartServiceLocked
	private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        ...
        ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
        slice.setInlineCountLimit(4);
        Exception caughtException = null;
        try {
            r.app.thread.scheduleServiceArgs(r, slice);//會調用到這個方法
        }
		...
    }
	
	//通過IPC調用到了 ApplicationThread#scheduleServiceArgs方法
	sendMessage(H.SERVICE_ARGS, s);
	
	
	//Handler片段
	case SERVICE_ARGS:
		Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));
		handleServiceArgs((ServiceArgsData)msg.obj);
		Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
		break;
		
	可以看到最終調用到了ActivityThread#handleServiceArgs方法
	
	private void handleServiceArgs(ServiceArgsData data) {
		...
				if (!data.taskRemoved) {
					res = s.onStartCommand(data.args, data.flags, data.startId);//最終調用到了onStartCommand方法
				} else {
					s.onTaskRemoved(data.args);
					res = Service.START_TASK_REMOVED_COMPLETE;
				}
	
				QueuedWork.waitToFinish();
				...
		
	}

========疑問已解答

到這裏,Service的啓動過程就分析完成了。下面看Service的綁定過程。

三、Service的綁定過程
和Service的啓動過程一樣,Service的綁定過程也是從ContextWrapper開始的:

	//綁定一個服務的方式:
	Intent intent = new Intent(this, MyServiceService.class);
	bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
	
	private ServiceConnection mServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder binder) {
			
			//MyService.MyBinder這個可以在你的服務中定義,也可以定義具體的邏輯方法。
			MyService.MyBinder myBinder = (MyService.MyBinder)binder;
			
			//調用服務裏面的方法,calculate可以自己去實現,這裏只是個僞代碼
			myBinder.calculate();
		}
	
		@Override
		public void onServiceDisconnected(ComponentName name) {
			isBound = false;
		}
    };
	
	//ContextWrapper#bindService
	@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }

這個過程和Service的啓動過程是類似的,mBase同樣是ContextImpl類型的對象。ContextImpl的bindService方法最終會調用bindServiceCommon方法:

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
        	//特別關注下這個方法,使用到了我們設置的ServiceConnection
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess(this);
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());//這裏通過Binder調用到AMS中去了
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在這裏插入圖片描述

    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) {
                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                sd = map.get(c);
            }
            if (sd == null) {
                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<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

在這裏插入圖片描述
接着bindServiceCommon方法會通過AMS來完成Service的具體綁定過程,這裏對應AMS的bindService方法:

    public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
        enforceNotIsolatedCaller("bindService");

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

        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }

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

在這裏插入圖片描述

    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 (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
                + " rebind=" + rebind);
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            ...
        }
        return true;
    }
    

AMS通過Binder調用到了ApplicationThread#scheduleBindService了

	ApplicationThread#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;

		if (DEBUG_SERVICE)
			Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
					+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
		sendMessage(H.BIND_SERVICE, s);//發送一個消息
	}

在這裏插入圖片描述

    private void handleBindService(BindServiceData data) {
        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) {
                    	//回調到onBind的方法,這個時候客戶端並不知道已經綁定成功了。
                        IBinder binder = s.onBind(data.intent);
						//會調用到這個方法,又IPC調用到AMS中了。目的是回調ServiceConnection#onServiceConnected方法
                        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) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }
	

通過上面的分析,已經回調了onBind方法。但是我們客戶端不知道,還需要一次IPC來回調我們設置的ServiceConnection#onServiceConnected方法。
在這裏插入圖片描述

AMS中的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);
		}
    }

在這裏插入圖片描述

調用到InnerConnection#connected(可以看到又調回了我們客戶端的Binder線程池了

	//android.app.LoadedApk的內部類InnerConnection 看定義也是一個Binder類
	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);
			}
		}
	}
	
	//LoadedApk.ServiceDispatcher#connected方法
	public void connected(ComponentName name, IBinder service, boolean dead) {
		if (mActivityThread != null) {
			mActivityThread.post(new RunConnection(name, service, 0, dead));//mActivityThread不會爲null、走到這個分支
		} else {
			doConnected(name, service, dead);
		}
	}

在這裏插入圖片描述

	//LoadedApk內部類RunConnection
	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(mName, mService, mDead);
			} else if (mCommand == 1) {
				doDeath(mName, mService);
			}
		}

		final ComponentName mName;
		final IBinder mService;
		final int mCommand;
		final boolean mDead;
	}
	
	
	//LoadedApk.ServiceDispatch#doConnected
	public void doConnected(ComponentName name, IBinder service, boolean dead) {
		...

		// If there is a new service, it is now connected.
		if (service != null) {
			mConnection.onServiceConnected(name, service);//到這裏就調用到了onServiceConnected,我們就知道綁定成功了。
		}
	
	}

到這裏客戶端的onServiceConnected回調了,並且將service這個Binder服務對象返回給客戶端了。綁定過程就分析完成了。

總結下:第一次回調onBind的時候,客戶端並不知道綁定成功了。緊接着需要再次IPC,通過publishService這個方法,再次進入AMS,最終回調了onServiceConnected。所以瞭解Binder的IPC通信很重要。將IPC放在前面介紹是很正確的。只有掌握前面的知識,這裏才能完成分析。

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