Android Phone进程启动过程详解

枕上从妨一夜睡,灯前读尽十年诗。这篇文章主要讲述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" ); }

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

    推荐阅读