bindService绑定服务源码流程

Quibbler 2021-7-24 793

bindService绑定服务源码流程


        终于轮到双休,周末可以摸一下书。本次阅读的源码基于API 30,将来回头再看可能有误。



1、绑定Service

        Service作为四大组件之一,承担着执行后台任务的重担。有两种启动方式:startServicebindService

        本篇跟随源码了解绑定Service的过程。绑定Service仅需简单几步:

    //构造启动目标Service所需Intent
    Intent intent = new Intent();
    
    //构造绑定服务所需ServiceConnection连接对象
    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        
        }
        
        @Override        
        public void onServiceDisconnected(ComponentName name) {
        
        }
    };
    
    //绑定服务
    bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

        将Service的绑定过程拆分开来看,并不复杂,逻辑清晰。


1.1、Context中处理

        先从调用Context上下文的bindService(...)方法开始:

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }


        关于Context详见另一篇:各种Context及其初始化流程。它的实现类是ContextImpl,实现了bindService(...)方法:

    @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
                getUser());
    }

        内部调用bindServiceCommon(...)方法进入到AMS服务处理Service的启动和绑定。

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        ...
            int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
        ...
    }

        在进入AMS之前,先留意一下在bindServiceCommon(...)方法中获取了LoadedApk.ServiceDispatcher实例,封装了绑定服务所创建的ServiceConnection接口对象,这在后面绑定服务后回调用到。


1.2、AMS服务处理

        现在对AMS已经不再陌生,应用侧通过AIDL接口与系统服务完成远程调用。

    public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String instanceName,
            String callingPackage, int userId) throws TransactionTooLargeException {
        ...
        return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
    }

        调用ActiveServices中的bindServiceLocked()方法完成服务的绑定,这个方法很长很复杂。简化看:



1.3、创建服务*

        这一步不一定必须执行。如果服务没有创建还会先创建Service。以bringUpServiceLocked()方法为例开始,再执行realStartServiceLocked()方法,进入ApplicationThread执行scheduleCreateService(),向Handler发送CREATE_SERVICE消息执行handleCreateService()创建Service


1.4、绑定服务

        通过requestServiceBindingsLocked()完成服务的绑定,通样进入ApplicationThread执行scheduleBindService(),向Handler发送BIND_SERVICE消息执行handleBindService()绑定Service



2、bindService生命周期及回调

        通过对Service绑定源码流程的分析,对绑定Service的回调及生命周期会有更深刻的理解。


2.1、onServiceConnected回调

        接着1.4节继续往下看,执行handleBindService()方法

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        ...
        IBinder binder = s.onBind(data.intent);
        ActivityManager.getService().publishService(
                data.token, data.intent, binder);
        ...
    }

        回到AMS服务,执行publishService()方法:

    public void publishService(IBinder token, Intent intent, IBinder service) {
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }

        在ActiveServicespublishServiceLocked()方法中执行Service的连接:

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        ...
        try {
            c.conn.connected(r.name, service, false);
        } catch (Exception e) {
            
        }
        ...
    }

        还记得在1.1节中提到的LoadedApk.ServiceDispatcher吗?上面方法中回调的对象正是LoadedApk.ServiceDispatcher的内部类InnerConnection

    private static class InnerConnection extends IServiceConnection.Stub {
        @UnsupportedAppUsage
        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);
            }
        }
    }

        经过doConnected()层层调用,最终调用ServiceConnectiononServiceConnected()回调。

    public void doConnected(ComponentName name, IBinder service, boolean dead) {
        ...
        // 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);
        }
    }


2.2、onServiceDisconnected回调

        同上,Service断开连接的时候在doDeath()方法中回调ServiceConnectiononServiceDisconnected()方法。

    public void doDeath(ComponentName name, IBinder service) {
        ...
        mConnection.onServiceDisconnected(name);
    }


2.3、onBind回调

        在2.1节中提到的handleBindService()方法也执行了ServiceonBind()回调:

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        ...
        IBinder binder = s.onBind(data.intent);
        ...
    }

        ServiceonCreate()回调,当然是在Service创建的时候调用。

    private void handleCreateService(CreateServiceData data) {
        ...
        Service service = null;
        ...
        service.onCreate();
        ...
    }


2.4、onUnBind回调

        Service被“解绑”的时候,通过handleUnbindService()回调onUnBInd()方法。

    private void handleUnbindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        ...
        boolean doRebind = s.onUnbind(data.intent);
        ...       
    }



不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com