android startService流程梳理笔记

2024-04-28 02:08

本文主要是介绍android startService流程梳理笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、ContextWrapper.startService

  startService是Context的方法,Activity、Service都继承自ContextWrapper,而ContextWrapper又继承自Context,BroadcastReceiver的onReceive方法中有个参数是Context类型的,所以我们在Activity、Service、BroadcastReceiver中都可以调用startService方法,当在Activity等中调用startService时,首先会调用到ContextWrapper的startService方法:

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

2、ContextImpl.startService

  mBase是ContextImpl的实例,从名字也可以看到ContextImpl也是Context的子类,从ContextWrapper的名字也可以看到,它只是Context的包装类,其函数内部的实现都是通过调用内部ContextImpl类的实例mBase来完成实际请求,这被称为装饰者模式。

  ContextImpl的startService直接调用startServiceAsUser,在startServiceAsUser中调用ActivityManagerNative.getDefault().startService,ActivityManagerNative.getDefault()返回一个IActivityManager对象,典型的Binder通信。所以接下来会通过ActivityManagerProxy的startService经由Binder调用到ActivityManagerService(继承自ActivityManagerNative)的startService方法。

public ComponentName startServiceAsUser(Intent service, UserHandle user) {
     try {
         service.setAllowFds( false );
         ComponentName cn = ActivityManagerNative.getDefault().startService(
             mMainThread.getApplicationThread(), service,
             service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
     ...
         return cn;
     } catch (RemoteException e) {
         return null ;
     }
}

3、ActivityManagerService.startService与ActiveServices

  在ActivityManagerService的startService中,首先检查Caller的合法性(PID、UID),然后调用ActiveServices的startServiceLocked方法(在旧版本中这个方法在ActivityManagerService中),在startServiceLocked中,首先通过retrieveServiceLocked检索我们调用startService时传入的Intent信息,将结果存入ServiceLookupResult.record中(ServiceRecord),紧接着调用ActiveServices的bringUpServiceLocked方法。

  在bringUpServiceLocked中调用ActivityManagerService的startProcessLocked获得一个ProcessRecord对象并将其加入到mPendingServices队列中。startServiceLocked、bringUpServiceLocked都是从ActivityManagerService中调用过来的,所以是一直运行在ActivityaManagerService进程中,再调用ActivityManagerService的方法就是直接调用,而不用通过IPC。

  ActivityManagerService中有两个重载形式的startProcessLocked,首先进入参数多的那一个,通过newProcessRecordLocked获得一个ProcessRecord对象,然后把这个对象作为参数调用另一个形式的startProcessLocked,在这个startProcessLocked中,调用Process.start创建一个新的进程,将返回的Process.ProcessStartResult对象、新进程的PID及获得的ProcessRecord对象放入mPidSelfLocked列表中。

final ProcessRecord startProcessLocked(String processName,
         ApplicationInfo info, boolean knownToBeDead, int intentFlags,
         String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated) {
     ...
     app = newProcessRecordLocked( null , info, processName, isolated);
     ...
     startProcessLocked(app, hostingType, hostingNameStr);
     return (app.pid != 0 ) ? app : null ;
}
private final void startProcessLocked(ProcessRecord app,
         String hostingType, String hostingNameStr) {
     ...
     Process.ProcessStartResult startResult = Process.start( "android.app.ActivityThread" ,
                     app.processName, uid, uid, gids, debugFlags, mountExternal,
                     app.info.targetSdkVersion, null , null );
     ...
     synchronized (mPidsSelfLocked) {
         this .mPidsSelfLocked.put(startResult.pid, app);
         ...
     }
     ...
}

4、ActivityThread.main

  在Process.start中创建了一个进程,然后调用了ActivityThread的main函数。

public static void main(String[] args) {
     ...
     Looper.prepareMainLooper();
     ActivityThread thread = new ActivityThread();
     thread.attach( false );
     if (sMainThreadHandler == null ) {
         sMainThreadHandler = thread.getHandler();
     }
     ...
     Looper.loop();
     ...
}

5、ActivityManagerService.attachApplication

  在main中新建一个ActivityThread对象,并调用其attach方法,参数表示是否是系统进程。这里已经是在新进程里了。在attach中,又调用了ActivityManagerNative.getDefault().attachApplication(mAppThread)。同样,经由Binder由ActivityManagerProxy到了ActivityManagerService的attachApplication方法,在attachApplication中直接调用attachApplicationLocked。

  在attachApplicationLocked中,通过新进程的PID获得在第3步中放入mPidSelfLocked列表中的ProcessRecord对象,然后调用ActiveyServices的attachApplicationLocked方法,在这个方法中通过进程PID与进程名找到在第3步中放入mPendingServices中的ServiceRecord对象,再以这个找到的ServiceRecord对象与传入的ProcessRecord对象为参数调用realStartServiceLocked,这个函数也在ActiveServices中。

private final boolean attachApplicationLocked(IApplicationThread thread, nt pid) {
     ProcessRecord app;
     if (pid != MY_PID && pid >= 0 ) {
         synchronized (mPidsSelfLocked) {
             app = mPidsSelfLocked.get(pid);
         }
     } else {
         app = null ;
     }
     ...
     mServices.attachApplicationLocked(app, processName);
     ...
}
boolean attachApplicationLocked(ProcessRecord proc, String processName) throws Exception {
     boolean didSomething = false ;
     // Collect any services that are waiting for this process to come up.
     if (mPendingServices.size() > 0 ) {
         ServiceRecord sr = null ;
         try {
             for ( int i= 0 ; i<mPendingServices.size(); i++) {
                 sr = mPendingServices.get(i);
                 if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                         || !processName.equals(sr.processName))) {
                     continue ;
                 }
                 mPendingServices.remove(i);
                 i--;
                 realStartServiceLocked(sr, proc);
                 didSomething = true ;
             }
         } catch (Exception e) {
             Slog.w(TAG, "Exception in new application when starting service "
                     + sr.shortName, e);
             throw e;
         }
     }
     ...
}

