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

相关文章

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

一文带你了解SpringBoot中启动参数的各种用法

《一文带你了解SpringBoot中启动参数的各种用法》在使用SpringBoot开发应用时,我们通常需要根据不同的环境或特定需求调整启动参数,那么,SpringBoot提供了哪些方式来配置这些启动参... 目录一、启动参数的常见传递方式二、通过命令行参数传递启动参数三、使用 application.pro

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

Linux中的进程间通信之匿名管道解读

《Linux中的进程间通信之匿名管道解读》:本文主要介绍Linux中的进程间通信之匿名管道解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基本概念二、管道1、温故知新2、实现方式3、匿名管道(一)管道中的四种情况(二)管道的特性总结一、基本概念我们知道多

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

Linux进程终止的N种方式详解

《Linux进程终止的N种方式详解》进程终止是操作系统中,进程的一个重要阶段,他标志着进程生命周期的结束,下面小编为大家整理了一些常见的Linux进程终止方式,大家可以根据需求选择... 目录前言一、进程终止的概念二、进程终止的场景三、进程终止的实现3.1 程序退出码3.2 运行完毕结果正常3.3 运行完毕

Spring AI ectorStore的使用流程

《SpringAIectorStore的使用流程》SpringAI中的VectorStore是一种用于存储和检索高维向量数据的数据库或存储解决方案,它在AI应用中发挥着至关重要的作用,本文给大家介... 目录一、VectorStore的基本概念二、VectorStore的核心接口三、VectorStore的

python之流程控制语句match-case详解

《python之流程控制语句match-case详解》:本文主要介绍python之流程控制语句match-case使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录match-case 语法详解与实战一、基础值匹配(类似 switch-case)二、数据结构解构匹

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景

Windows命令之tasklist命令用法详解(Windows查看进程)

《Windows命令之tasklist命令用法详解(Windows查看进程)》tasklist命令显示本地计算机或远程计算机上当前正在运行的进程列表,命令结合筛选器一起使用,可以按照我们的需求进行过滤... 目录命令帮助1、基本使用2、执行原理2.1、tasklist命令无法使用3、筛选器3.1、根据PID