Android系统源码分析--Service启动流程

在前面文章我们分析了四大组件中的两个:Broadcast和Activity,这章我们分析四大组件中的服务(Service)的启动过程。Service的启动方式有两种:一种是startService,一种是bindService;第一种通常是开启一个服务执行后台任务,不进行通信,第二章通过是启动服务进行通信。下面我们就根据这两种启动方式来讲Service的启动流程以及unbindService和stopService流程。

Service启动流程-startService

首先来看启动流程时序图:

Service1.jpg

Step0.ContextImpl.startService

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

调用当前类中的startServiceCommon方法。

Step1.ContextImpl.startServiceCommon

    private ComponentName startServiceCommon(Intent service, UserHandle user) {
        try {
            // 检验Intent,组件和包名不能为空
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // 通过getDefault方法获取AMS的一个代理对象(ActivityManagerProxy),然后调用这个代理对象
            // 的startService方法来请求AMS启动Service
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                    mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), getOpPackageName(), user.getIdentifier());
            ...
            return cn;
        } catch (RemoteException e) {
            ...
        }
    }

首先验证Intent中传递的组件名是否为空,为什么判断下面我们介绍,接着通过代理对象ActivityManagerProxy,通过Binder调用AMS(ActivityManagerService)中的对应方法startService。我们先看包名验证。

Step2.ContextImpl.validateServiceIntent

    private void validateServiceIntent(Intent service) {
        if (service.getComponent() == null && service.getPackage() == null) {
            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                IllegalArgumentException ex = new IllegalArgumentException(
                        "Service Intent must be explicit: " + service);
                throw ex;
            } else {
                Log.w(TAG, "Implicit intents with startService are not safe: " + service
                        + " " + Debug.getCallers(2, 3));
            }
        }
    }

这里给出了如果系统在Android5.0及以上版本,启动服务必须为显式启动,否则抛出异常,这个情况我们在刚开始在高于5.0系统都会遇到过,限制就在这里,所以,5.0及以上系统必须用显式的方式启动服务。

3.AMP.startService

    public ComponentName startService(IApplicationThread caller, Intent service,
                                      String resolvedType, String callingPackage, int userId) throws RemoteException {
        ...
        // 通过Binder对象mRemote向AMS发送一个类型为START_SERVICE_TRANSACTION的进程间通信请求,
        // 然后会调用AMS中的对应的startService方法
        mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
        ...
        return res;
    }

看过前面文章的对这一段代码应该很熟悉了,这个就是通过Binder调用AMS中对应方法的。所以我们直接看AMS。

4.AMS.startService

    public ComponentName startService(IApplicationThread caller, Intent service,
                                      String resolvedType, String callingPackage, int userId)
            throws TransactionTooLargeException {

        ...
        synchronized (this) {
            ...
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, callingPackage, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }

这里的mServices是ActiveServices,因此调用的是ActiveServices中的startServiceLocked方法。

5.ActiveServices.startServiceLocked

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
                                     int callingPid, int callingUid, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        ...
        
        // 解析service这个Intent,就是解析在AndroidManifest.xml定义的Service标签的intent-filter相关内容
        // 并将其内容保存在Service的record(ServiceRecord)中
        ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType, callingPackage,
                        callingPid, callingUid, userId, true, callerFg, false);
        ...

        // 每一个Service组件都使用一个ServiceRecord对象来描述,就像每一个Activity都是用一个ActivityRecord
        // 对象来描述一样
        ServiceRecord r = res.record;
        ...
        // 加入启动服务列表
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants));

        final ServiceMap smap = getServiceMap(r.userId);
        boolean addToStarting = false;
        // 如果是非前台(后台)进程调用
        if (!callerFg && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
            // 获取启动服务所在进程
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            ...
        } else if (DEBUG_DELAYED_STARTS) {
            ...
        }

        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }

这里做的主要是启动服务前的准备工作,首先是解析Intent携带的参数,并将这些内容保存在用来描述Service的ServiceRecord对象中保存起来,并将该对象放到等待启动服务的列表中。然后调用startServiceInnerLocked启动服务。在上面调用retrieveServiceLocked函数解析的过程中先去判断AMS中是否存在参数为service对应的ServiceRecord对象,如果存在说明已经启动过该服务,如果不存在,说明是第一次启动该服务。

8.ActiveServices.startServiceInnerLocked

   ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
                                          boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ServiceState stracker = r.getTracker();// 获取服务状态
        ...
        r.callStart = false;// 是否调用onStart方法
        ...

        // 启动ServiceRecord对象r所描述的一个Service组件,即Server组件
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        ...

        return r.name;
    }

这里比较简单主要是调用bringUpServiceLocked唤起服务。

Step9.ActiveServices.bringUpServiceLocked

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
                                        boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
            
        // 这里的r.app.thread是一个ApplicationThread对象,ApplicationThread是用来AMS和应用进程通信的工具,
        // 如果服务中的这个thread不为空说明已经和该Service存在通信了,也就是说已经启动了该服务了。
        // 如果服务已经存在,调用startService的时候会执行Service.onStartCommand,
        // 只有首次启动服务才会调用onCreate方法
        if (r.app != null && r.app.thread != null) {
            // 执行Service.onStartCommand方法过程
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

        ...

        // Make sure that the user who owns this service is started.  If not,
        // we don't want to allow it to run.
        // 确保正在启动服务的用户已经启动,否则不允许执行
        if (!mAm.mUserController.hasStartedUserState(r.userId)) {
            ...
            bringDownServiceLocked(r);
            return msg;
        }

        ...

        // 是不是独立进程
        final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        // 首先获取ServiceRecord对象r所描述的Service组件的android:process属性,并保存在procName中
        final String procName = r.processName;
        ProcessRecord app;

        if (!isolated) {// 要启动的服务不是独立进程
            // 如果不是独立进程,通过进程名称和uid查找是否已经存在一个对应的ProcessRecord对象app,如果存在,
            // 说明用来运行这个Service组件的应用进程已经存在了,因此下面的realStartServiceLocked函数在
            // ProcessRecord对象app所描述的应用程序进程中启动这个Service组件。
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {// 进程存在,并且该进程已经与AMS通信过,那么直接启动服务
                try {
                    ...
                    // 启动服务
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    ...
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {// 如果要启动的进程是独立进程
            ...
        }

        // 如果要启动的Service所在进程没有启动
        if (app == null && !permissionsReviewRequired) {
            // 启动Service所需要的进程
            if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {
                ...
                // 启动失败
                bringDownServiceLocked(r);
                return msg;
            }
            ...
        }

        ...

        if (r.delayedStop) {// 如果是延迟停止的服务
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                // 停止服务
                stopServiceLocked(r);
            }
        }

        return null;
    }

这里是启动服务最重要的部分,根据不同的情况进行不同的处理。首先是判断服务所在进程是否存在,如果存在调用sendServiceArgsLocked方法,最终根据条件,如果服务存在调用服务的onStartCommand方法;然后判断被启动服务的用户是否已经被启动,如果没有则停止服务,也就是调用bringDownServiceLocked方法,最终调用服务的onDestroy方法;然后判断非独立进程的服务,如果进程存在并且服务未启动的开始正式启动服务,调用realStartServiceLocked方法,最终调用onCreate方法;然后判断如果进程不存在,要启动进程,并且在app启动后启动服务,这里会调用启动失败,停止启动,因为进程启动后会启动该服务,这个过程在前面我们讲过,这里不再分析这种情况。最后是如果是延迟停止的服务这里直接停止该服务。下面我们按顺序分析这几种情况。

Step10.ActiveServices.sendServiceArgsLocked

    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
                                             boolean oomAdjusted) throws TransactionTooLargeException {
        // 等待启动服务个数
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }

        while (r.pendingStarts.size() > 0) {
            ...
            try {
                ..
                // 标记启动服务开始
                bumpServiceExecutingLocked(r, execInFg, "start");
                ...
                // 发送消息,传动到ApplicationThread中的scheduleServiceArgs方法,最终会调用onStartCommand
                r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
            } catch (TransactionTooLargeException e) {
                ...
            } 
        }
    }

上面Step5提到启动的服务都要先放到等待启动服务列表中,因此这里先判断服务列表是否存在要启动的服务,如果不存在则不再继续执行,如果存在,循环启动服务,这里调用scheduleServiceArgs方法,其实在前面分析了很多遍,最终会发送消息ActivityThread中的Handler中的handleMessage中进行处理,然后调用ActivityThread中的handleServiceArgs方法。

Step13.ActivityThread.handleServiceArgs

    private void handleServiceArgs(ServiceArgsData data) {
        // 获取Service对象
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                ...
                if (!data.taskRemoved) {// 任务没有被移除的话,调用Service.onStartCommand方法
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {// 否则调用被移除方法
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }

                ...
            } catch (Exception e) {
                ...
            }
        }
    }

根据Service对应的token去缓存中获取服务,如果有该服务那么调用服务的onStartCommand方法,如果不存在那么就要继续往下走创建服务。

Step15.ActiveServices.bringDownServiceLocked

这个方法主要是处理停止服务的方法,里面主要是断开连接,解除绑定,然后销毁服务,因为这个过程是在服务停止时会调用,所以在后面介绍,这里先不介绍了。

Step16.ActiveServices.realStartServiceLocked

    private final void realStartServiceLocked(ServiceRecord r,
                                              ProcessRecord app, boolean execInFg) throws RemoteException {
        ...

        boolean created = false;
        ...
            // 发送信息到主线程,准备调用Service.onCreate方法
            // 请求ProcessRecord对象app描述的应用程序进程将ServiceRecord独享r所描述的Service组件启动起来。
            // ServiceRecord对象r所描述的Service组件启动完成之后,AMS就需要将它连接到一个请求绑定它的一个
            // Activity组件中,这是通过调用AMS类的另一个成员函数requestServiceBindingLocked来实现的
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
        ...

        // 准备调用Service.onBind方法
        requestServiceBindingsLocked(r, execInFg);

        ...

        // 准备调用Service.onStartCommand方法
        sendServiceArgsLocked(r, execInFg, true);

        ...
    }

启动服务调用三个方法,首先是通过app.thread.scheduleCreateService方法调用onCreate方法,然后通过requestServiceBindingsLocked方法调用Service.onBind方法,然后通过sendServiceArgsLocked方法调用Service.onStartCommand方法,其中最后一个方法我们分析过了,所以我们只分析前两个。第一很简单了,最终调用ActivityThread中的handleCreateService方法。

Step18.ActivityThread.handleCreateService

    private void handleCreateService(CreateServiceData data) {
        ...

        // 获取一个用来描述即将要启动的Service组件所在的应用程序的LoadedApk对象,并将它保存在packageInfo
        // 变量中(每一个应用程序都使用一个LoadedApk对象来描述,通过它就能方位到它所描述的应用程序的资源)
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        ...
            // 获取类加载器
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            // 通过类加载器将CreateServiceData对象data描述的一个Service组件加载的内存中,并且创建它的一个
            // 实例,保存在Service对象service中。因为CreateServiceData对象data描述的Service组件即为应用
            // 程序的Ashmem中的Server组件,因此,Service对象service指向的Service组件实际上是一个Server组件
            service = (Service) cl.loadClass(data.info.name).newInstance();
        ...
            // 初始化一个ContextImpl对象context,用来为前面所创建的Service对象service的运行上下文环境,
            // 通过它可以访问特定的应用程序资源,以及启动其他应用程序组件
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            // 创建一个Application对象app,用来描述Service对象service所属的应用程序。
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 使用Application对象app,ContextImpl对象context和CreateServiceData对象data来初始化
            // Service对象service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            // 调用Service的onCreate方法
            service.onCreate();
            // 以token为关键字保存Service对象service到mServices中,服务启动完成
            mServices.put(data.token, service);
            ...
        } catch (Exception e) {
            ...
        }
    }

首先获取LoadedApk对象,然后通过类加载器加载Service类,初始化Context,获取对应的Application,如果存在直接返回,如果该应用还没启动则直接创建该Application,然后通过Service的attach方法将对应的信息放置到Service中,这里面就包含ActivityThread,因此我们在Step9中可以通过这个来判断Service是不是被启动了,然后调用onCreate方法,创建完成后,将该服务以token为键,Service为值放入到缓存中,这样我们前面获取的时候就只从这里获取的,因此如果服务启动了换粗就会存在,否则不存在。下面我们分析onBind方法。

Step20.ActiveServices.requestServiceBindingsLocked

    // 参数r指向一个ServiceRecord,表示一个已经启动的Service组件
    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i = r.bindings.size() - 1; i >= 0; i--) {
            // 每一个IntentBindRecord对象都用来描述若干个需要将ServiceRecord对象r所描述的Service组件
            // 绑定到它们里面的应用程序进程
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

for循环调用onBind。

Step21.ActiveServices.requestServiceBindingLocked

    // 参数rebind表示是否需要将ServiceRecord对象r所描述的Service组件重新绑定到IntentBindRecord对象i
    // 所描述的应用程序进程中如果为false,则说明为第一绑定
    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
                                                      boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        ...
        // 检查AMS是否已经为IntentBindRecord对象i所描述的应用程序进程请求过ServiceRecord对象r所描述的
        // Service组件返回其内部的一个Binder本地对象。如果还没有请求requested为false并且apps的数量大于0
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                ...
                //会执行到Service的onBind方法
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    // 设置为true,防止重复请求
                    i.requested = true;
                }
            ...
            }
        }
        return true;
    }

这里通过调用r.app.thread.scheduleBindService方法,最终调用到ActivityThread中的handleBindService方法。

Step23.ActivityThread.handleBindService

    private void handleBindService(BindServiceData data) {
        // 通过token来获得一个描述Service组件的Service对象
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
               ...
                    if (!data.rebind) {// 首次绑定
                        // 获取一个实现了IBinder接口的Binder对象
                        IBinder binder = s.onBind(data.intent);
                        ...
                    } else {
                        s.onRebind(data.intent);
                        ...
                    }
                ...
            } catch (Exception e) {
                ...
            }
        }
    }

现获取服务,然后判断是再次绑定还是首次绑定,如果是首次绑定调用Service.onBind方法,如果是再次绑定调用Service.onRebind方法。到这里服务的启动就完成了,其他一些操作就不分析了。下面我们先分析另外一个启动流程bindService,最后分析停止服务流程。

Service启动流程-bindService

首先来看绑定流程时序图:

Service3.jpg

Step1.ContextImpl.bindService

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

这里是绑定服务的入口位置,调用bindServiceCommon方法。

