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 Phone进程启动过程详解

android framework的opt/telephony是啥进程

Android 进阶——系统启动之核心SystemServer进程启动详解

Android 进阶——系统启动之核心SystemServer进程启动详解

Android4.0(Phone)拨号启动过程分析

Android 系统服务管家servicemanager启动过程详解