Android Phone进程启动过程详解
Posted Jason_Wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Phone进程启动过程详解相关的知识,希望对你有一定的参考价值。
之前解决一个开机搜网慢的问题时,发现由于Phone进程起来以后才会主动连接RILD,因而在一定程度上Phone进程启动的时间会影响网络状态注册的快慢。适当的将Phone进程提前,可以将网络注册时间提前一点,让状态栏中信号显示的时间提前。那么,android中作为系统的核心进程之一,Phone进程是如何启动的了?
本文参考代码为Android NN7.0, RIL运行机制请参考: Android RIL概述
Telephony最开始创建的是PhoneFactory
对象,直接搜索源码,可以看到在PhoneGlobals.java
创建时,会调用PhoneFactory
对Telephony进行初始化操作:
/**
* 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
文件:
@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
文件:
<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
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
的应用:
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;
准备创建应用进程:
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相关代码都运行在此进程中:
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端口,请求创建新的进程:
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
负责处理请求:
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的代码:
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;
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
:
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/
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
开始了自己的堆栈调用。
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整个框架代码的加载与初始化了。
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系统,源码是王道,但要深入理解系统背后的设计,还是需要从把基本的概念梳理清楚,才能更好的理解系统背后设计的逻辑。
以上是关于Android Phone进程启动过程详解的主要内容,如果未能解决你的问题,请参考以下文章
Android 进阶——系统启动之核心SystemServer进程启动详解
Android 进阶——系统启动之核心SystemServer进程启动详解