6、ActiveServices.realStartServiceLocked

  在realStartServiceLocked中,取得传入的ProcessRecord对象的IApplicationThread类型的成员变量thread,调用其scheduleCreateService方法,同ActivityManagerProxy一样,调用的是ApplicationThreadProxy的scheduleCreateService,然后经由Binder到ApplicationThread的scheduleCreateService(ApplicationThread是ActivityThread的私有内部类)。

7、ApplicationThread.scheduleCreateService与ActivityThread.handleCreateService

  在ApplicationThread的scheduleCreateService中调用了外部类ActivityThread的queueOrSendMessage方法,向H中sendMessage(H继承自Handler),接下来肯定到了H的handleMessage,在handleMessage中走CREATE_SERVICE的switch case,调用外部类ActivityThread的handleCreateService方法。

  在handleCreateService通过JAVA的ClassLoader load加载要启动的Service的类,并通过newInstance新建一个Service的实例,new ContextImpl,makeApplication并跟新建的Service实例attach,然后调用我们熟悉的Service的onCreate方法,至此Service启动成功。

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();
     LoadedApk packageInfo = getPackageInfoNoCheck(
             data.info.applicationInfo, data.compatInfo);
     Service service = null ;
     try {
         java.lang.ClassLoader cl = packageInfo.getClassLoader();
         service = (Service) cl.loadClass(data.info.name).newInstance();
     } catch (Exception e) {
         ...
     }
     try {
         if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
         ContextImpl context = new ContextImpl();
         context.init(packageInfo, null , this );
         Application app = packageInfo.makeApplication( false , mInstrumentation);
         context.setOuterContext(service);
         service.attach(context, this , data.info.name, data.token, app,
                     ActivityManagerNative.getDefault());
         // 调用Service的onCreate,即要启动的Service的onCreate
         service.onCreate();
         mServices.put(data.token, service);
         try {
             ActivityManagerNative.getDefault().serviceDoneExecuting(
                     data.token, 0 , 0 , 0 );
         } catch (RemoteException e) {
             // nothing to do.
         }
     } catch (Exception e) {
         ...
     }
}

 

总结:

  1、调用ContextImpl的startService,通过Binder进入ActivityManagerService的进程执行ActivityManagerService的startService方法。

  2、在startService过程中新建一个进程,在新建的进程中创建Looper,调用ActivityThread的attach方法,然后就又进入了ActivityManagerService的进程。

  3、获取要在新进程启动的服务的相关信息,在ActivityManagerService中通过ApplicationThreadProxy又进入Service进程,Service的进程启起来,调用我们熟悉的Service的onCreate方法。

这篇关于android startService流程梳理笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/942087

相关文章

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

MySQL 升级到8.4版本的完整流程及操作方法

《MySQL升级到8.4版本的完整流程及操作方法》本文详细说明了MySQL升级至8.4的完整流程,涵盖升级前准备(备份、兼容性检查)、支持路径(原地、逻辑导出、复制)、关键变更(空间索引、保留关键字... 目录一、升级前准备 (3.1 Before You Begin)二、升级路径 (3.2 Upgrade

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)

《SpringBoot从main方法到内嵌Tomcat的全过程(自动化流程)》SpringBoot启动始于main方法,创建SpringApplication实例,初始化上下文,准备环境,刷新容器并... 目录1. 入口:main方法2. SpringApplication初始化2.1 构造阶段3. 运行阶