startService启动流程---Service在非App进程且未启动

2023-10-11 21:48

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

在 Service启动流程(startService)的最后,分析了在调用startService时可能存在的三种情况,本文分析第三种情况—Service不在App进程且未启动。

Service启动流程(startService)最后已经说明,在这种情况下,系统会执行startProcessLocked函数。startProcessLocked函数是不是很熟悉,在前面分析Activity从Launched中启动的时候,为了启动App,需要调用startProcessLocked函数创建新的进程。

private final void startProcessLocked(ProcessRecord app,String hostingType, String hostingNameStr) {......int debugFlags = 0;if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;// Also turn on CheckJNI for debuggable apps. It's quite// awkward to turn on otherwise.debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;}// Run the app in safe mode if its manifest requests so or the// system is booted in safe mode.if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||Zygote.systemInSafeMode == true) {debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;}if ("1".equals(SystemProperties.get("debug.checkjni"))) {debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;}if ("1".equals(SystemProperties.get("debug.jni.logging"))) {debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;}if ("1".equals(SystemProperties.get("debug.assert"))) {debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;}// Start the process.  It will either succeed and return a result containing// the PID of the new process, or else throw a RuntimeException.Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",app.processName, uid, uid, gids, debugFlags,app.info.targetSdkVersion, null);......
}  

函数中略去了不影响Process启动的代码,Process.start方法的执行,回去调用ActivityThreadmain方法。

public static void main(String[] args) {......ActivityThread thread = new ActivityThread();thread.attach(false);......
}  

继续看下ActivityThreadattach函数

