Android Phone进程启动过程分析

之前解决一个开机搜网慢的问题时,发现由于Phone进程起来以后才会主动连接RILD,因而在一定程度上Phone进程启动的时间会影响网络状态注册的快慢。适当的将Phone进程提前,可以将网络注册时间提前一点,让状态栏中信号显示的时间提前。那么,Android中作为系统的核心进程之一,Phone进程是如何启动的了?

本文参考代码为Android NN7.0, RIL运行机制请参考: Android RIL概述

Telephony最开始创建的是PhoneFactory对象,直接搜索源码,可以看到在PhoneGlobals.java创建时,会调用PhoneFactory对Telephony进行初始化操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

/**
* Global state for the telephony subsystem when running in the primary
* phone process.
*/
public class PhoneGlobals extends ContextWrapper {

public void onCreate() {
Log.v(LOG_TAG, "!@Boot_SVC : PhoneApp OnCrate");
// CallManager为空
if (mCM == null) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// 创建CallManager实例
mCM = CallManager.getInstance();
for (Phone phone : PhoneFactory.getPhones()) {
mCM.registerPhone(phone);
}
....
}

}

那么,PhoneGlobals又是在哪里创建的了?再次搜索代码,可以看到在同一文件目录下,有一个PhoneApp.java文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@Override
public void onCreate() {
Log.d("PhoneApp", "onCreate");

if (UserHandle.myUserId() == 0) {
// 创建PhoneGlobals实例
mPhoneGlobals = new PhoneGlobals(this);
mPhoneGlobals.onCreate();

mTelephonyGlobals = new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
} else {
Log.d("PhoneApp", "Phone app is created as userid not 0, there's no PhoneApp() Instance");
}
....
}

那么,PhoneApp这个类又是什么时候创建的?我们知道,每一个Android应用都有一个Application与之对应,它是在应用启动过程中创建的,但是在这里搜索所有的源码,也无法看到PhoneApp创建的地方。联想到应用的启动过程,APP的启动的入口是ActivityThread,那么对于任何PhoneApp这样的系统应用来说,启动的入口也应该是ActivityThread。不妨继续看看代码。

打开Phone进程所在的源码路径: /android/applications/sources/services/Telephony/,查看应用对应的AndroidManefest.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.phone"
android:versionCode="1"
android:versionName="1.0.0"
coreApp="true"
android:sharedUserId="android.uid.phone"
android:sharedUserLabel="@string/phoneAppLabel" >
.....
<application android:name="PhoneApp"
android:persistent="true"
android:hardwareAccelerated="true"
android:label="@string/phoneAppLabel"
android:icon="@mipmap/ic_launcher_phone"
android:allowBackup="false"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
....
</application>
</manifest>

application标签下面,可以看到android:persistent="true"这个属性值,看一看官方的文档怎么解释的:

android:persistent

Whether or not the application should remain running at all times — “true” if it should, and “false” if not. The default value is “false”. Applications should not normally set this flag; persistence mode is intended only for certain system applications.

由此可见,Phone应用是系统常驻进程,一旦起来后就会一直运行,不会被杀死(除非Phone进程自己发生了的运行时错误而崩溃)。对于这类常驻进程,ActivityManagerService(以下简称AMS)会在初始化完成后,主动启动。在SystemServer初始化完系统的核心服务后,会调用AMS的systemReady(Runnable r)函数。

ActivityManagerService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

public void systemReady(final Runnable goingCallback) {

synchronized (this) {

// Only start up encryption-aware persistent apps; once user is
// unlocked we'll come back around and start unaware apps
// 正是在这里,phone进程被创建
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);

// Start up initial activity.
mBooting = true;
// Enable home activity for system user, so that the system can always boot
if (UserManager.isSplitSystemUser()) {
ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
try {
AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
startHomeActivityLocked(currentUserId, "systemReady");

}

}

启动所有PackageManager.MATCH_DIRECT_BOOT_AWARE标志为true的应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

private void startPersistentApps(int matchFlags) {

synchronized (this) {
try {
//获取系统所有常驻应用程序信息
final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName)) {
//加载应用
addAppLocked(app, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
}
}
}

//添加应用程序进程到LRU列表中,并创建进程
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(info.processName, info.uid, true);
} else {
app = null;
}

// 没有进程记录,因此创建一个进程记录
if (app == null) {
app = newProcessRecordLocked(info, null, isolated, 0);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
....

if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
app.persistent = true;
app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
}

// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
// 进程入口为ActivityThread
if (entryPoint == null) entryPoint = "android.app.ActivityThread";

//启动应用进程
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application", app.processName, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}

return app;
}

准备创建应用进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {

Process.ProcessStartResult startResult = null;
....

startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, aasaSeInfo != null ? new String(aasaSeInfo) : app.info.seinfo, //AASA--4 : changed orginal : only "app.info.seinfo"
app.info.category, app.info.accessInfo,
requiredAbi, instructionSet,
app.info.dataDir, mountKnoxPoint, entryPointArgs);

....
}

Process.java

调用Process.start(),创建一个新的进程, Telephony服务以及RIL相关代码都运行在此进程中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

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,
int category,
int accessInfo,
String abi,
String instructionSet,
String appDataDir,
boolean mountKnoxPoint,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, category, accessInfo,
abi, instructionSet, appDataDir, mountKnoxPoint, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}

发送消息到zygote服务进程的socket端口,请求创建新的进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
int category,
int accessInfo,
String abi,
String instructionSet,
String appDataDir,
boolean mountKnoxPoint,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();

// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
....
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
....
argsForZygote.add(processClass);

if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}

//发送消息到zygote的socket端口,请求创建新的进程
if (Zygote.isEnhancedZygoteASLREnabled) {
....
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
// End of isEnhancedZygoteASLREnabled case
} else {
// Original case
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
}

ZygoteConnection.java

zygote进程接收到AMS的请求后,由ZygoteConnection负责处理请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;

try {
// 从socket中读取参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}

if (args == null) {
// EOF reached.
closeSocket();
return true;
}

int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
...
try {
parsedArgs = new Arguments(args);
//Zygote调用本地方法创建进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.category, parsedArgs.accessInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir, parsedArgs.mountKnoxPoint);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}

try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}

ZygoteInit.java

至此phone进程已经创建完成了,但实际上PhoneApp的代码还没有加载。继续看,在启动的进程里,调用ZygoteInit.zygoteInit来加载phoneApp的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws Zygote.MethodAndArgsCaller {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
* objects still need to be closed properly.
*/
closeSocket();
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);

for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}

if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}

// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 这里没有指定invokewith参数
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
// 这里remaingArgs的第一参数是android.app.ActivityThread, 就是之前的entrypoint
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}

RuntimeInit.java

通过RuntimeInit来加载phone APP的代码, zygoteInit函数主要做三件事:

  • 做一些通用的初始化,比如设置虚拟机中线程的exception handler;设置默认时区;
  • 完成VM本地的初始化操作;
  • 加载APP代码,也就是调用ActivityThread.main函数来加载整个phone APP;
1
2
3
4
5
6
7
8
9
10
11
12
13

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();

commonInit();
nativeZygoteInit();
// 初始化应用代码
applicationInit(targetSdkVersion, argv, classLoader);
}

函数applicationInit通过方法invokeStaticMain反射调用ActivityThread.main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);

// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

invokeStaticMain通过抛出一个MethodAndArgsCaller的异常,被ZygoteInit.main方法捕获后,调用MethodAndArgsCaller.run,至此就调用了ActivityThread.main方法了,还真是有点绕。

| 有关zygote进程可以参考http://sniffer.site/2017/05/27/Zygote%E8%BF%9B%E7%A8%8B%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B%E5%88%86%E6%9E%90/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
Class<?> cl;

try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}

Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}

int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}

/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
throw new Zygote.MethodAndArgsCaller(m, argv);
}

MethodAndArgsCaller异常的作用是清除父进程中的一些调用堆栈,这样子进程就从ActivityThread.main开始了自己的堆栈调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;

/** argument array */
private final String[] mArgs;

public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}

public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}

ActivityThread.java

到这里,ActivityThread.main会启动一个主线程,接着创建一个ActivityThread用于Phone APP与AMS进行交互。最重要的是,接着在thread.attach(false);这个函数里,ActivityThread会去创建Phone进程入口类PhoneApp。后续就是Phone整个框架代码的加载与初始化了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();

// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);

Environment.initForCurrentUser();

// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());

// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);

Process.setArgV0("<pre-initialized>");
// 启动主线程Looper
Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();
thread.attach(false);

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}

// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}

这样Phone进程就创建启动完成了。整个流程看下来,研究Android系统,源码是王道,但要深入理解系统背后的设计,还是需要从把基本的概念梳理清楚,才能更好的理解系统背后设计的逻辑。