Framework 学习之旅:Service 启动过程

news2024/9/21 0:46:19

前言

Service 的启动过程将分为两个部分,分别是ContextImpl到ActivityManageService调用过程和ActivityThread启动Service过程。

ContextImpl到ActivityManageService调用过程

一般启动服务操作在Activity中调用startService方法,从Activity的startService开始进行了解,Activity继承ContextWrapper,所以调用的是ContextWrapper的startService方法。

frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }

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

从以上代码可知,startService方法最终调用的是mBase的startService方法,mBase是Context类型并且它是一个抽象类,mBase具体指向实际上是ContextImpl类(它是Context的实现类)。原因是:在Activity的启动流程中,ActivityThread启动Activity会调用performLaunchActivity()方法。

frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......
    ContextImpl appContext = createBaseContextForActivity(r);//1
    ......
    if (activity != null) {
        ......
          activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback,
                        r.assistToken);
        ......
    }
}

frameworks/base/core/java/android/app/Activity.java

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, IBinder assistToken) {
              ......
               attachBaseContext(context);
              ......
            }
            
protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase); 
        if (newBase != null) {
            newBase.setAutofillClient(this);
            newBase.setContentCaptureOptions(getContentCaptureOptions());
        }
    }

在注释1处创建上下文对象appContext,并传入Activity的attach方法中,将Activity与上下文对象appContext关联起来,这个上下文对象appContext的具体类型是什么,查看createBaseContextForActivity()方法:

frameworks/base/core/java/android/app/ActivityThread.java

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    .....
    ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
   .....
   return appContext;
}

从以上代码可以看出,上下文对象appContext具体类型就是Contextlmpl,在Activity的attach方法中将Contextlmpl赋值给ContextWrapper的成员变量mBase,mBase具体指向的就是Contextlmpl。查看Contextlmpl的startService方法:

frameworks/base/core/java/android/app/ContextImpl.java

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // 直接调用 AMS的 startService方法 , 返回一个 ComponentName 对象。
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
            .......
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

ContextImpl的startService方法调用自身的startServiceCommon方法,在startServiceCommon()方法中调用AMS的代理IActivityManager的startService方法,最终调用的是AMS的startService方法。

frameworks/base/core/java/android/app/ActivityManager.java

    /**
     * @hide
     */
    @UnsupportedAppUsage
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }
    
     @UnsupportedAppUsage
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

从以上源码可知,ActivityManager最终获取的是IActivityManager,通过AIDL实现应该程序进程与AMS所在的SystemServer进程通信,而他的实现则在ActivityMangerService中。前面分析的ContextImpl的startServiceCommon方法中最终调用的就是AMS的startServie方法,并且将mMainThread.getApplicationThread获取的IApplicationThread的实现类ApplicationThread引用传递给AMS,方便后续AMS能与应用程序进程通信启动Service。

时序图

在这里插入图片描述

ActivityThread启动Service过程

接着,上一节分析ContextImpl最终调用的是AMS的startService方法:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ......
    
    final ActiveServices mServices;
    ......
            
     public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        ........
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);//1
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
}

从源码可以看出,AMS实现了IActivityManager,并且实现了startService方法。从注释1处调用mServices的startServiceLocked方法,mServices的类型是ActiveServices,ActiveServices是用来管理Service的类。继续看ActiveServices的startServiceLocked方法:

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            final int userId, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
        .......

        ServiceLookupResult res =
            retrieveServiceLocked(service, null, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false);//1
        .......

        ServiceRecord r = res.record;//2

        .......

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

注释1处的retrieveServiceLocked方法会查找是否有与参数service对应的ServiceRecord,如果没有找到,就会调用PackageManagerService去获取参数service对应的Service信息,并封装到ServiceRecord中,最后将ServiceRecord封装为ServiceLookupResult返回。其中ServiceRecord用于描述一个Service。

注释2处,根据ServiceLookupResult获取对应的ServiceRecord,并传入到注释3处的startServicelnnerLocked方法中。

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
       
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);//1
        if (error != null) {
            return new ComponentName("!!", error);
        }

       .....

        return r.name;
    }

