源码分析 Service 的启动和绑定过程

前言

Service 分为两种工作状态,一种是启动状态,主要用于执行后台计算;一种是绑定状态,主要用于和其他组件进行交互。
Service的这两种状态是可以共存的,即 Service 即可以处于启动状态,也可以同时处于绑定状态。
通过Context的 startService 可以启动一个Service
启动Service:

Intent intent = new Intent(this,MyService.class);
startService(intent);

通过Context的 bindService 可以以绑定的方式启动一个Service
绑定Service:

Intent intent = new Intent(this,MyService.class);
bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
Service的启动过程
1、ContextWrapper 中的方法
@Override
public ComponentName startService(Intent service) {
    return mBase.startService(service);
}

mBase的类型是Context对应的真实对象实例是ContextImpl

2、ContextImpl 中的方法
@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess(this);
        ComponentName cn = ActivityManager.getService().startService(
            mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                        getContentResolver()), requireForeground,
                        getOpPackageName(), user.getIdentifier());
        ··· ···
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

在ContextImpl中,startService方法调用了startServiceCommon方法,然后在方法内部又调用了ActivityManager.getService().startService方法。

3、ActivityManager中的方法
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

这里其实涉及到了Android当中的 Binder 进程间通信了,这里我们暂时只需要知道这里ActivityManager.getService()返回来的其实是就是ActivityManagerService这里它继承了IActivityManager.Stub,它其实相当于是一个继承了android.os.Binder并且实现了IActivityManager接口的Binder类。(写过 AIDL 查看过系统帮我们生成的 Java 类的话可能就会明白一些,其中就有一个 Stub 类)

public class ActivityManagerService extends IActivityManager.Stub
4、ActivityManagerService中的方法
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage, int userId)
        throws TransactionTooLargeException {
    ··· ···
    synchronized(this) {
        ··· ···
        try {
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

这里会通过mServices.startServiceLocked方法来继续执行。这里的mServices是ActiveServices的实例对象。
ActiveServices是一个辅助 AMS(ActivityManagerService)对 Service 进行管理的类,包括Service的启动、绑定和停止等。

5、ActiveServices中的方法
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
    int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
    throws TransactionTooLargeException {
    ··· ···
    ServiceRecord r = res.record;	// 记录Service信息,贯穿后续的整个启动过程
    ··· ···
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

在ActiveServices中startServiceLocked方法的结尾处调用了startServiceInnerLocked 方法,并且在这个方法过程中,有一个ServiceRecord的类在该方法过程中记录了我们将要启动的这个Service的需要参数信息。

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ···· ····
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        ···· ····
    return r.name;
}
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
        ··· ···
        realStartServiceLocked(r, app, execInFg);	// 注意,这里的 r 还是前边的 ServiceRecord 
        ··· ···
}
private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
		··· ···
		app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
		··· ···
		
        sendServiceArgsLocked(r, execInFg, true);	// 通过这里调用了Service的其他方法,例如 onStartCommand

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
}

首先通过 app.thread的 scheduleCreateService 方法来创建 Service 对象并调用其 onCreate,接着再通过 sendServiceArgsLocked 方法来调用 Service 的其他方法,比如 onStartCommand,这两个过程同样还都是 进程间通信完成的。

这里的 app.thread 同样还是一个 Binder 对象,继承了 Binder 实现了 IApplicationThread 接口。它的具体实现就是 ApplicationThread,它是 ActivityThread 类中的一个内部类。

6、ApplicationThread中的方法
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);
}

这里通过发送消息给Handler H来完成的。 H接收到该消息,通过 ActivityThread 中的handleCreateService((CreateServiceData)msg.obj);方法来完成Service最终的启动。

7、ActivityThread中的方法
private void handleCreateService(CreateServiceData data) {
    ··· ···
    Service service = null;
    try {
    	// 这里来通过 ClassLoader 创建 Service 实例
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
    } 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);
        context.setOuterContext(service);
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        // attach 这里应该也比较关键,暂时还没太多关注
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        // 到这里 Service 的创建就完成了
        service.onCreate();
        mServices.put(data.token, service);
        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 这里主要完成了以下一些任务:

  • 通过类加载器创建出了 Service 的实例对象。
  • 创建 Application 对象并调用其 onCreate。(当然Application的创建过程只会有一次)
  • 创建了 ContextImpl 对象通过 Service 的 attach 方法建立二者之间的关系。(Activity也是类似)
    所以我们通常调用的 Context 的方法,其实都是 ContextImpl 来完成具体实现的啦!
  • 最后调用了 Service 的 onCreate 方法,并通过mServices.put(data.token, service);将 Service 对象存储到了 ActivityThread 的一个列表中了。
    final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();

ActivityThread 中还会通过 handleServiceArgs方法完成 Service 中 onStartCommand方法的调用。

到这里,Service 的整个启动过程就已经完成了。我们就在 onStartCommand 中收到了服务开启成功的回调了哦。

Service的绑定过程
1、ContextWrapper 中的方法
@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    return mBase.bindService(service, conn, flags);
}
2、ContextImpl 中的方法
@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
}
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) {
        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());
        if (res < 0) {
            throw new SecurityException(
                    "Not allowed to bind to service " + service);
        }
        return res != 0;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

大家都知道,我们在调用 bindService 的时候需要传递一个 ServiceConnection 实例对象的参数。

IServiceConnection sd;
if (conn == null) {
    throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
    sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
    throw new RuntimeException("Not supported in system context");
}

