【移动应用开发技术】Android中怎么创建进程_第1页
【移动应用开发技术】Android中怎么创建进程_第2页
【移动应用开发技术】Android中怎么创建进程_第3页
【移动应用开发技术】Android中怎么创建进程_第4页
【移动应用开发技术】Android中怎么创建进程_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】Android中怎么创建进程

Android中怎么创建进程,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面在下将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Android系统以Linux内核为基础,所以对于进程的管理自然离不开Linux本身提供的机制。例如:通过fork来创建进行通过信号量来管理进程通过proc文件系统来查询和调整进程状态等对于Android来说,进程管理的主要内容包括以下几个部分内容:进程的创建进程的优先级管理进程的内存管理进程的回收和死亡处理本文会专门讲解进程的创建,其余部分将在后面的文章中讲解。主要模块为了便于下文的讲解,这里先介绍一下Android系统中牵涉到进程创建的几个主要模块。同时为了便于读者更详细的了解这些模块,这里也同时提供了这些模块的代码路径。这里提到的代码路径是指AOSP的源码数中的路径。关于如何获取AOSP源码请参见这里:DownloadingtheSource。本文以AndroidN版本的代码为示例,所用到的SourceCodeTags是: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官方开发网站的这篇文章:ProcessesandThreads

非常好的介绍了Android系统中进程相关的一些基本概念和重要知识。在阅读下文之前,请务必将这篇文章浏览一遍。关于进程在Android系统中,进程可以大致分为系统进程和应用进程两大类。系统进程是系统内置的(例如:init,zygote,system_server进程),属于操作系统必不可少的一部分。系统进程的作用在于:管理硬件设备提供访问设备的基本能力管理应用进程应用进程是指应用程序运行的进程。这些应用程序可能是系统出厂自带的(例如Launcher,电话,短信等应用),也可能是用户自己安装的(例如:微信,支付宝等)。系统进程的数量通常是固定的(出厂或者系统升级之后就确定了),并且系统进程通常是一直存活,常驻内存的。系统进程的异常退出将可能导致设备无法正常使用。而应用程序和应用进程在每个人使用的设备上通常是各不一样的。如何管理好这些不确定的应用进程,就是操作系统本身要仔细考虑的内容。也是衡量一个操作系统好坏的标准之一。在本文中,我们会介绍init,zygote和system_server三个系统进程。除此之外,本系列文章将会把主要精力集中在讲解Android系统如何管理应用进程上。init进程init进程是一切的开始,在Android系统中,所有进程的进程号都是不确定的,唯独init进程的进程号一定是1。因为这个进程一定是系统起来的***个进程。并且,init进程掌控了整个系统的启动逻辑。我们知道,Android可能运行在各种不同的平台,不同的设备上。因此,启动的逻辑是不尽相同的。为了适应各种平台和设备的需求,init进程的初始化工作通过init.rc配置文件来管理。你可以在AOSP源码的system/core/rootdir/路径找到这些配置文件。配置文件的主入口文件是init.rc,这个文件会通过import引入其他几个文件。在本文中,我们统称这些文件为init.rc。init.rc通过AndroidInitLanguage来进行配置。建议读者大致阅读一下其语法说明。init.rc中配置了系统启动的时候该做哪些事情,以及启动哪些系统进程。这其中有两个特别重要的进程就是:zygote和system_server进程。zygote的中文意思是“受精卵“。这是一个很有寓意的名称:所有的应用进程都是由zygote

fork出来的子进程,因此zygote进程是所有应用进程的父进程。system_server

这个进程正如其名称一样,这是一个系统服务器。Framework层的几乎所有服务都位于这个进程中。这其中就包括管理四大组件的ActivityManagerService。Zygote进程init.rc文件会根据平台不一样,选择下面几个文件中的一个来启动zygote进程:init.zygote32.rcinit.zygote32_64.rcinit.zygote64.rcinit.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在这段配置文件中(如果你不明白这段配置的含义,请阅读一下文档:AndroidInit

Language),启动了一个名称叫做zygote的服务进程。这个进程是通过/system/bin/app_process这个可执行程序创建的。并且在启动这个可执行程序的时候,传递了`-Xzygote/system/bin--zygote--start-system-serverclassmain`这些参数。要知道这里到底做了什么,我们需要看一下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("ernal.os.ZygoteInit",

args,

zygote);

}

else

if

(className)

