Service启动流程(startService)

2023-10-11 21:48

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

前面分析了Activity的启动流程,下面开始分析Service的启动,本文分析的是startService的流程,android的版本为4.1.2

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

这就是startService的入口,mUser就是代表当前的用户,在后面启动Serivce的流程中,会通过此实例获取用户的uid。

private ComponentName startServiceCommon(Intent service, UserHandle user) {try {......ComponentName cn = ActivityManagerNative.getDefault().startService(mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), 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());}}return cn;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}

接下来通过binder通信,Service启动流程会进入ActivityManagerService的startService函数中。

public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType) {......synchronized(this) {final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();ComponentName res = startServiceLocked(caller, service,resolvedType, callingPid, callingUid);Binder.restoreCallingIdentity(origId);return res;}
}

接下来会调用startServiceLockedstartServiceLocked的逻辑稍微显得复杂一些,主要的难点是获取Service信息。

ComponentName startServiceLocked(IApplicationThread caller,Intent service, String resolvedType,int callingPid, int callingUid) {synchronized(this) {......ServiceLookupResult res =retrieveServiceLocked(service, resolvedType,callingPid, callingUid);if (res == null) {return null;}if (res.record == null) {return new ComponentName("!", res.permission != null? res.permission : "private to package");}ServiceRecord r = res.record;//检测当前用户是否有权限访问Intent中的Data和ClipDataint targetPermissionUid = checkGrantUriPermissionFromIntentLocked(callingUid, r.packageName, service);//将即将启动的Service从等待启动列表中删除if (unscheduleServiceRestartLocked(r)) {if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);}......if (!bringUpServiceLocked(r, service.getFlags(), false)) {return new ComponentName("!", "Service process is bad");}return r.name;}
}  

系统首先调用retriveServiceLocked 函数获取即将要启动的Service信息,并封装成ServiceLookupResult对象,ServiceLoopupResult对象内部包括了一个ServiceRecord对象和记录Service权限的字符串,retrivveServiceLocked函数的执行过程会在后面分析。获得ServiceLookupResult结果res后会进行判断,如果未找到即将启动的Service的ServiceLookupResult对象,则直接返回;接下来会将即将启动的Service从等待启动列表中删除,最终会调用会进入bringupServiceLockedbringupServiceLocked函数中包含了ActivityManagerService对Service进行不同配置以及系统处于不同状态的不同启动方式。

private final boolean bringUpServiceLocked(ServiceRecord r,int intentFlags, boolean whileRestarting) {//Slog.i(TAG, "Bring up service:");//r.dump("  ");//Service已经运行,则执行Service的onStartCommand函数if (r.app != null && r.app.thread != null) {sendServiceArgsLocked(r, false);return true;}//如果正在等待重启,则直接返回if (!whileRestarting && r.restartDelay > 0) {// If waiting for a restart, then do nothing.return true;}//从正在重启的服务列表中删除即将启动的服务mRestartingServices.remove(r);//服务正在启动,当前应用不能被停止try {AppGlobals.getPackageManager().setPackageStoppedState(r.packageName, false, r.userId);} catch (RemoteException e) {} catch (IllegalArgumentException e) {Slog.w(TAG, "Failed trying to unstop package "+ r.packageName + ": " + e);}final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;final String appName = r.processName;ProcessRecord app;//如果Service不需要运行在单独的进程if (!isolated) {//尝试获取Service的进程app = getProcessRecordLocked(appName, r.appInfo.uid);if (DEBUG_MU)Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);//如果Service所在进程已经启动,但是Service还未启动,则去执行realStartServiceLocked,在进程内执行Service的启动流程if (app != null && app.thread != null) {try {app.addPackage(r.appInfo.packageName);realStartServiceLocked(r, app);return true;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting service " + r.shortName, e);}// If a dead object exception was thrown -- fall through to// restart the application.}} else {// If this service runs in an isolated process, then each time// we call startProcessLocked() we will get a new isolated// process, starting another process if we are currently waiting// for a previous process to come up.  To deal with this, we store// in the service any current isolated process it is running in or// waiting to have come up.app = r.isolatedProc;}// Not running -- get it started, and enqueue this service record// to be executed when the app comes up.//Service所在的进程未启动,则启动进程if (app == null) {//如果Service所在进程并没有被启动,则根据Service信息去启动一个新的进程,新进程启动完成后则去启动Serviceif ((app=startProcessLocked(appName, r.appInfo, true, intentFlags,"service", r.name, false, isolated)) == null) {Slog.w(TAG, "Unable to launch app "+ r.appInfo.packageName + "/"+ r.appInfo.uid + " for service "+ r.intent.getIntent() + ": process is bad");bringDownServiceLocked(r, true);return false;}if (isolated) {r.isolatedProc = app;}}//将即将启动的Service添加到pending队列中if (!mPendingServices.contains(r)) {mPendingServices.add(r);}return true;
}

这部分的代码描述了调用startService时可能遇到的三种情况:

  • 目标Service已经启动,则去执行onStartCommand
  • 目标Service未启动,但是Service所在的进程已经启动
  • 目标Service未启动且Service所在进程未启动,需要新建进程

本篇的分析到此结束,接下来我会分3篇文章分别取分析这三种不同的启动方式。

这篇关于Service启动流程(startService)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Spring Security中用户名和密码的验证完整流程

《SpringSecurity中用户名和密码的验证完整流程》本文给大家介绍SpringSecurity中用户名和密码的验证完整流程,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 首先创建了一个UsernamePasswordAuthenticationTChina编程oken对象,这是S

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

java Long 与long之间的转换流程

《javaLong与long之间的转换流程》Long类提供了一些方法,用于在long和其他数据类型(如String)之间进行转换,本文将详细介绍如何在Java中实现Long和long之间的转换,感... 目录概述流程步骤1:将long转换为Long对象步骤2:将Longhttp://www.cppcns.c

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地