Android Launcher启动应用程序流程源码解析

Posted 一口仨馍

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Launcher启动应用程序流程源码解析相关的知识,希望对你有一定的参考价值。

带着问题看源码

  1. 点击桌面Launcher图标后做了哪些工作?
  2. 应用程序什么时候被创建的?
  3. Application和MainActivity的onCreate()方法什么时候被调用的?

概述

android系统中,启动四大组件中的任何一个都可以启动应用程序。但绝大部分时候我们是通过点击Launcher图标启动应用程序。本文依据Android6.0源码,从点击Launcher图标,直至解析到MainActivity#OnCreate()被调用。

Launcher简析

Launcher也是个应用程序,不过是个特殊的应用。俗称“桌面”。通过PackageManagerService查询所有已安装的应用程序,并保存相应的图标、应用名称、包名和第一个要启动的类名等。

源码位置:frameworks/base/core/java/android/app/LauncherActivity.java

LauncherActivity#onListItemClick()

public abstract class LauncherActivity extends ListActivity 
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) 
        Intent intent = intentForPosition(position);
        startActivity(intent);
    

可以看到LauncherActivity继承自ListActivity,而ListActivity继承自Activity。在LauncherActivity#onListItemClick()方法中首先通过intentForPosition()获取了一个Intent,然后调用startActivity(intent)启动一个Activity。由于ListActivity并没有重写Activity#startActivity()方法,所以这里会直接调用Activity#startActivity()。在此之前先看下intentForPosition()是怎样构造Intent

    protected Intent intentForPosition(int position) 
        ActivityAdapter adapter = (ActivityAdapter) mAdapter;
        return adapter.intentForPosition(position);
    

    private class ActivityAdapter extends BaseAdapter implements Filterable 
        public Intent intentForPosition(int position) 
            if (mActivitiesList == null) 
                return null;
            
            Intent intent = new Intent(mIntent);
            ListItem item = mActivitiesList.get(position);
            intent.setClassName(item.packageName, item.className);
            if (item.extras != null) 
                intent.putExtras(item.extras);
            
            return intent;
        
    

Intent中只是指定了即将启动的Activity

源码位置:frameworks/base/core/java/android/app/Activity.java

Activity#startActivity()

    public void startActivity(Intent intent) 
        this.startActivity(intent, null);
    

    public void startActivity(Intent intent, @Nullable Bundle options) 
        if (options != null) 
            startActivityForResult(intent, -1, options);
         else 
            startActivityForResult(intent, -1);
        
    

    /** @param requestCode If >= 0, this code will be returned inonActivityResult() when the activity exits. */
    public void startActivityForResult(Intent intent, int requestCode) 
        startActivityForResult(intent, requestCode, null);
    

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) 
            Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
           ...
        
    

在调用的过程中可以观察到,无论调用StartActivity()还是startActivityForResult(),最终调用的都是startActivityForResult()。而且注释说明只有requestCode >= 0onActivityResult()才会被调用。经过一系列的调用,最终调用了Instrumentation#execStartActivity()。跟进。

源码位置:frameworks/base/core/java/android/app/Instrumentation.java

Instrumentation#execStartActivity()

    public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target, 
        Intent intent, int requestCode, Bundle options) 
            ...
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            ...
    

这里ActivityManagerNative.getDefault()涉及到Binder进程间通信机制。下面进行一个简短的介绍,这不是本文的重点。了解过同学的可以略过下面这段Binder简析,不想了解的也可以直接理解为返回的是ActivityManagerService(以下简称AMS)。实际调用的是AMS#startActivity()

AMS中Binder机制简析

ActivityManagerNative.getDefault()

    static public IActivityManager getDefault() 
        return gDefault.get();
    

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() 
        protected IActivityManager create() 
            IBinder b = ServiceManager.getService("activity");
            IActivityManager am = asInterface(b);
            return am;
        
    ;

    static public IActivityManager asInterface(IBinder obj) 
        if (obj == null) 
            return null;
        
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) 
            return in;
        

        return new ActivityManagerProxy(obj);
    

本例中AMS作为服务器端,ActivityManagerNative作为客户端。在getDefault()方法中通过调用asInterface()方法中的 new ActivityManagerProxy(obj)返回了IActivityManager的子类对象AMS。从哪里可以看出来呢?这个就比较难找了,不过细心点还是可以发现写蛛丝马迹。重点在于IBinder b = ServiceManager.getService("activity"),这里的参数是“activity”。在上篇博文SystemServer启动流程源码解析中,分析SystemServer#startBootstrapServices()方法启动AMS之后调用mActivityManagerService.setSystemProcess(),跟进。