{

runtime.start("ernal.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启动ernal.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);注册ZygoteSocket通过preload();预先加载所有应用都需要的公共资源通过startSystemServer(abiList,socketName);启动system_server通过runSelectLoop(abiList);在Looper上等待连接这里需要说明的是:zygote进程启动之后,会启动一个socket套接字,并通过Looper一直在这个套接字上等待连接。所有应用进程都是通过发送数据到这个套接字上,然后由zygote进程创建的。这里还有一点说明的是:在Zygote进程中,会通过preload函数加载需要应用程序都需要的公共资源。预先加载这些公共资源有如下两个好处:加快应用的启动速度因为这些资源已经在zygote进程启动的时候加载好了通过共享的方式节省内存

这是Linux本身提供的机制:父进程已经加载的内容可以在子进程中进行共享,而不用多份数据拷贝(除非子进程对这些数据进行了修改。)preload的资源主要是Framework相关的一些基础类和Resource资源,而这些资源正是所有应用都需要的:开发者通过AndroidSDK开发应用所调用的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");

}system_server进程上文已经提到,zygote进程起来之后会根据需要启动system_server进程。system_server进程中包含了大量的系统服务。例如:负责网络管理的NetworkManagementService负责窗口管理的WindowManagerService负责震动管理的VibratorService负责输入管理的InputManagerService等等。关于system_server,我们今后会其他的文章中专门讲解,这里不做过多说明。在本文中,我们只关注system_server中的ActivityManagerService这个系统服务。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,

cessName,

uid,

uid,

gids,

debugFlags,

mountExternal,

.targetSdkVersion,

.seinfo,

requiredAbi,

instructionSet,

.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">关于应用组件ProcessesandThreads提到:“当某个应用组件启动且该应用没有运行其他任何组件时,Android系统会使用单个执行线程为应用启动新的Linux进程。”因此,四大组件中的任何一个先起来都会导致应用进程的创建。下文我们就详细看一下,它们启动时,各自是如何导致应用进程的创建的。PS:四大组件的管理本身又是一个比较大的话题,限于篇幅关系,这里不会非常深入的讲解,这里主要是讲解四大组件与进程创建的关系。在应用程序中,开发者通过:startActivity(Intentintent)来启动ActivitystartService(Intentservice)来启动ServicesendBroadcast(Intentintent)来发送广播ContentResolver中的接口来使用ContentProvider这其中,startActivity,startService和sendBroadcast还有一些重载方法。其实这里提到的所有这些方法,最终都是通过Binder调用到ActivityManagerService中,由其进行处理的。这里特别说明一下:应用进程和ActivityManagerService所在进程(即system_server进程)是相互独立的,两个进程之间的方法通常是不能直接互相调用的。而Android系统中,专门提供了Binder框架来提供进程间通讯和方法调用的能力。调用关系如下图所示:<img

src="http://qiangbo-workspace.oss-...

width="600"

>Activity与进程创建在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包含多个TaskActivityStackSupervisor类负责管理所有的StackActivity的启动过程会牵涉到:Intent的解析Stack,Task的查询或创建Activity进程的创建Activity窗口的创建Activity的生命周期调度Activity的管理结构如下图所示:<imgsrc="http://qiangbo-workspace.oss-...width="500">在Activity启动的***,会将前一个Activitypause,将新启动的Activityresume以便被用户看到。在这个时候,如果发现新启动的Activity进程还没有启动,则会通过startSpecificActivityLocked将其启动。整个调用流程如下:ActivityManagerService.activityPaused=>ActivityStack.activityPausedLocked=>ActivitySpletePauseLocked=>ActivityStackSupervisor.ensureActivitiesVisibleLocked=>ActivityStack.makeVisibleAndRestartIfNeeded=>ActivityStackSupervisor.startSpecificActivityLocked=>ActivityManagerService.startProcessLockedActivityStackSupervisor.startSpecificActivityLocked关键代码如下:void

startSpecificActivityLocked(ActivityRecord

r,

boolean

andResume,

boolean

checkConfig)

{

//

Is

this

activity's

application

already

running?

ProcessRecord

app

=

mService.getProcessRecordLocked(cessName,

.applicationInfo.uid,

true);

r.task.stack.setLaunchTime(r);

if

(app

!=

null

&&

app.thread

!=

null)

{

...

}

mService.startProcessLocked(cessName,

.applicationInfo,

true,

0,

"activity",

ent.getComponent(),

false,

false,

true);

}这里的ProcessRecordapp描述了Activity所在进程。Service与进程创建Service的启动相对于Activity来说要简单一些。在ActivityManagerService中,对每一个运行中的Service都有一个ServiceRecord对象与之对应,这个对象记录Service的详细状态。ActivityManagerService中的startService方法处理Context.startServiceAPI的请求,相关代码:@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.startProcessLockedActiveServices.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",

,

false,

isolated,

false))

==

null)

{

String

msg

=

"Unable

to

launch

app

"

+

r.appInfo.packageName

+

"/"

+

r.appInfo.uid

+

"

for

service

"

+

ent.getIntent()

+

":

process

is

bad";

Slog.w(TAG,

msg);

bringDownServiceLocked(r);

return

msg;

}

if

(isolated)

{

r.isolatedProc

=

app;

}

}这里的mAm就是ActivityManagerService。Provider与进程创建在ActivityManagerService中,对每一个运行中的ContentProvider都有一个ContentProviderRecord对象与之对应,这个对象记录ContentProvider的详细状态。开发者通过ContentResolver中的insert,delete,update,

query这些API来使用ContentProvider。在ContentResolver的实现中,无论使用这里的哪个接口,ContentResolver都会先通过acquireProvider

这个方法来获取到一个类型为IContentProvider的远程接口。这个远程接口对接了ContentProvider的实现提供方。同一个ContentProvider可能同时被多个模块使用,而调用ContentResolver接口的进程只是ContentProvider的一个客户端而已,真正的ContentProvider提供方是运行自身的进程中的,两个进程的通讯需要通过Binder的远程接口形式来调用。如下图所示:<imgsrc="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方法将其启动。Receiver与进程创建开发者通过Context.sendBroadcast接口来发送广播。ActivityManagerService.broadcastIntent

方法了对应广播发送的处理。广播是一种一对多的消息形式,广播接受者的数量是不确定的。因此发送广播本身可能是一个很耗时的过程(因为要逐个通知)。在ActivityManagerService内部,是通过队列的形式来管理广播的:BroadcastQueue描述了一个广播队列BroadcastRecord描述了一个广播事件在ActivityManagerService中,如果收到了一个发送广播的请求,会先创建一个BroadcastRecord接着将其放入BroadcastQueue中。然后通知队列自己去处理这个广播。然后ActivityManagerService自己就可以继续处理其他请求了。广播队列本身是在另外一个线程处理广播的发送的,这样保证的ActivityManagerService主线程的负载不会太重。在BroadcastQcessNextBroadcast(booleanfromMsg)

方法中真正实现了通知广播事件到接受者的逻辑。在这个方法,如果发现接受者(即BrodcastReceiver)还没有启动,便会通过ActivityManagerService.sta

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论