在startServicelnnerLock方法继续调用了ActiveServices的bringUpServiceLocked方法,继续查看:

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

final ActivityManagerService mAm;
 
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
    // 获取Service在哪个进程中运行
    final String procName = r.processName;//1
    HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
    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.longVersionCode, 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.shortInstanceName, e);
                }
        }    
    }else{
        app = r.isolatedProc;
        .....
    }
    
    // 如果用来运行Service的应用程序进程不存在    
    if (app == null && !permissionsReviewRequired) {//5
        // 创建应用程序 
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, false, isolated, false)) == null) {//6
            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处得到ServiceRecord的processName值并赋值给procName,其中processName用来描述Service要在哪个进程中运行,默认是当前进程,我们也可以在AndroidManifest文件中设 android:process属性来新开启一个进程运行Service 。

在注释2处将procName和Service的uid传入到AMS的getProcessRecordLocked方法,查询是否存在一个与Service对应的ProcessRecord 类型的对象app,ProcessRecord主要描述运行的程序进程的信息。

注释5处判断Service对应app为null则说明用来运行Service的应用程序不存在,则调用注释6处的AMS的startProcessLock方法来创建对应的应用程序进程。

在注释3处判断如果用来运行Service的应用程序存在,则调用注释4处的rea!StartServiceLocked方法来启动 Service:

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
   .....
   r.setProcess(app);//1
   
    try {
            ......
            
            app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());//2
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
           .....
        } finally {
            ........
        }
}

注释1处将获取的应用程序进程设置给ServiceRecord也就是Service组件,代表它将在哪个应用程序进程启动。

注释2处realStartServiceLocked方法中调用了app.thread的scheduleCreateService方法。其中app.thread是IApplicationThread类型的,它的实现是ActivityThread的内部类ApplicationThread。

继续看到ApplicationThread的scheduleCreateService方法:

frameworks/base/core/java/android/app/ActivityThread.java

public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;//1
            sendMessage(H.CREATE_SERVICE, s);//2
    }

scheduleLaunchActivity的方法将启动Service的参数封装成 CreateServiceData,sendMessage方法向H类发送类型为CREATE_SERVICE的消息,并将CreateServiceData传递过去。sendMessage
方总有多个重载方法,最终调用的sendMessage方法如下所示:

frameworks/base/core/java/android/app/ActivityThread.java

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) {
            Slog.v(TAG,
                    "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj);
        }
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

这里mH指的是H,它是ActivityThread的内部类并继承自Handler ,是应用程序进程中主线程的消息管理类。我们接着查看handleMessage方法:

frameworks/base/core/java/android/app/ActivityThread.java

class H extends Handler {
     public static final int CREATE_SERVICE          = 114;
     .....
     public void handleMessage(Message msg) {
         switch (msg.what) {
             ....
             case CREATE_SERVICE:
               handleCreateService((CreateServiceData)msg.obj);
               break;
             ....  
         }
     }
     ....
}

handleMessage方法根据消息类型为CREAE_SERVICE调用handleCreateService方法:

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        // 获取要启动Service的应用程序的LoadedApk
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);//1
        Service service = null;
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//2
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //获取类加载器
            java.lang.ClassLoader cl = packageInfo.getClassLoader();//3
            // 创建Service 实例
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);//4
            // Service resources must be initialized with the same loaders as the application
            // context.
            context.getResources().addLoaders(
                  app.getResources().getLoaders().toArray(new ResourcesLoader[0]));

            context.setOuterContext(service);
            // 初始化Service
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());//5
            service.onCreate();//6
            mServices.put(data.token, service);//7
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

在注释1处获取要启动Service的应用程序的LoadedApk,LoadedApk是一个APK文件的描述类。

在注释2处创建Service的上下文环境ContextImpl对象。

在注释3处通过调用LoadedAPK的getClassLoader方法来获取类加载器。

在注释4处,创建Service实例。

在注释5处通过Service的attach方法来初始化Service。

