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

相关文章

检查 Nginx 是否启动的几种方法

《检查Nginx是否启动的几种方法》本文主要介绍了检查Nginx是否启动的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1. 使用 systemctl 命令(推荐)2. 使用 service 命令3. 检查进程是否存在4

解决idea启动项目报错java: OutOfMemoryError: insufficient memory

《解决idea启动项目报错java:OutOfMemoryError:insufficientmemory》:本文主要介绍解决idea启动项目报错java:OutOfMemoryError... 目录原因:解决:总结 原因:在Java中遇到OutOfMemoryError: insufficient me

SpringBoot项目整合Netty启动失败的常见错误总结

《SpringBoot项目整合Netty启动失败的常见错误总结》本文总结了SpringBoot集成Netty时常见的8类问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、端口冲突问题1. Tomcat与Netty端口冲突二、主线程被阻塞问题1. Netty启动阻

SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)

《SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)》本文总结了SpringBoot项目整合Kafka启动失败的常见错误,包括Kafka服务器连接问题、序列化配置错误、依赖配置问题、... 目录一、Kafka服务器连接问题1. Kafka服务器无法连接2. 开发环境与生产环境网络不通二、序

Java JAR 启动内存参数配置指南(从基础设置到性能优化)

《JavaJAR启动内存参数配置指南(从基础设置到性能优化)》在启动Java可执行JAR文件时,合理配置JVM内存参数是保障应用稳定性和性能的关键,本文将系统讲解如何通过命令行参数、环境变量等方式... 目录一、核心内存参数详解1.1 堆内存配置1.2 元空间配置(MetASPace)1.3 线程栈配置1.

在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)

《在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)》DataGrip是JetBrains公司出品的一款现代化数据库管理工具,支持多种数据库系统,包括MySQL,:本文主要介绍在D... 目录前言一、登录 mysql 服务器1.1 打开 DataGrip 并添加数据源1.2 配置 MySQL

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Spring Boot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)

《SpringBoot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)》本文将以一个实际案例(用户管理系统)为例,详细解析SpringBoot中Co... 目录引言:为什么学习Spring Boot分层架构?第一部分:Spring Boot的整体架构1.1

nodejs打包作为公共包使用的完整流程

《nodejs打包作为公共包使用的完整流程》在Node.js项目中,打包和部署是发布应用的关键步骤,:本文主要介绍nodejs打包作为公共包使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言一、前置准备二、创建与编码三、一键构建四、本地“白嫖”测试(可选)五、发布公共包六、常见踩坑提醒

Ubuntu向多台主机批量传输文件的流程步骤

《Ubuntu向多台主机批量传输文件的流程步骤》:本文主要介绍在Ubuntu中批量传输文件到多台主机的方法,需确保主机互通、用户名密码统一及端口开放,通过安装sshpass工具,准备包含目标主机信... 目录Ubuntu 向多台主机批量传输文件1.安装 sshpass2.准备主机列表文件3.创建一个批处理脚