源码位置:frameworks/base/services/java/com/android/server/SystemServer.java

SystemServer#startBootstrapServices()

    private void startBootstrapServices() 
        Installer installer = mSystemServiceManager.startService(Installer.class);

        // Activity manager runs the show.
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        // Set up the Application instance for the system process and get started.
        mActivityManagerService.setSystemProcess();
    

    public void setSystemProcess() 
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
    

静态常量Context.ACTIVITY_SERVICE = "activity"。到这里就对上了。先addService("activity"),然后getService("activity")。其实在add和get的时候,又是一次通过Binder进行进程间通信的过程。这次和本文关系不大,这里不再拓展。下面回到AMS#startActivity()

调用过程解析

前方高能,可能会导致身体感到严重不适。请做好心理准备!

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ActivityManagerService#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 options) 
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    

    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) 
        // 验证CallingUid是否合法
        enforceNotIsolatedCaller("startActivity");
        // 检查限权
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    

简单验证后开始调用StackSupervisor#startActivityMayWait(),跟进。
源码位置:frameworks/base/services/core/java/com/android/server/am/StackSupervisor.java

StackSupervisor#startActivityMayWait()、StackSupervisor#resolveActivity()

    final int startActivityMayWait(IApplicationThread caller, int callingUid,
                                   String callingPackage, Intent intent, String resolvedType,
                                   IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                                   IBinder resultTo, String resultWho, int requestCode, int startFlags,
                                   ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
                                   Bundle options, boolean ignoreTargetSecurity, int userId,
                                   IActivityContainer iContainer, TaskRecord inTask) 
          ...
         // 解析intent信息                         
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
         // 验证pid uid(省略)
         ...
        int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                voiceSession, voiceInteractor, resultTo, resultWho,
                requestCode, callingPid, callingUid, callingPackage,
                realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                componentSpecified, null, container, inTask);

        return res;                          
    

    ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
                                 ProfilerInfo profilerInfo, int userId) 
        // Collect information about the target of the Intent.
        ActivityInfo aInfo;
        try 
            ResolveInfo rInfo = AppGlobals.getPackageManager().resolveIntent(
                            intent, resolvedType,
                            PackageManager.MATCH_DEFAULT_ONLY 
                            | ActivityManagerService.STOCK_PM_FLAGS, userId);
            aInfo = rInfo != null ? rInfo.activityInfo : null;
         catch (RemoteException e) 
            aInfo = null;
        

        if (aInfo != null) 
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            ...
        
        return aInfo;
    

在调用resolveActivity()之后会读取配置文件中包名和要启动Activity完整的路径名,并分别赋值给aInfo.applicationInfo.packageName和aInfo.name。跟进。

StackSupervisor#startActivityLocked()

    final int startActivityLocked(IApplicationThread caller,
                                  Intent intent, String resolvedType, ActivityInfo aInfo,
                                  IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                                  IBinder resultTo, String resultWho, int requestCode,
                                  int callingPid, int callingUid, String callingPackage,
                                  int realCallingPid, int realCallingUid, int startFlags, Bundle options,
                                  boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
                                  ActivityContainer container, TaskRecord inTask) 
        ProcessRecord callerApp = null;
        if (caller != null) 
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) 
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
             else 
                err = ActivityManager.START_PERMISSION_DENIED;
            
        
        ...
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);
        // 检查intent中的flag信息
        ...
        // 检查限权
        ...
        ...
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);
        return err;

    

这个方法近300行代码,我们只看关键的部分就好了。首先获取调用者的pid、uid等信息,然后保存在callerApp中。目标Activity的信息保存在 r 中。跟进。

StackSupervisor#startActivityUncheckedLocked()

    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
        boolean doResume, Bundle options, TaskRecord inTask) 
        ...
        int launchFlags = intent.getFlags();
        // 对intent的flag各种判断
        ...
        ActivityRecord notTop = (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
        ...
                ActivityStack sourceStack;
        if (sourceRecord != null) 
            if (sourceRecord.finishing) 
                if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) 
                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
                    newTaskInfo = sourceRecord.info;
                    newTaskIntent = sourceRecord.task.intent;
                
                sourceRecord = null;
                sourceStack = null;
             else 
                sourceStack = sourceRecord.task.stack;
            
         else 
            sourceStack = null;
        
        ...
        if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                || launchSingleInstance || launchSingleTask) 
            if (inTask == null && r.resultTo == null) 
                // See if there is a task to bring to the front.  If this is
                // a SINGLE_INSTANCE activity, there can be one and only one
                // instance of it in the history, and it is always in its own
                // unique task, so we do a special search.
                ActivityRecord intentActivity = !launchSingleInstance ?
                        findTaskLocked(r) : findActivityLocked(intent, r.info);
        ...
        
        ...
        // Should this be considered a new task?
        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) 
            newTask = true;
            targetStack = computeStackFocus(r, newTask);
            targetStack.moveToFront("startingNewTask");

            if (reuseTask == null) 
                // 设任务栈
                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                        newTaskInfo != null ? newTaskInfo : r.info,
                        newTaskIntent != null ? newTaskIntent : intent,
                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                        taskToAffiliate);
             
            ...
        
        ...
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
        return ActivityManager.START_SUCCESS;
    