这里对 conn 参数进行了判空,并且通过mPackageInfo.getServiceDispatcher将我们传入的ServiceConnection转化为了ServiceDispatcher.InnerConnection的实例对象,而InnerConnection刚好是继承了 Binder 并实现了IServiceConnection接口的类,这里其实就变成了一个 Binder,之所以不能直接使用 ServiceConnection是因为服务的绑定可能是跨进程的,所以必须借助 Binder才能让远程服务端回调自己的方法。
这里 mPackageInfo.getServiceDispatcher具体的逻辑是在 LoadedApk中执行的。

3、LoadedApk 中的方法
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();
    }
}

mServices 是一个 ArrayMap,它存储了一个应用当前活动的 ServiceConnection 和 ServiceDispatcher 的映射关系。而ServiceDispatcher又起着连接 ServiceConnection 和 ServiceDispatcher.InnerConnection的作用(后面要返回的 Binder)。

系统会先查找是否存在相同的 ServiceConnection,不存在就重新创建一个 ServiceDispatcher 对象并将其存储在 mServices 中,key 是 ServiceConnection,value 是 ServiceDispatcher,在 ServiceDispatcher 的内部又保存了 ServiceConnection 和 InnerConnection对象。

当Services 和客户端建立连接后,系统通过 InnerConnection 来调用 ServiceConnection 中的 onServiceConnected 方法,这个过程有可能是跨进程的。

ServiceDispatcher创建好了之后,getServiceDispatcher方法就会返回其保存的 InnerConnection对象。

接着
ActivityManager.getService().bindService(...);
会同样通过 AMS(ActivityManagerService)来完成 Service 的绑定过程。

4、ActivityManagerService中的方法
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);
    }
}

mServices 是 ActiveServices 的实例

5、ActiveServices 中的方法
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String callingPackage, final int userId) throws TransactionTooLargeException {
		··· ···
		bringUpServiceLocked(serviceRecord,serviceIntent.getFlags(),callerFg, false, false);
		··· ···
}
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
		··· ···
		ProcessRecord app;
		if (!isolated) {
    		app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
					··· ···
            		app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
            		realStartServiceLocked(r, app, execInFg);
					··· ···
}
private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
		··· ···
		app.thread.scheduleCreateService(r, r.serviceInfo,
        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo)
        app.repProcState);
		··· ···
		requestServiceBindingsLocked(r, execInFg);
		updateServiceClientActivitiesLocked(app, null, true);
		// If the service is in the started state, and there are no
		// pending arguments, then fake up one so its onStartCommand() will
		// be called.
		if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
    		r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            null, null, 0));
		}
		sendServiceArgsLocked(r, execInFg, true);
		··· ···
}
  • app.thread.scheduleCreateService跟startService部分的逻辑一样,最终会通过 ActivityThread 来完成 Service 实例的创建并执行 onCreate 方法。
  • requestServiceBindingsLocked来负责完成 Service 的绑定部分。
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;
        }
    }
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
		··· ···
		r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,r.app.repProcState);
		··· ···
}

r.app.thread.scheduleBindService这里其实又回到了 ApplicationThread中逻辑。

6、ApplicationThread中的绑定逻辑
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);
}

通过 ActivityThread 中的 ActivityThread.H 的实例对象 mH 发送消息,把后边的逻辑交给了 ActivityThread 来处理了。

7、ActivityThread中的方法
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) {
                    IBinder binder = s.onBind(data.intent);
                    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);
            }
        }
    }
}

handleBindService 方法中,首先会根据 Service 的 token 取出 Service 对象,然后调用 onBind 方法,Service 的 onBind 方法会返回一个 Binder 对象给客户端使用。

到这里其实就已经完成了 Service 的绑定,不过虽然执行了 Service 的 onBind 方法,但是客户端其实还不知道已经成功的绑定上了 Service,这里接着通过 ActivityManager.getService().publishService(data.token, data.intent, binder);来把绑定成功的结果公布出去。

8、ActivityManagerService中的方法

这里其实又是回到了 ActivityManagerService 中完成的,具体如下:

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);
    }
}
9、ActiveServices 中的方法

这里接着又通过mServices.publishServiceLocked把逻辑给到了 ActiveServices中执行:

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
	··· ···
	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--) {
        	ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
        	for (int i=0; i<clist.size(); i++) {
            	ConnectionRecord c = clist.get(i);
            	··· ···
                c.conn.connected(r.name, service, false);
            	··· ···
            }
        }
    }
}

这里 c.conn.connected(r.name, service, false);中,c.conn 的类型其实就是 ServiceDispatcher.InnerConnection,service就是 Service的 onBind 方法返回的 Binder 对象。

10、LoadedApk.ServiceDispatcher.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);
        }
    }
}
11、LoadedApk.ServiceDispatcher
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.post 中 mActivityThread是一个Handler,其实就是ActivityThread中的H,从前面 ServiceDispatcher 的创建过程来说,mActivityThread 不会为 null,RunConnection就由 H 的 post 方法从而运行在主线程中。因此,客户端的 ServiceConnection 中的方法是在主线程中被回调的。
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;
}

RunConnection的 run 方法也是简单的调用了 ServiceDispatcher 的 doConnected 方法,由于ServiceDispatcher 内部保存了客户端的 ServiceConnection 对象,因此可以很方便的调用 ServiceConnection 对象的 onServiceConnected 方法,如下:

public void doConnected(ComponentName name, IBinder service, boolean dead) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;
	··· ···
    // If there is a new viable service, it is now connected.
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    } else {
        // The binding machinery worked, but the remote returned null from onBind().
        mConnection.onNullBinding(name);
    }
}

客户端的onServiceConnected方法执行后,客户端就可以收到服务绑定成功的回调了,并且service其实就是绑定服务成功后服务端返回给客户端的 Binder 对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值