Android笔记-service启动过程分析:startService源码分析


前言:

Service的启动流程将会分为一个系列来讲述。
本系列开始将分析Service的启动过程。
看这个系列文章之前你所需要知道的知识点:

  1. 熟悉service的基本用法。
  2. 了解bind机制,知道android的客户端和AMS间通信流程。
  3. 最好学习过activity的启动流程。

本系列将涉及到以下一些分支:
startService源码分析
bindService源码分析、startService和bindService区别
第二次startService为什么没有调用onCreate
为什么bindService和startService同时调用后需要同时调用unBind和stop才能使服务停止。
前台Service原理
今天这一篇将讲述startService源码分析:


service启动过程分析

startService和bindService流程图

image

了解Context

Context分析

开始分析startService源码我们之前先了解下Context。
context是一个抽象类,它定义了一些通用方法。
最常见的有:

startActivity()//启动Activity
startService() //启动Service
stopServic() //停止Service
unbindService()//取消绑定Service 
bindService()  //绑定Service
registerReciver()//  注册广播
sendBroadCastReciver()//  发送广播
getResources()  //获取资源
.....  还有好多

我们看到四大组件基本操作都在这个类里面定义好了,还有一些方法也是我们日常开发中用到的。
今天我们要看的是startService这个方法。
先看一下源码:

  public abstract ComponentName startService(Intent service);

很简单定义了一个抽象方法,需要传入一个Intent。
这个方法的实现在哪呢?我们可以从Activity里面的startActivity追溯一下。
从源码里面发现Activity里面并实现没有startService方法。
而在ContextWrapper里面实现了,方法如下:


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

这个mBase是什么?其实它也是一个Context。他是那里来的呢?
熟悉Activity启动流程的小伙伴一定知道最终启动Activity时候,Activity会先调用一下attach方法,没错这个mBase就是在这时候赋值的:


    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);//给mBase赋值
        ...
}

activity中的attach方法的第一参数就是赋值给mBase的。我们再看它是什么,从源码中看到,其实他是一个ContextImpl。如下:

ContextImpl appContext = createBaseContextForActivity(r);

createBaseContextForActivity具体做内容可以暂时不看,但我们可以知道,原来真正实现startService的类是ContextImpl。
小结:
Context:抽象类,定义了开发中常用方法,如四大组件的使用方法。
ContextImpl:继承Context,真正实现Context中的方法。
ContextWrapper:继承Context,包含一个ContextImpl。是包装类,是Activity、Service、Application的父类。
他们的关系可以看类图:

Context相关类图

image

startService源码分析

onCreate流程源码分析

下面我们就真正进入ContextImpl的startService学习吧。
startService源码如下:

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

startServiceCommon源码如下:

 private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(//进程间通信,进入AMS流程
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), 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());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

我们看到这里用到了跨进程通信,最终会调用AMS的startService方法。(这里涉及的跨进程通信机制不详细说明了,我在startActivity源码分析一文中有详细说明,感兴趣的可以自行了解)。
再看AMS中的startService:

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

        if (callingPacka
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值