这个方法600+行,而且好多逻辑判断,看的几近崩溃。不过还好,关键的代码已经被过滤出来了~首先确定几个变量。前面都没有设置过intentflag,所以launchFlags = 0x00000000,但是在执行launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK之后。launchFlags = Intent.FLAG_ACTIVITY_NEW_TASKnotTop = null。由于没有要接收返回信息的Activity,所以r.resultTo == null。由于没有设置Activity的启动模式为SingleInstance,所以launchSingleInstance = false,即会执行findTaskLocked(r)。这个方法的作用是查找历史所有stack中有没有目标Activity,很显然返回值为null,所以下面很大一段判断逻辑都不会执行。大约200行,爽~。既然没有相应的任务栈,肯定要创建的。在上文中创建任务栈对应的方法为targetStack.createTaskRecord()。最后执行ActivityStack#startActivityLocked(),跟进。

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

ActivityStack#startActivityLocked()

    final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) 
        ...
        // newTask = true
        if(!newTask)
            ...
        
        task = r.task;
        // 将ActivityRecord置于栈顶
        task.addActivityToTop(r);
        // 将任务栈置于前台
        task.setFrontOfTask();
        ...
        if (doResume) 
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        
    

跟进。

源码位置:frameworks/base/services/core/java/com/android/server/am/StackSupervisor.java

StackSupervisor#resumeTopActivitiesLocked()

    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
                                      Bundle targetOptions) 
        if (targetStack == null) 
            targetStack = mFocusedStack;
        
        // Do targetStack first.
        boolean result = false;
        if (isFrontStack(targetStack)) 
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        

        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) 
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) 
                final ActivityStack stack = stacks.get(stackNdx);
                if (stack == targetStack) 
                    // Already started above.
                    continue;
                
                if (isFrontStack(stack)) 
                    stack.resumeTopActivityLocked(null);
                
            
        
        return result;
    

这个方法的作用是将Launcher应用程序所在的任务栈执行resumeTopActivityLocked()方法。跟进。

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

ActivityStack#resumeTopActivityLocked()

    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) 
        if (mStackSupervisor.inResumeTopActivity) 
            // Don't even start recursing.
            return false;
        

        boolean result = false;
        try 
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) 
                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
                mService.updateSleepIfNeededLocked();
            
            result = resumeTopActivityInnerLocked(prev, options);
         finally 
            mStackSupervisor.inResumeTopActivity = false;
        
        return result;
    

跟进。

ActivityStack#resumeTopActivityInnerLocked()

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) 
        ...
        // If the top activity is the resumed one, nothing to do.
        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                    mStackSupervisor.allResumedActivitiesComplete()) 
            ...
            return false;
        
        ...
        if (mResumedActivity != null) 
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        
        ...
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
        ...
    

这个方法的主要作用是将mResumedActivity暂停(Launcher任务栈的TopActivity),即进入onPause状态。之后启动指定的AttivityRecored,即target AttivityRecored

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

ActivityStackSupervisor#startSpecificActivityLocked()

    void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) 
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);

        if (app != null && app.thread != null) 
            try 
                if ((r.info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) 
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
             catch (RemoteException e) 
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    

由于没有在指定Applicationprocess属性,所以这里的app = null

详见ActivityStackSupervisor#getProcessRecordLocked()

    final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) 
        if (uid == Process.SYSTEM_UID) 
            // The system gets to run in any process.  If there are multiple
            // processes with the same uid, just pick the first (this
            // should never happen).
            SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
            if (procs == null) return null;
            ...
        
        ...
    

跟进。

源码位置:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

ActivityManagerService#startProcessLocked()

    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) 
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    

跟进。

ActivityManagerService#startProcessLocked()

    final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) 
        // isolated = false
        if (!isolated) 
            // 没有指定application的process,所以app = null
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            ...
        
        ...
        if (app == null) 
            checkTime(startTime, "startProcess: creating new process record");
            // 创建ProcessRecord
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            ...
            checkTime(startTime, "startProcess: done creating new process record");
        
    
        ...
        checkTime(startTime, "startProcess: stepping in to startProcess");
        // hostingNameStr="activity" 后面仨参数都是null
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        checkTime(startTime, "startProcess: done starting proc!");

终于看见Process的身影了,亲人呐!!!

ActivityManagerService#startProcessLocked()

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) 
            ...
        try 
            int uid = app.uid;
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            // isolated = false
            if (!app.isolated) 
                int[] permGids = null;
                try 
                    checkTime(startTime, "startProcess: getting gids from package manager");
                    final IPackageManager pm = AppGlobals.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
                    MountServiceInternal mountServiceInternal = LocalServices.getService(
                            MountServiceInternal.class);
                    mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
                            app.info.packageName);
                 catch (RemoteException e) 
                    throw e.rethrowAsRuntimeException();
                

                /*
                 * Add shared application and profile GIDs so applications can share some
                 * resources like shared libraries and access user-wide resources
                 */
                if (ArrayUtils.isEmpty(permGids)) 
                    gids = new int[2];
                 else 
                    gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
                
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            
            ...
            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
            if (requiredAbi == null) 
                requiredAbi = Build.SUPPORTED_ABIS[0];
            

            String instructionSet = null;
            if (app.info.primaryCpuAbi != null) 
                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
            

            app.gids = gids;
            app.requiredAbi = requiredAbi;
            app.instructionSet = instructionSet;

            checkTime(startTime, "startProcess: asking zygote to start proc");
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");
            ...
        
        ...
    

这个方法太重要了,所以展示的代码稍微多一些。首先确定几个参数值。hostingType = activity、后面的三个参数abiOverrideentryPointentryPointArgs均等于nullapp.isolated = false。首先创建了gids[]这个参数,然后在前两项插入AppGidUserGid,然后构造了requiredAbiinstructionSet等参数,之后调用Process#start()来创建新进程。Process#start()。现在是凌晨两点,如果你像我一样已经写了5个小时,一定会发现这方法名字是多么的让人陶醉~

抽只烟冷静下~

跟进。

源码位置:frameworks/base/core/java/android/os/Process.java

Process#start()

    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);
        
    

这是只是调用startViaZygote()进一步处理。跟进。

Process#startViaZygote()

    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,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  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);
            ...
                        // --setgroups is a comma-separated list
            if (gids != null && gids.length > 0) 
                StringBuilder sb = new StringBuilder();
                sb.append("--setgroups=");

                int sz = gids.length;
                for (int i = 0; i < sz; i++) 
                    if (i != 0) 
                        sb.append(',');
                    
                    sb.append(gids[i]);
                

                argsForZygote.add(sb.toString());
            

            if (niceName != null) 
                argsForZygote.add("--nice-name=" + niceName);
            

            if (seInfo != null) 
                argsForZygote.add("--seinfo=" + seInfo);
            

            if (instructionSet != null) 
                argsForZygote.add("--instruction-set=" + instructionSet);
            

            if (appDataDir != null) 
                argsForZygote.add("--app-data-dir=" + appDataDir);
            

            argsForZygote.add(processClass);

            if (extraArgs != null) 
                for (String arg : extraArgs) 
                    argsForZygote.add(arg);
                
            
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        
    

可以看到,这里前面一大段都在构造参数argsForZygoteuid啦、gid啦、-nice-name啦,这里需要注意processClass = android.app.ActivityThread,后文会用到。参数构造完成之后,接下来看下openZygoteSocketIfNeeded()这个方法。

Process#openZygoteSocketIfNeeded()

    /**
     * Tries to open socket to Zygote process if not already open. If
     * already open, does nothing.  May block and retry.
     */
    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx 
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) 
            try 
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
             catch (IOException ioe) 
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            
        

        if (primaryZygoteState.matches(abi)) 
            return primaryZygoteState;
        

        // The primary zygote didn't match. Try the secondary.
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) 
            try 
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
             catch (IOException ioe) 
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            
        

        if (secondaryZygoteState.matches(abi)) 
            return secondaryZygoteState;
        

        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    

罕见的我把注释写上了,因为注释说的比我清楚~接下来跟进zygoteSendArgsAndGetResult()方法。