Step2.ContextImpl.bindServiceCommon

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        IServiceConnection sd;
        ...
        // mPackageInfo类型是LoadedApk
        if (mPackageInfo != null) {
            // 将ServiceConnection对象conn封装成一个实现了IServiceConnection接口的Binder本地对象sd
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            ...
        }
        ...
        try {
            IBinder token = getActivityToken();
            ...
            // 通过调用代理对象ActivityManagerProxy的bindService方法将前面获得的sd对象,以及Intent对象
            // service等信息发送给AMS,以便AMS可以将ServiceConnection组件启动起来
            int res = ActivityManagerNative.getDefault().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
            ...
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

首先调用LoadedApk中的getServiceDispatcher方法获取实现IServiceConnection接口的Binder对象ServiceDispatcher.InnerConnection。然后调用AMP中的bindService方法,然后通过Binder通信调用AMS中的bindService方法。

Step3.LoadedApk.getServiceDispatcher

    // 每一个绑定过Service组件的Activity组件在LoadedApk类中都有一个对应的ServiceDispatcher对象,它负责将
    // 这个被绑定的Service组件与绑定它的Activity组件关联起来,这些ServiceDispatcher保存在map中
    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);
            // 检查成员变量mServices中是否存在一个以ServiceConnection对象c为关键字的ServiceDispatcher
            // 对象sd,如果不存在,则创建一个并且以context为关键字保存到mServices中
            if (map != null) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (map == null) {
                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            // 调用前面获取到的ServiceDispatcher对象sd的成员函数getIServiceConnection来获取一个实现了
            // IServiceConnection接口的本地Binder对象
            return sd.getIServiceConnection();
        }
    }

首先根据ServiceConnection取缓存中获取,如果没有要初始化一个ServiceDispatcher对象,然后获取ServiceDispatcher.InnerConnection对象并且返回。

Step6.AMP.bindService

    public int bindService(IApplicationThread caller, IBinder token,
                           Intent service, String resolvedType, IServiceConnection connection,
                           int flags, String callingPackage, int userId) throws RemoteException {
        ...
        // 通过Binder对象mRemote向AMS发送一个类型为BIND_SERVICE_TRANSACTION的进程间通信请求
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
        ...
        return res;
    }

这里通过Binder调用AMS中对应的方法。

Step7.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);
        }
    }

这里调用ActiveServices.bindServiceLocked方法。

Step8.ActiveServices.bindServiceLocked

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                          String resolvedType, final IServiceConnection connection, int flags,
                          String callingPackage, final int userId) throws TransactionTooLargeException {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
                + " type=" + resolvedType + " conn=" + connection.asBinder()
                + " flags=0x" + Integer.toHexString(flags));
        // 根据caller来获取一个ProcessRecord对象callerApp用来描述AMS执行绑定Service组件操作的一个Activity
        // 组件所运行在的应用程序进程
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        ...

        ActivityRecord activity = null;
        if (token != null) {
            // 通过token来获得一个ActivityRecord对象activity,用来描述正在请求AMS执行绑定Service组件
            // 操作的一个Activity组件
            activity = ActivityRecord.isInStackLocked(token);
            if (activity == null) {
                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;

        // 根据参数service来得到一个ServiceRecord对象s,用来描述即将被绑定的Service组件
        ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                        Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
        ...
            // 调用ServiceRecord对象s的成员函数retrieveAppBindingLocked来得到一个AppBindRecord对象b,
            // 表示ServiceRecord对象s所描述的Service组件是绑定在ProcessRecord对象callerApp所描述的一个
            // 应用程序进程中的
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            // 将前面获得的APPBindRecord对象、ActivityRecord对象Activity以及参数connection封装成一个
            // ConnectionRecord对象s所描述的一个Service组件,并且这个Activity组件是运行在
            // ProcessRecord对象callerApp所描述的一个应用进程中的
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            // 由于一个Service组件可能会被同一个应用程序进程中的多个Activity组件使用同一个InnerConnection
            // 对象来绑定,因此,在AMS中,用来描述该Service组件的ServiceRecord对象就有可能会对应有多个
            // ConnectionRecord对象。在这种情况下,这些ConnectionRecord对象就会被保存在一个列表中。
            // 这个列表最终会保存在对应的ServiceRecord对象的成员变量Connection所描述的HashMap中,并且以
            // 它里面的ConnectionRecord对象共同使用的一个InnerConnection代理对象的IBinder接口为关键字

            // 参数connection是一个InnerConnection代理对象,因此可以获取它的一个IBinder接口binder
            IBinder binder = connection.asBinder();
            // 检测在ServiceRecord对象s中是否存在一个以IBinder接口binder为关键字的列表clist,如果不存在
            // 创建一个,并且将clist以binder为关键字放到ServiceRecord对象成员变量connections中
            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
            if (clist == null) {// 没有绑定过
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }
            clist.add(c);// 添加绑定列表
            b.connections.add(c);// 添加到关联应用和服务的对象AppBindRecord中记录绑定列表中
            if (activity != null) {
                if (activity.connections == null) {// 这里判断Activity里面是否绑定过服务
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                // 添加到描述Activity的ActivityRecord对象中记录绑定服务的列表中
                activity.connections.add(c);
            }
            ...
            // 从记录该服务所有绑定列表中获取是否存在绑定列表
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);// 添加都所有列表中

            // 从前面可知flags的Context.BIND_AUTO_CREATE位等于1,因此会调用bringUpServiceLocked来启动
            // ServiceRecord对象s所描述的一个Service组件,等到这个Service组件启动以后,AMS再将它与
            // ActivityRecord对象Activity所描述的一个Activity绑定自来
            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 && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.
                try {
                    // 这里的c.conn是ServiceDispatcher.InnerConnection对象,这里最终调用
                    // ServiceDispatcher中的doConnected方法
                    c.conn.connected(s.name, b.intent.binder);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortName
                            + " 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) {// 重新绑定
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {// 首次绑定
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }

            getServiceMap(s.userId).ensureNotStartingBackground(s);

        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return 1;
    }

这里代码比较多,所以写的注释也比较多,前面主要是判断是否绑定过该服务,并对InnerConnection进行缓存,放置到各个列表中,让Activity,Service进行联系。最后调用requestServiceBindingLocked方法,这个方法调用两次,一次是首次绑定,一个是重新绑定。

Step9.AMS.requestServiceBindingLocked

    // 参数rebind表示是否需要将ServiceRecord对象r所描述的Service组件重新绑定到IntentBindRecord对象i
    // 所描述的应用程序进程中如果为false,则说明为第一绑定
    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
                                                      boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        ...
        // 检查AMS是否已经为IntentBindRecord对象i所描述的应用程序进程请求过ServiceRecord对象r所描述的
        // Service组件返回其内部的一个Binder本地对象。如果还没有请求requested为false并且apps的数量大于0
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                // 会执行到Service的onBind方法
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    // 设置为true,防止重复请求
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            ...
        }
        return true;
    }

