对于操做系统来讲,进程管理是其最重要的职责之一。
考虑到这部分的内容较多,所以会拆分红几篇文章来说解。
本文是进程管理系统文章的第一篇,会讲解Android系统中的进程建立。
本文适合Android平台的应用程序开发者,也适合对于Android系统内部实现感兴趣的读者。html
Android系统以Linux内核为基础,因此对于进程的管理天然离不开Linux自己提供的机制。例如:java
经过fork来建立进行linux
经过信号量来管理进程android
经过proc文件系统来查询和调整进程状态
等ios
对于Android来讲,进程管理的主要内容包括如下几个部份内容:编程
进程的建立api
进程的优先级管理数组
进程的内存管理服务器
进程的回收和死亡处理微信
本文会专门讲解进程的建立,其他部分将在后面的文章中讲解。
为了便于下文的讲解,这里先介绍一下Android系统中牵涉到进程建立的几个主要模块。
同时为了便于读者更详细的了解这些模块,这里也同时提供了这些模块的代码路径。
这里提到的代码路径是指AOSP的源码数中的路径。
关于如何获取AOSP源码请参见这里:Downloading the Source。
本文以Android N版本的代码为示例,所用到的Source Code Tags是:android-7.0.0_r1。
相关模块:
app_process
代码路径:frameworks/base/cmds/app_process
说明:app_process是一个可执行程序,该程序的主要做用是启动zygote
和system_server
进程。
Zygote
代码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
说明:zygote
进程是全部应用进程的父进程,这是系统中一个很是重要的进程,下文咱们会详细讲解。
ActivityManager
代码路径:frameworks/base/services/core/java/com/android/server/am/
说明:am是ActivityManager的缩写。
这个目录下的代码负责了Android所有四大组件(Activity,Service,ContentProvider,BroadcastReceiver)的管理,而且还掌控了全部应用程序进程的建立和进程的优先级管理。
所以,这个部分的内容将是本系列文章讲解的重点。
Android官方开发网站的这篇文章:Processes and Threads 很是好的介绍了Android系统中进程相关的一些基本概念和重要知识。
在阅读下文以前,请务必将这篇文章浏览一遍。
在Android系统中,进程能够大体分为系统进程和应用进程两大类。
系统进程是系统内置的(例如:init
,zygote
,system_server
进程),属于操做系统必不可少的一部分。系统进程的做用在于:
管理硬件设备
提供访问设备的基本能力
管理应用进程
应用进程是指应用程序运行的进程。这些应用程序多是系统出厂自带的(例如Launcher,电话,短信等应用),也多是用户本身安装的(例如:微信,支付宝等)。
系统进程的数量一般是固定的(出厂或者系统升级以后就肯定了),而且系统进程一般是一直存活,常驻内存的。系统进程的异常退出将可能致使设备没法正常使用。
而应用程序和应用进程在每一个人使用的设备上一般是各不同的。如何管理好这些不肯定的应用进程,就是操做系统自己要仔细考虑的内容。也是衡量一个操做系统好坏的标准之一。
在本文中,咱们会介绍init
,zygote
和system_server
三个系统进程。
除此以外,本系列文章将会把主要精力集中在讲解Android系统如何管理应用进程上。
init进程是一切的开始,在Android系统中,全部进程的进程号都是不肯定的,惟独init进程的进程号必定是1。
由于这个进程必定是系统起来的第一个进程。而且,init进程掌控了整个系统的启动逻辑。
咱们知道,Android可能运行在各类不一样的平台,不一样的设备上。所以,启动的逻辑是不尽相同的。
为了适应各类平台和设备的需求,init进程的初始化工做经过init.rc
配置文件来管理。
你能够在AOSP源码的system/core/rootdir/
路径找到这些配置文件。
配置文件的主入口文件是init.rc
,这个文件会经过import
引入其余几个文件。
在本文中,咱们统称这些文件为init.rc
。
init.rc经过Android Init Language来进行配置。
建议读者大体阅读一下其 语法说明 。
init.rc中配置了系统启动的时候该作哪些事情,以及启动哪些系统进程。
这其中有两个特别重要的进程就是:zygote和system_server进程。
zygote的中文意思是“受精卵“。这是一个颇有寓意的名称:全部的应用进程都是由zygote
fork出来的子进程,所以zygote进程是全部应用进程的父进程。
system_server 这个进程正如其名称同样,这是一个系统服务器。Framework层的几乎全部服务都位于这个进程中。这其中就包括管理四大组件的ActivityManagerService
。
init.rc文件会根据平台不同,选择下面几个文件中的一个来启动zygote进程:
init.zygote32.rc
init.zygote32_64.rc
init.zygote64.rc
init.zygote64_32.rc
这几个文件的内容是大体一致的,仅仅是为了避免同平台服务的。这里咱们以init.zygote32.rc的文件为例,来看看其中的内容:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
在这段配置文件中(若是你不明白这段配置的含义,请阅读一下文档:Android Init Language),启动了一个名称叫作zygote
的服务进程。这个进程是经过/system/bin/app_process
这个可执行程序建立的。
而且在启动这个可执行程序的时候,传递了`-Xzygote /system/bin --zygote --start-system-server
class main` 这些参数。
要知道这里到底作了什么,咱们须要看一下app_process的源码。
app_process的源码在这个路径:frameworks/base/cmds/app_process/app_main.cpp
。
这个文件的main函数的有以下代码:
int main(int argc, char* const argv[]) { ... while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; ... } ... if (!className.isEmpty()) { ... } else { ... if (startSystemServer) { args.add(String8("start-system-server")); } } ... if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); } else { fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } }
这里会判断,
若是执行这个命令时带了--zygote
参数,就会经过runtime.start
启动com.android.internal.os.ZygoteInit
。
若是参数中带有--start-system-server
参数,就会将start-system-server
添加到args中。
这段代码是C++实现的。在执行这段代码的时候尚未任何Java的环境。而runtime.start
就是启动Java虚拟机,并在虚拟机中启动指定的类。因而接下来的逻辑就在ZygoteInit.java中了。
这个文件的main
函数主要代码以下:
public static void main(String argv[]) { ... try { ... boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { ... } } ... registerZygoteSocket(socketName); ... preload(); ... Zygote.nativeUnmountStorageOnInit(); ZygoteHooks.stopZygoteNoThreadCreation(); if (startSystemServer) { startSystemServer(abiList, socketName); } Log.i(TAG, "Accepting command socket connections"); runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
在这段代码中,咱们主要关注以下几行:
经过 registerZygoteSocket(socketName);
注册Zygote Socket
经过 preload();
预先加载全部应用都须要的公共资源
经过 startSystemServer(abiList, socketName);
启动system_server
经过 runSelectLoop(abiList);
在Looper上等待链接
这里须要说明的是:zygote进程启动以后,会启动一个socket套接字,并经过Looper一直在这个套接字上等待链接。
全部应用进程都是经过发送数据到这个套接字上,而后由zygote进程建立的。
这里还有一点说明的是:
在Zygote进程中,会经过preload
函数加载须要应用程序都须要的公共资源。
预先加载这些公共资源有以下两个好处:
加快应用的启动速度 由于这些资源已经在zygote进程启动的时候加载好了
经过共享的方式节省内存 这是Linux自己提供的机制:父进程已经加载的内容能够在子进程中进行共享,而不用多份数据拷贝(除非子进程对这些数据进行了修改。)
preload的资源主要是Framework相关的一些基础类和Resource资源,而这些资源正是全部应用都须要的:
开发者经过Android SDK开发应用所调用的API实现都在Framework中。
static void preload() { Log.d(TAG, "begin preload"); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "BeginIcuCachePinning"); beginIcuCachePinning(); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses"); preloadClasses(); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources"); preloadResources(); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL"); preloadOpenGL(); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); preloadSharedLibraries(); preloadTextResources(); WebViewFactory.prepareWebViewInZygote(); endIcuCachePinning(); warmUpJcaProviders(); Log.d(TAG, "end preload"); }
上文已经提到,zygote进程起来以后会根据须要启动system_server
进程。
system_server
进程中包含了大量的系统服务。例如:
负责网络管理的NetworkManagementService
负责窗口管理的WindowManagerService
负责震动管理的VibratorService
负责输入管理的InputManagerService
等等。关于system_server,咱们从此会其余的文章中专门讲解,这里不作过多说明。
在本文中,咱们只关注system_server
中的ActivityManagerService
这个系统服务。
上文中提到:zygote进程在启动以后会启动一个socket,而后一直在这个socket等待链接。
而会链接它的就是ActivityManagerService
。由于ActivityManagerService
掌控了全部应用进程的建立。
全部应用程序的进程都是由ActivityManagerService
经过socket发送请求给Zygote
进程,而后由zygote fork建立的。ActivityManagerService
经过Process.start
方法来请求zygote
建立进程:
public static final ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); throw new RuntimeException( "Starting VM process through Zygote failed", ex); } }
这个函数会将启动进程所须要的参数组装好,并经过socket发送给zygote进程。而后zygote进程根据发送过来的参数将进程fork出来。
在ActivityManagerService
中,调用Process.start的地方是下面这个方法:
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { ... Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); ... }
下文中咱们会看到,全部四大组件进程的建立,都是调用这里的startProcessLocked
这个方法而建立的。
对于每个应用进程,在ActivityManagerService
中,都有一个ProcessRecord
与之对应。这个对象记录了应用进程的全部详细状态。
PS:对于ProcessRecord
的内部结构,在下一篇文章中,咱们会讲解。
为了查找方便,对于每一个ProcessRecord
会存在下面两个集合中。
按名称和uid组织的集合:
/** * All of the applications we currently have running organized by name. * The keys are strings of the application package name (as * returned by the package manager), and the keys are ApplicationRecord * objects. */ final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
按pid组织的集合:
/** * All of the processes we currently have running organized by pid. * The keys are the pid running the application. * * <p>NOTE: This object is protected by its own lock, NOT the global * activity manager lock! */ final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
下面这幅图小节了上文的这些内容:
<img src="http://qiangbo-workspace.oss-... width="600">
Processes and Threads 提到:
“当某个应用组件启动且该应用没有运行其余任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。”
所以,四大组件中的任何一个先起来都会致使应用进程的建立。下文咱们就详细看一下,它们启动时,各自是如何致使应用进程的建立的。
PS:四大组件的管理自己又是一个比较大的话题,限于篇幅关系,这里不会很是深刻的讲解,这里主要是讲解四大组件与进程建立的关系。
在应用程序中,开发者经过:
startActivity(Intent intent)
来启动Activity
startService(Intent service)
来启动Service
sendBroadcast(Intent intent)
来发送广播
ContentResolver
中的接口来使用ContentProvider
这其中,startActivity
,startService
和sendBroadcast
还有一些重载方法。
其实这里提到的全部这些方法,最终都是经过Binder调用到ActivityManagerService中,由其进行处理的。
这里特别说明一下:应用进程和ActivityManagerService
所在进程(即system_server
进程)是相互独立的,两个进程之间的方法一般是不能直接互相调用的。
而Android系统中,专门提供了Binder框架来提供进程间通信和方法调用的能力。
调用关系以下图所示:
<img src="http://qiangbo-workspace.oss-... width="600" >
在ActivityManagerService中,对每个运行中的Activity都有一个ActivityRecord
对象与之对应,这个对象记录Activity的详细状态。
ActivityManagerService中的startActivity
方法接受Context.startActivity
的请求,该方法代码以下:
@Override public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId()); }
Activity的启动是一个很是复杂的过程。这里咱们简单介绍一下背景知识:
ActivityManagerService中经过Stack和Task来管理Activity
每个Activity都属于一个Task,一个Task可能包含多个Activity。一个Stack包含多个Task
ActivityStackSupervisor类负责管理全部的Stack
Activity的启动过程会牵涉到:
Intent的解析
Stack,Task的查询或建立
Activity进程的建立
Activity窗口的建立
Activity的生命周期调度
Activity的管理结构以下图所示:
<img src="http://qiangbo-workspace.oss-... width="500">
在Activity启动的最后,会将前一个Activity pause,将新启动的Activity resume以便被用户看到。
在这个时候,若是发现新启动的Activity进程尚未启动,则会经过startSpecificActivityLocked
将其启动。整个调用流程以下:
ActivityManagerService.activityPaused
=>
ActivityStack.activityPausedLocked
=>
ActivityStack.completePauseLocked
=>
ActivityStackSupervisor.ensureActivitiesVisibleLocked
=>
ActivityStack.makeVisibleAndRestartIfNeeded
=>
ActivityStackSupervisor.startSpecificActivityLocked
=>
ActivityManagerService.startProcessLocked
ActivityStackSupervisor.startSpecificActivityLocked
关键代码以下:
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); r.task.stack.setLaunchTime(r); if (app != null && app.thread != null) { ... } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
这里的ProcessRecord app
描述了Activity所在进程。
Service的启动相对于Activity来讲要简单一些。
在ActivityManagerService中,对每个运行中的Service都有一个ServiceRecord
对象与之对应,这个对象记录Service的详细状态。
ActivityManagerService中的startService
方法处理Context.startService
API的请求,相关代码:
@Override public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws TransactionTooLargeException { ... synchronized(this) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, callingPackage, userId); Binder.restoreCallingIdentity(origId); return res; } }
这段代码中的mServices
对象是ActiveServices
类型的,这个类专门负责管理活动的Service。
启动Service的调用流程以下:
ActivityManagerService.startService
=>
ActiveServices.startServiceLocked
=>
ActiveServices.startServiceInnerLocked
=>
ActiveServices.bringUpServiceLocked
=>
ActivityManagerService.startProcessLocked
ActiveServices.bringUpServiceLocked
会判断若是Service所在进程尚未启动,
则经过ActivityManagerService.startProcessLocked
将其启动。相关代码以下:
// Not running -- get it started, and enqueue this service record // to be executed when the app comes up. if (app == null && !permissionsReviewRequired) { if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) { String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " + r.intent.getIntent() + ": process is bad"; Slog.w(TAG, msg); bringDownServiceLocked(r); return msg; } if (isolated) { r.isolatedProc = app; } }
这里的mAm
就是ActivityManagerService。
在ActivityManagerService中,对每个运行中的ContentProvider都有一个ContentProviderRecord
对象与之对应,这个对象记录ContentProvider的详细状态。
开发者经过ContentResolver中的insert
, delete
, update
, query
这些API来使用ContentProvider。在ContentResolver的实现中,不管使用这里的哪一个接口,ContentResolver都会先经过acquireProvider
这个方法来获取到一个类型为IContentProvider
的远程接口。这个远程接口对接了ContentProvider的实现提供方。
同一个ContentProvider可能同时被多个模块使用,而调用ContentResolver接口的进程只是ContentProvider的一个客户端而已,真正的ContentProvider提供方是运行自身的进程中的,两个进程的通信须要经过Binder的远程接口形式来调用。以下图所示:
<img src="http://qiangbo-workspace.oss-... width="500">
ContentResolver.acquireProvider
最终会调用到ActivityManagerService.getContentProvider
中,该方法代码以下:
@Override public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) { enforceNotIsolatedCaller("getContentProvider"); if (caller == null) { String msg = "null IApplicationThread when getting content provider " + name; Slog.w(TAG, msg); throw new SecurityException(msg); } // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal // with cross-user grant. return getContentProviderImpl(caller, name, null, stable, userId); }
而在getContentProviderImpl
这个方法中,会判断对应的ContentProvider进程有没有启动,
若是没有,则经过startProcessLocked
方法将其启动。
开发者经过Context.sendBroadcast
接口来发送广播。ActivityManagerService.broadcastIntent
方法了对应广播发送的处理。
广播是一种一对多的消息形式,广播接受者的数量是不肯定的。所以发送广播自己多是一个很耗时的过程(由于要逐个通知)。
在ActivityManagerService内部,是经过队列的形式来管理广播的:
BroadcastQueue
描述了一个广播队列
BroadcastRecord
描述了一个广播事件
在ActivityManagerService
中,若是收到了一个发送广播的请求,会先建立一个BroadcastRecord
接着将其放入BroadcastQueue
中。
而后通知队列本身去处理这个广播。而后ActivityManagerService
本身就能够继续处理其余请求了。
广播队列自己是在另一个线程处理广播的发送的,这样保证的ActivityManagerService
主线程的负载不会过重。
在BroadcastQueue.processNextBroadcast(boolean fromMsg)
方法中真正实现了通知广播事件到接受者的逻辑。在这个方法,若是发现接受者(即BrodcastReceiver)尚未启动,便会经过ActivityManagerService.startProcessLocked
方法将其启动。相关以下所示:
final void processNextBroadcast(boolean fromMsg) { ... // Hard case: need to instantiate the receiver, possibly // starting its application process to host it. ResolveInfo info = (ResolveInfo)nextReceiver; ComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); ... // Not running -- get it started, to be executed when the app comes up. if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Need to start app [" + mQueueName + "] " + targetProcess + " for broadcast " + r); if ((r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. Slog.w(TAG, "Unable to launch app " + info.activityInfo.applicationInfo.packageName + "/" + info.activityInfo.applicationInfo.uid + " for broadcast " + r.intent + ": process is bad"); logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; } mPendingBroadcast = r; mPendingBroadcastRecvIndex = recIdx; } }
至此,四大组件的启动就已经分析完了。
进程管理自己是一个很是大的话题,本文讲解了Android系统中进程建立的相关内容。
进程启动以后该如何管理就是下一篇文章要讲解的内容了。
敬请期待。