Process#zygoteSendArgsAndGetResult()

    /**
     * Sends an argument list to the zygote process, which starts a new child
     * and returns the child's pid. Please note: the present implementation
     * replaces newlines in the argument list with spaces.
     *
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */
    private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx 
        try 
            /**
             * See com.android.internal.os.ZygoteInit.readArgumentList()
             * Presently the wire format to the zygote process is:
             * a) a count of arguments (argc, in essence)
             * b) a number of newline-separated argument strings equal to count
             *
             * After the zygote process reads these it will write the pid of
             * the child or -1 on failure, followed by boolean to
             * indicate whether a wrapper process was used.
             */
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            int sz = args.size();
            for (int i = 0; i < sz; i++) 
                String arg = args.get(i);
                if (arg.indexOf('\\n') >= 0) 
                    throw new ZygoteStartFailedEx(
                            "embedded newlines not allowed");
                
                writer.write(arg);
                writer.newLine();
            

            writer.flush();

            // Should there be a timeout on this?
            ProcessStartResult result = new ProcessStartResult();
            result.pid = inputStream.readInt();
            if (result.pid < 0) 
                throw new ZygoteStartFailedEx("fork() failed");
            
            result.usingWrapper = inputStream.readBoolean();
            return result;
         catch (IOException ex) 
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        
    

注释也说的很清楚,给Zygote发送一个argument list。通知Zygote进程启动一个子进程。再接下来就该和Zygote进程打交道了。

太晚了,关键明天还要上班。明天再细致分析这部分,古耐~

大哥大Zygote

在另一篇博文 Android Zygote启动流程源码解析中说到:在Zygote#main()中先注册了一个serverSocket,在启动了SystemServer进程之后,一直监听这个serverSocket,准备启动新的应用进程。大概过程如下:

源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

ZygoteInit#main()

public static void main(String argv[]) 
    // 注册socket
    registerZygoteSocket(socketName);
    ...
    if (startSystemServer) 
        // 启动SystemServer进程
        startSystemServer(abiList, socketName);
    
    // 监听socket,启动新的应用进程。--后文会讲
    runSelectLoop(abiList);
    closeServerSocket();
    ...

跟进runSelectLoop(abiList)

ZygoteInit#runSelectLoop()

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller 
        while (true) 
            int index;
            ...
            if (index < 0) 
                throw new RuntimeException("Error in select()");
             else if (index == 0) 
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDescriptor());
             else 
                boolean done;
                done = peers.get(index).runOnce();

                if (done) 
                    peers.remove(index);
                    fds.remove(index);
                
            
           
    

    private static ZygoteConnection acceptCommandPeer(String abiList) 
        try 
            return new ZygoteConnection(sServerSocket.accept(), abiList);
         catch (IOException ex) 
            ...
        
    

这个方法的主要作用是通过acceptCommandPeer()方法接收客户端发送的Socket消息。之后执行ZygoteConnection#runOnce()方法。跟进。

源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

ZygoteConnection#runOnce()

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller 
        ...
        checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize");
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize");
        ...
        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 
               ...
            
            ...
    

省略的一大段代码都在构造参数,之后根据参数调用Zygote.forkAndSpecialize()方法fork出应用程序进程,到这里,应用进程已经被创建了。因为是子进程pid = 0,所以之后会调用handleChildProc()方法进一步处理。跟进。

ZygoteConnection#handleChildProc()

    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller 
        closeSocket();
        ZygoteInit.closeServerSocket();
        ...
        ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
        ...
       

上述代码先关闭从Zygote进程继承来的ServerSocket,然后调用ZygoteInit.invokeStaticMain()。接下来的流程和启动System进程流程差不多,这里快速的过一遍。不熟悉这部分的同学可以参考这篇博客

源码位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

ZygoteInit#invokeStaticMain()

    static void invokeStaticMain(ClassLoader loader, String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller 
        Class<?> cl;
        try 
            cl = loader.loadClass(className);
         catch (ClassNotFoundException ex) 
            throw new RuntimeException(
                    "Missing class when invoking static main " + className, ex);
        
        Method m;
        m = cl.getMethod("main", new Class[]  String[].class );
        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) 
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    

意料之中的装载类文件、意料之中的反射、意料之中的验证修饰符、意料之中的抛出个异常,甚至意料之中的在Zygote#main()中捕获。看过Zygote启动流程源码解析的读着肯定和我有一样的感觉。接下来就该捕获异常,然后反射ActivityThread的静态方法main()。直接贴代码了,so boring…

ZygoteInit#main()

    public static void main(String argv[]) 
        try 
            ...
            runSelectLoop(abiList);
         catch (MethodAndArgsCaller caller) 
            caller.run();
        

        // ZygoteInit&MethodAndArgsCaller#run()
        public void run() 
            以上是关于Android Launcher启动应用程序流程源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Android—launcher 启动流程

Android Launcher启动应用程序流程源码解析

从launcher程序启动App流程分析

Android 源码分析 Launcher 启动

Android 中应用程序Activity的冷启动流程

Android系统启动流程分析