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

相关文章

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Nginx、Tomcat等项目部署问题以及解决流程

《Nginx、Tomcat等项目部署问题以及解决流程》本文总结了项目部署中常见的four类问题及其解决方法:Nginx未按预期显示结果、端口未开启、日志分析的重要性以及开发环境与生产环境运行结果不一致... 目录前言1. Nginx部署后未按预期显示结果1.1 查看Nginx的启动情况1.2 解决启动失败的

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica