bindService绑定服务源码流程

QuibblerQuibbler 2021-07-24 约 15 分钟 2064 次阅读

bindService绑定服务源码流程

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

1、绑定Service

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

本篇跟随源码了解绑定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);
    }

在ActiveServices的publishServiceLocked()方法中执行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()层层调用,最终调用ServiceConnection的onServiceConnected()回调。

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()方法中回调ServiceConnection的onServiceDisconnected()方法。

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

2.3、onBind回调

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

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

Service的onCreate()回调,当然是在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);
        ...       
    }

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w