Android启动之Service启动流程

前言

Service启动与上一篇说的入口Activity启动类似,主要分成ContextImpl到ActivityManagerService调用和ActivityThread启动Service这两个过程

ContextImpl到AMS的调用过程

这个过程比较简单,如图所示

在这里插入图片描述

启动Service肯定是从startService开始,这个方法是在ContextWrapper中实现的,在这个方法中调用了ContextImpl的startService方法。

在ContextImpl中经过startServiceCommon,最终通过IActivityManager的startService方法来通知AMS启动一个Service。

ActivityThread启动Service

这部分过程如图:

在这里插入图片描述

上一个过程最终是调用了AMS的startService方法,这个过程就是从这开始的,这里会调用ActiveService的startServiceLocked,代码如下:

ComponentName startServiceLocked(...) throws TransactionTooLargeException {
        
    ...

    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false);  //1
    if (res == null) {
        return null;
    }
    if (res.record == null) {
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }

    ServiceRecord r = res.record;  //1

    ...

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

代码1处通过retrieveServiceLocked方法会先查找参数service对应的ServiceRecord;如果没有回调用PackageManagerService取获取参数service对应的Service信息并封装到ServiceRecord。最后将ServiceRecord封装成ServiceLookupResult返回。可以看到这里与上一篇讲的Activity很类似,ServiceRecord就像ActivityRecord一样用来描述一个Service。

代码2就是从ServiceLookupResult取出ServiceRecord,然后调用startServiceInnerLocked。

startServiceInnerLocked方法会调用bringUpServiceLocked方法,这个方法代码如下:

private String bringUpServiceLocked(...) throws TransactionTooLargeException {
        
    ...

    final String procName = r.processName;  //1
    String hostingType = "service";
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); //2

        ...

        if (app != null && app.thread != null) { //3
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                realStartServiceLocked(r, app, execInFg); //4
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }

        }
    } else {          
        ...
    }

    if (app == null && !permissionsReviewRequired) { //5
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,  //6
                hostingType, r.name, false, isolated, false)) == null) {
            String msg = "Unable to launch app "
                    + r.appInfo.packageName + "/"
                    + r.appInfo.uid + " for service "
                    + r.intent.getIntent() + ": process is bad";
            Slog.w(TAG, msg);
            bringDownServiceLocked(r);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    ...

    return null;
}

代码1得到进程名称。代码2调用AMS的getProcessRecordLocked查询与该Service对应的ProcessRecord,ProcessRecord一看名字就应该能猜出来了,主要是描述运行的应用程序进程信息。所以代码2的目的就是获取该Service对应的应用程序进程。

代码3处判断如果应用程序进程存在,则执行代码4,通过realStartServiceLocked方法来启动Service。

如果不存在就会跳到代码5,再次判断不存在则在代码6处调用AMS的startProcessLocked来创建对应的应用程序信息。

在realStartServiceLocked方法中调用了IApplicationThread的scheduleCreateService方法,它的实现是ActivityThread内部类ApplicatioinThread,这块跟Activity启动几乎一样。

scheduleCreateService将service的启动参数封装后通过Handler进行通知。最终会在ActivityThread处理,处理方法是handleCreateService,代码如下:

private void handleCreateService(CreateServiceData data) {
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);  //1
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();  //2
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);  //3
    } catch (Exception e) {
        ...
    }

    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//4
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());  //5
        service.onCreate();  //6
        mServices.put(data.token, service);  //7
        ...
    } catch (Exception e) {
        ...
    }
}

代码2会获取类加载器,然后代码3从之前封装的对象中获取Service信息,创建service;代码4获取上下文;代码5通过service的attach方法来初始化service;代码6则调用了service的onCreate方法;代码7将service加入ActivithThread的成员变量mServices中,以便后续使用。

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

  • 29
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值