在注释6处调用Service的onCreate方法,这样Service就启动了。

在注释7处将启动的Service加入到ActivityThread的成员变量mServices中,其中mServices是ArrayMap类型。

时序图

在这里插入图片描述
至此,Service 启动分析过程结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/60449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]计算机毕业设计springboot智慧园区运营管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

360T7路由器进行WiFi无线中继教程

360T7路由器进行WiFi中继教程1. 概述2. 360T7路由器进行WiFi中继实现教程2.1 登录路由器管理界面2.2 选择上网方式2.3 搜索WiFi2.4 连接WiFi2.5 点击确认2.6 在主页面查看网络1. 概述 中继路由系统由一组中继路由器组成&#xff0c;为不能交换路由信息的路由域提供中继路由。该…

关于小程序session_key漏洞问题的解决2022-12-01

业务背景&#xff1a;开发了小程序&#xff0c;使用了一段时间以后&#xff0c;小程序提示系统漏洞session_key的问题&#xff0c;在网上找了好多的博客&#xff0c;感觉好多写的没那么清晰&#xff0c;更偏重于理论&#xff0c;导致自己走了很多的弯路&#xff0c;为了更方便快…

基于海鸥算法优化的lssvm回归预测-附代码

基于海鸥算法优化的lssvm回归预测 - 附代码 文章目录基于海鸥算法优化的lssvm回归预测 - 附代码1.数据集2.lssvm模型3.基于海鸥算法优化的LSSVM4.测试结果5.Matlab代码摘要&#xff1a;为了提高最小二乘支持向量机&#xff08;lssvm&#xff09;的回归预测准确率&#xff0c;对…

【树莓派不吃灰】Linux服务器篇(核心概念)

目录1. 第一章 架设服务器前的准备工作2. 第二章 基础网络概念3. 第三章 局域网络架构简介4. 第四章 连上 Internet5. 第五章 Linux 常用网络指令6. 第六章 Linux 网络侦错7. 第七章 网络安全与主机基本防护8. 第八章 路由观念与路由器设定9. 第九章 防火墙与 NAT 服务器&#…

Python源码剖析2-字符串对象PyStringObject

二、 1、PyStringObject与 PyString_Type PyStringObject是变长对象中的不可变对象。当创建了一个PyStringObject对象之后,该对象内部维护的字符串就不能再被改变了。这一点特性使得 PyStringObject 对象能作为 PyDictObject 的键值,但同时也使得一些字符串操作的效率大大降低…

Kafka RecordAccumulator 三 高并发写入数据

Kafka RecordAccumulator 三 高并发写入数据 首先我们客户端会通过多线程的方式来发送消息&#xff08;一般业务需求可能会通过业务系统或者大数据流计算系统如Spark Streaming或者Flink将业务数据发送出去&#xff0c;进而让下游系统消费使用&#xff09;&#xff0c;那这里业…

【Linux】进程状态|僵尸进程 |孤儿进程

索引运行状态&#xff1a;阻塞状态挂起状态看看Linux是怎么做的运行状态R睡眠状态S停止状态T两个特殊的进程&#xff1a;僵尸进程孤儿进程在之前我们听过很多很多进程的状态&#xff0c;像是运行、新建、就绪、挂起、阻塞、等待、停止、挂机、死亡等等。推荐阅读&#xff1a;通…

http协议之digest(摘要)认证,详细讲解并附Java SpringBoot源码

目录 1.digest认证是什么&#xff1f; 2.digest认证过程 3.digest认证参数详解 4.基于SpringBoot实现digest认证 5.digest认证演示 6.digest认证完整项目 7.参考博客 1.digest认证是什么&#xff1f; HTTP通讯采用人类可阅读的文本格式进行数据通讯&#xff0c;其内容非…

Android入门第40天-Android中的Service(SimpleStartService)

简介 博文总阅读量已经突破了300万&#xff0c;给自己加油打CALL。 从今天开始&#xff0c;之前39天的Android如果每一篇只有30分钟就能读完和掌握那么从今天开始越往后会越复杂。因为我们的Android教程开始进入“中级”难度了。特别是Service&#xff0c;这个Service我要分成…