这里是判断首次绑定还是重新绑定,这两种绑定都会执行绑定步骤,这里有个参数i.requested,代表是否是首次绑定,如果默认值是false,如果不是重新绑定,那么执行完绑定就会设置为true。然后调用thread.scheduleBindServic方法,这个方法讲了很多次了,最终调用ApplicationThread.scheduleBindService方法,然后通过handler调用ActivityThread.handleBindService方法。

Step10.ActivityThread.handleBindService

    private void handleBindService(BindServiceData data) {
        // 通过token来获得一个描述Service组件的Service对象
        Service s = mServices.get(data.token);
        ...
                    if (!data.rebind) {// 首次绑定
                        // 获取一个实现了IBinder接口的Binder对象
                        IBinder binder = s.onBind(data.intent);
                        // 调用AMS代理对象的成员函数publishService,将前面得到的Binder本地对象传递给AMS
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
    }

这里如果是首次绑定调用onBind方法,否则调用onRebind方法,在首次调用绑定后还有publishService方法,自己看一下,不在详细分析了。这样绑定流程就分析完了,难度不大。下面我们开分析解绑过程。

Service解绑流程-unbindService

首先来看解绑流程时序图:

Service4.jpg

Step1.ContextImpl.unbindService

    public void unbindService(ServiceConnection conn) {
        ...
        if (mPackageInfo != null) {
            // 获取将ServiceConnection对象conn封装成一个实现了IServiceConnection接口的Binder
            // 本地对象sd(ServiceDispatcher.InnerConnection)
            IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                    getOuterContext(), conn);
            try {
                ActivityManagerNative.getDefault().unbindService(sd);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
    }

IServiceConnection对象的获取我们前面分析过了,这里直接过,然后调用AMP.unbindService方法,最终调用AMS.unbindService方法。

Step3.AMS.unbindService

    public boolean unbindService(IServiceConnection connection) {
        synchronized (this) {
            return mServices.unbindServiceLocked(connection);
        }
    }

这里调用ActiveServices.unbindServiceLocked方法。

Step4.ActiveServices.unbindServiceLocked

    boolean unbindServiceLocked(IServiceConnection connection) {
        IBinder binder = connection.asBinder();
        // 获取缓存中绑定列表
        ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
        ...
        try {
            while (clist.size() > 0) {
                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);
                }

                ....
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return true;
    }

首先从AMS中获取绑定过的列表,如果存在说明绑定过,然后调用removeConnectionLocked移除连接。

Step5.ActiveServices.removeConnectionLocked

    void removeConnectionLocked(
            ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
        // 获取连接中的Binder对象
        IBinder binder = c.conn.asBinder();
        // 获取连接应用、服务和连接列表的客户端
        AppBindRecord b = c.binding;
        // 获取描述服务的对象
        ServiceRecord s = b.service;
        // 根据Binder对象获取服务绑定的连接列表
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist != null) {
            clist.remove(c);// 移除该连接对象
            if (clist.size() == 0) {// 如果列表为空,移除该列表
                s.connections.remove(binder);
            }
        }
        // 从连接应用、服务和连接列表的客户端中的连接列表中移除
        b.connections.remove(c);
        ...
        // 从总的缓存列表中移除
        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.name);

        // 如果连接应用、服务和连接列表的客户端中的连接列表为空了,说明没有绑定了,那么移除该客户端
        if (b.connections.size() == 0) {
            b.intent.apps.remove(b.client);
        }

        if (!c.serviceDead) {// 服务还存在
            if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                    && b.intent.hasBound) {
                try {
                    ...
                    b.intent.doRebind = false;
                    s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                } catch (Exception e) {
                    Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
                    serviceProcessGoneLocked(s);
                }
            }

            ...
        }
    }

在绑定服务的时候进行各种缓存,加入各种列表,那么在接触绑定的时候就有从之前加入的列表中删除,然后执行接触绑定。

Step7.ActivityThread.handleUnbindService

    private void handleUnbindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                ...
                boolean doRebind = s.onUnbind(data.intent);// 调用解绑回调
                ...
            } catch (Exception e) {
                ...
            }
        }
    }

调用Service的onUnbind接触绑定。到这里接触绑定就分析完了,过程比较简单,只是上面的各种列表搞清楚要多看看。最后就剩下了stopService,我们一口气就将它分析完。

Service停止流程-stopService

首先来看停止服务流程时序图:

Service2.jpg

Step1.ContextImpl.stopSevice

    // 停止服务
    @Override
    public boolean stopService(Intent service) {
        warnIfCallingFromSystemProcess();
        return stopServiceCommon(service, mUser);
    }

调用stopServiceCommon停止服务。

Step2.ContextImpl.stopServiceCommon

    private boolean stopServiceCommon(Intent service, UserHandle user) {
        try {
            // 检验Intent,组件和包名不能为空
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            int res = ActivityManagerNative.getDefault().stopService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
            ...
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

这里最终调用AMS的stopService方法。

Step3.AMS.stopService

    public int stopService(IApplicationThread caller, Intent service,
                           String resolvedType, int userId) {
        ...

        synchronized (this) {
            return mServices.stopServiceLocked(caller, service, resolvedType, userId);
        }
    }

这里就是简单的调用ActiveServices.stopServiceLocked方法。

Step4.ActiveServices.stopServiceLocked

    int stopServiceLocked(IApplicationThread caller, Intent service,
                          String resolvedType, int userId) {

        // 根据caller获取调用者进程
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        ...
        if (r != null) {
            ...
                    stopServiceLocked(r.record);
            ...
            return -1;
        }

        return 0;
    }

简单的调用了stopServiceLocked方法。

Step6.ActiveServices.stopServiceLocked

    private void stopServiceLocked(ServiceRecord service) {
        ...
        bringDownServiceIfNeededLocked(service, false, false);
    }

我们前面分析过bringUp的是启动服务,因此对应的bringDown的是结束服务。

Step7.ActiveServices.bringDownServiceIfNeededLocked

    // 停止服务
    private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
                                                      boolean hasConn) {
        ...

        bringDownServiceLocked(r);
    }

这里只是简单的调用了bringDownServiceLocked方法,这个方法我们在服务启动时也遇到过,只是没有分析,我们放到了停止服务的流程中来分析,下面我们看看详细代码。

Step8.ActiveServices.bringDownServiceLocked

    private final void bringDownServiceLocked(ServiceRecord r) {
        
        for (int conni = r.connections.size() - 1; conni >= 0; conni--) {
            ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
            for (int i = 0; i < c.size(); i++) {
                ...
                    // 断开服务连接
                    cr.conn.connected(r.name, null);
                ...
            }
        }

        // Tell the service that it has been unbound.
        if (r.app != null && r.app.thread != null) {
            for (int i = r.bindings.size() - 1; i >= 0; i--) {
                IntentBindRecord ibr = r.bindings.valueAt(i);
                if (ibr.hasBound) {// 所有服务与客户端已经解绑
                    try {
                        ...
                        // 调用Service的onUnbind方法
                        r.app.thread.scheduleUnbindService(r,
                                ibr.intent.getIntent());
                    } catch (Exception e) {
                        ...
                    }
                }
            }
        }

        ...

        if (r.app != null) {// 服务进程存在
            ...
            if (r.app.thread != null) {
                updateServiceForegroundLocked(r.app, false);
                try {
                    ...
                    // 停止服务,调用onDestroy方法
                    r.app.thread.scheduleStopService(r);
                } catch (Exception e) {
                   ...
        ...
    }

这里主要有三步,第一步,断开服务连接,这个方法我们前面提到过,可以根据前面提到的去看看如何断开连接的;第二步,如果已经绑定了服务要解除绑定,这个在上面解除绑定的时候分析了该过程,因此这里就不再重复了;第三步,如果服务存在,则停止服务。我们开始分析第三步,第三步这里最终调用ActivityThread的handleStopService方法。

Step13.ActivityThread.handleStopService

    private void handleStopService(IBinder token) {
        Service s = mServices.remove(token);
        ...
                s.onDestroy();
                ...
    }

这里如果服务存在则调用服务的onDestroy方法,到这里服务的停止也就结束了。从上面看服务的整个流程相对于Activity简单的多。很容易就看懂了。其实还有一个IntentService,整个服务继承Service,只不过里面多了一个Handler,我们看看这段代码:

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

如果有Handler就有发送消息的地方,那么发送消息在哪里呢,我们知道当你调用服务的时候会走onStartCommand方法:

    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

这里会调用onStart方法:

    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

这里就是发送消息的时候,消息发出后会由上面的ServiceHandler来处理,我们看到构造函数里传入了一个Looper,这个是在onCreate方法中初始化的:

    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

这里创建了一个Handler线程,并且获取了它的Looper,用来循环处理消息,因此我们知道同时只能处理一个消息,等前一个消息处理完了才会处理第二个,以此类推,因此需要同时处理的不能用这个Service,另外在ServiceHandler中有个stopSelf用来在消息处理完成后停止自己,因此该服务可以说是用完自动停止,不会一直粗在,占用资源。

代码地址:

直接拉取导入开发工具(Intellij idea或者Android studio)

Android_Framework_Source

首发地址:http://www.codemx.cn

Android开发群:192508518

微信公众账号:Code-MX

注:本文原创,转载请注明出处,多谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容