private void attach(boolean system) {sThreadLocal.set(this);mSystemThread = system;if (!system) {......IActivityManager mgr = ActivityManagerNative.getDefault();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {// Ignore}} else {......}......
}  

由于Service进程不是系统进程,故attach会执行以上逻辑,attachApplication函数是跨进程调用,可以在ActivityManagerService中找到这个方法

private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {......try {......thread.bindApplication(processName, appInfo, providers,app.instrumentationClass, profileFile, profileFd, profileAutoStop,app.instrumentationArguments, app.instrumentationWatcher, testMode,enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),mCoreSettingsObserver.getCoreSettingsLocked());......} catch (Exception e) {// todo: Yikes!  What should we do?  For now we will try to// start another process, but that could easily get us in// an infinite loop of restarting processes...Slog.w(TAG, "Exception thrown during bind!", e);app.resetPackageList();app.unlinkDeathRecipient();startProcessLocked(app, "bind fail", processName);return false;}......//新建完进程后启动Serviceif (!badApp && mPendingServices.size() > 0) {ServiceRecord sr = null;try {for (int i=0; i<mPendingServices.size(); i++) {sr = mPendingServices.get(i);if (app != sr.isolatedProc && (app.uid != sr.appInfo.uid|| !processName.equals(sr.processName))) {continue;}mPendingServices.remove(i);i--;realStartServiceLocked(sr, app);didSomething = true;}} catch (Exception e) {Slog.w(TAG, "Exception in new application when starting service "+ sr.shortName, e);badApp = true;}}return true;
}  

这部分的代码有启动Service的逻辑,会在执行完新建进程后分析。直接定位到最关键的代码bindApplication,又是一个Binder跨进程调用,最终在ActivityThread中调用。

public final void bindApplication(String processName,ApplicationInfo appInfo, List<ProviderInfo> providers,ComponentName instrumentationName, String profileFile,ParcelFileDescriptor profileFd, boolean autoStopProfiler,Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode,boolean persistent, Configuration config, CompatibilityInfo compatInfo,Map<String, IBinder> services, Bundle coreSettings) {if (services != null) {// Setup the service cache in the ServiceManagerServiceManager.initServiceCache(services);}setCoreSettings(coreSettings);AppBindData data = new AppBindData();data.processName = processName;data.appInfo = appInfo;data.providers = providers;data.instrumentationName = instrumentationName;data.instrumentationArgs = instrumentationArgs;data.instrumentationWatcher = instrumentationWatcher;data.debugMode = debugMode;data.enableOpenGlTrace = enableOpenGlTrace;data.restrictedBackupMode = isRestrictedBackupMode;data.persistent = persistent;data.config = config;data.compatInfo = compatInfo;data.initProfileFile = profileFile;data.initProfileFd = profileFd;data.initAutoStopProfiler = false;queueOrSendMessage(H.BIND_APPLICATION, data);}  

又是Handler对消息的处理,可以直接定位到最终的执行函数handleBindApplication

private void handleBindApplication(AppBindData data) {mBoundApplication = data;......if (data.instrumentationName != null) {InstrumentationInfo ii = null;try {ii = appContext.getPackageManager().getInstrumentationInfo(data.instrumentationName, 0);} catch (PackageManager.NameNotFoundException e) {}if (ii == null) {throw new RuntimeException("Unable to find instrumentation info for: "+ data.instrumentationName);}mInstrumentationAppDir = ii.sourceDir;mInstrumentationAppLibraryDir = ii.nativeLibraryDir;mInstrumentationAppPackage = ii.packageName;mInstrumentedAppDir = data.info.getAppDir();mInstrumentedAppLibraryDir = data.info.getLibDir();ApplicationInfo instrApp = new ApplicationInfo();instrApp.packageName = ii.packageName;instrApp.sourceDir = ii.sourceDir;instrApp.publicSourceDir = ii.publicSourceDir;instrApp.dataDir = ii.dataDir;instrApp.nativeLibraryDir = ii.nativeLibraryDir;LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,appContext.getClassLoader(), false, true);ContextImpl instrContext = new ContextImpl();instrContext.init(pi, null, this);try {java.lang.ClassLoader cl = instrContext.getClassLoader();mInstrumentation = (Instrumentation)cl.loadClass(data.instrumentationName.getClassName()).newInstance();} catch (Exception e) {throw new RuntimeException("Unable to instantiate instrumentation "+ data.instrumentationName + ": " + e.toString(), e);}mInstrumentation.init(this, instrContext, appContext,new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher);if (mProfiler.profileFile != null && !ii.handleProfiling&& mProfiler.profileFd == null) {mProfiler.handlingProfiling = true;File file = new File(mProfiler.profileFile);file.getParentFile().mkdirs();Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);}} else {mInstrumentation = new Instrumentation();}if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();}// Allow disk access during application and provider setup. This could// block processing ordered broadcasts, but later processing would// probably end up doing the same disk access.final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();try {// If the app is being launched for full backup or restore, bring it up in// a restricted environment with the base application class.Application app = data.info.makeApplication(data.restrictedBackupMode, null);mInitialApplication = app;......try {mInstrumentation.onCreate(data.instrumentationArgs);}catch (Exception e) {throw new RuntimeException("Exception thrown in onCreate() of "+ data.instrumentationName + ": " + e.toString(), e);}try {//执行Application的onCreate方法mInstrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}} finally {StrictMode.setThreadPolicy(savedPolicy);}
}  

这段代码略去了不影响流程的代码,剩余的代码完成了新建Instrumentation对象mInstrumentation,然后调用了mInstrumentation.callApplicationOnCreate(app)方法,也就是执行了Application的onCreate方法。

这部分的逻辑也提醒我们,如果我们在应用中声明的Service不在应用的进程中,在启动Service的时候,应用的Application会执行。

好的,上面的代码执行完成之后,Service所在的进程已经创建完毕,接下来就要真正走执行Service自己的方法流程了。在本文attachApplicationLocked方法的最后,会有一个启动Service的逻辑:

if (!badApp && mPendingServices.size() > 0) {ServiceRecord sr = null;try {for (int i=0; i<mPendingServices.size(); i++) {sr = mPendingServices.get(i);if (app != sr.isolatedProc && (app.uid != sr.appInfo.uid|| !processName.equals(sr.processName))) {continue;}mPendingServices.remove(i);i--;realStartServiceLocked(sr, app);didSomething = true;}} catch (Exception e) {Slog.w(TAG, "Exception in new application when starting service "+ sr.shortName, e);badApp = true;}}  

badAppp = false,在Service启动流程(startService)的最后,会将即将启动的ServiceRecord添加到ActivityManagerService的mPendingServices队列中,因此mPendingServices.size()>0,故会执行接下来的逻辑。接下来的逻辑中,会循环遍历mPendingServices,由于此时是在单独进程中启动Service,故会对新建的进程app进行判断,,并且会对app的uid和processName进行判断,条件满足说明不需要对Service执行启动操作,执行continue,否则执行realStartServiceLocked去启动Service,realStartServiceLocked函数的逻辑可以参考startService启动流程—Service在App进程但未启动的内容,这里就不在进行分析了

这篇关于startService启动流程---Service在非App进程且未启动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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. 运行阶

使用Go实现文件复制的完整流程

《使用Go实现文件复制的完整流程》本案例将实现一个实用的文件操作工具:将一个文件的内容完整复制到另一个文件中,这是文件处理中的常见任务,比如配置文件备份、日志迁移、用户上传文件转存等,文中通过代码示例... 目录案例说明涉及China编程知识点示例代码代码解析示例运行练习扩展小结案例说明我们将通过标准库 os

一文解密Python进行监控进程的黑科技

《一文解密Python进行监控进程的黑科技》在计算机系统管理和应用性能优化中,监控进程的CPU、内存和IO使用率是非常重要的任务,下面我们就来讲讲如何Python写一个简单使用的监控进程的工具吧... 目录准备工作监控CPU使用率监控内存使用率监控IO使用率小工具代码整合在计算机系统管理和应用性能优化中,监

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

Linux进程CPU绑定优化与实践过程

《Linux进程CPU绑定优化与实践过程》Linux支持进程绑定至特定CPU核心,通过sched_setaffinity系统调用和taskset工具实现,优化缓存效率与上下文切换,提升多核计算性能,适... 目录1. 多核处理器及并行计算概念1.1 多核处理器架构概述1.2 并行计算的含义及重要性1.3 并

Linux下进程的CPU配置与线程绑定过程

《Linux下进程的CPU配置与线程绑定过程》本文介绍Linux系统中基于进程和线程的CPU配置方法,通过taskset命令和pthread库调整亲和力,将进程/线程绑定到特定CPU核心以优化资源分配... 目录1 基于进程的CPU配置1.1 对CPU亲和力的配置1.2 绑定进程到指定CPU核上运行2 基于

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存