java面向对象的三大特性之封装和继承(配视频讲解)

&#x1f345;程序员小王的博客&#xff1a;程序员小王的博客 &#x1f345;程序员小王的资源博客&#xff1a;http://wanghj.online/ &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 如有编辑错误联系作者&#xff0c;如果有比较好的文章欢迎…

JMeter入门教程(13) --事务

文章目录1.任务背景2.任务目标3.任务实操3.1.1 事务控制器3.2.2循环控制器1.任务背景 JMeter中的事务是通过事务控制器实现的。&#xff0c;为了衡量服务器对某一个或一系列操作处理的响应时间&#xff0c;需要定义事务。下面我们详细介绍在JMeter中如何使用事务 2.任务目标 …

基于JSP的网络教学平台的设计与实现

目 录 摘 要 I Abstract II 一、 引言 1 &#xff08;一&#xff09;项目开发的背景 1 &#xff08;二&#xff09;项目开发的意义 1 二、可行性分析及总体设计原则 3 &#xff08;一&#xff09;可行性分析 3 1&#xff0e;技术可行性 3 2&#xff0e;经济可行性 3 3&#xff…

MATLAB算法实战应用案例精讲-【图像处理】目标检测(附实战案例及代码实现)

前言 目标检测,也叫目标提取,是一种基于目标几何和统计特征的图像分割。它将目标的分割和识别合二为一,其准确性和实时性是整个系统的一项重要能力。尤其是在复杂场景中,需要对多个目标进行实时处理时,目标自动提取和识别就显得特别重要。 随着计算机技术的发展和计算机视…

Servlet —— Tomcat, 初学 Servlet 程序

JavaEE传送门JavaEE HTTP —— HTTP 响应详解, 构造 HTTP 请求 HTTPS —— HTTPS的加密方式 目录TomcatServlethello world创建项目引入 Servlet 依赖创建目录结构编写代码doGet打包程序部署程序验证程序Tomcat Tomcat 是一个 HTTP 服务器 HTTP 客户端, 就是大家平时用到的浏…

大数据hadoop_HDFS概述(1)

文章目录1. HDFS概述1.1 HDFS背景1.2 定义2. HDFS优缺点2.1 优点2.2 缺点3. HDFS架构4. HDFS文件块大小1. HDFS概述 1.1 HDFS背景 面对今天的互联网公司&#xff0c;每天都会有上亿次的用户访问量&#xff0c;用户每进行一次操作&#xff0c;都会产生数据&#xff0c;面对传统…

Android入门第41天-Android中的Service(bindService)

介绍 在前一天我们介绍了Android中有两种启动Service的方法。并擅述了startService和bindService的区别。同时我们着重讲了startService。 因此今天我们就来讲bindService。bindService大家可以认为它是和Android的一个共生体。即这个service所属的activity如果消亡那么bindS…

Docker涉及的Linux命名空间、CGroups

概述 Linux的NameSpace介绍 很多编程语言都包含了命名空间的概念&#xff0c;我们可以认为命名空间是一种封装&#xff0c;封装本身实现了代码的隔离。在操作系统中命名空间提供的是系统资源的隔离&#xff0c;其中系统资源包括了&#xff1a;进程、网络、文件系统…实际上li…

《模拟电子技术》半导体原理部分笔记

《模拟电子技术》笔记绪论第一章 常用半导体器件第二章 基本放大电路绪论 有的人把三极管的出现作为电子技术工业革命的开始标志学习架构&#xff1a;半导体器件&#xff08;二极管、三极管、场效应晶体管&#xff09;、基于上述管的放大电路、集成运算放大器、放大电路的频率…

第11章 初识IdentityServer4

1 构建IdentityServer4 服务 1.1 通过配置类配置类(Config)实例化IdentityServer4中间件 using IdentityServer4.Models; namespace BuilderServer { /// <summary> /// 【配置--类】 /// <remarks> /// 摘要&#xff1a; /// 通过该中类的方法成员&#xff…