ActivityThread分析—ActivityThread的main方法是如何被调用的

前言

我们都知道ActivityThread这个类是app程序的入口,本文为了证明这一点,因Launcher亦是一个Activity,且我们之前也对Launcher启动流程做过一定的分析,SO,本文以它为支点,展开对于ActivityThread的学习。

本文的目的只分析到main方法的调用处,而main方法中是如何进行初始化的将另开一篇,另外,有错误请直接指出。

参考:Launcher启动流程

代码分析

frameworks\base\services\java\com\android\server\am\ActivityStack.java#startActivityLocked()

注意这里调用的是11个参数的startActivityLocked方法。


    final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType,
            Uri[] grantedUriPermissions,
            int grantedMode, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, boolean onlyIfNeeded,
            boolean componentSpecified) {

        ......

        return startActivityUncheckedLocked(r, sourceRecord,
                grantedUriPermissions, grantedMode, onlyIfNeeded, true);
    }

frameworks\base\services\java\com\android\server\am\ActivityStack.java#startActivityUncheckedLocked()

这个函数尾部注释6处调用了3个参数的startActivityLocked方法。


    final int startActivityUncheckedLocked(ActivityRecord r,
            ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
            int grantedMode, boolean onlyIfNeeded, boolean doResume) {
        ......

        if (r.packageName != null) {//逻辑1
            // If the activity being launched is the same as the one currently
            // at the top, then we need to check if it should only be launched
            // once.
            ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);//注释1
            if (top != null && r.resultTo == null) {
                if (top.realActivity.equals(r.realActivity)) {
                    if (top.app != null && top.app.thread != null) {
                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
                            logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
                            // For paranoia, make sure we have correctly
                            // resumed the top activity.
                            if (doResume) {
                                resumeTopActivityLocked(null);//注释2
                            }
                            if (onlyIfNeeded) {
                                // We don't need to start a new activity, and
                                // the client said not to do anything if that
                                // is the case, so this is it!
                                return START_RETURN_INTENT_TO_CALLER;
                            }
                            top.deliverNewIntentLocked(callingUid, r.intent);//注释3
                            return START_DELIVERED_TO_TOP;
                        }
                    }
                }
            }
        } else {
            if (r.resultTo != null) {
                sendActivityResultLocked(-1,
                        r.resultTo, r.resultWho, r.requestCode,
                    Activity.RESULT_CANCELED, null);//注释4
            }
            return START_CLASS_NOT_FOUND;
        }

        boolean newTask = false;

        // Should this be considered a new task?
        if (r.resultTo == null && !addingToTask
                && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            // todo: should do better management of integers.
         ......
        } else if (sourceRecord != null) {
            if (!addingToTask &&
                    (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                // In this case, we are adding the activity to an existing
                // task, but the caller has asked to clear that task if the
                // activity is already running.
             ......
            } else if (!addingToTask &&
                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
                // In this case, we are launching an activity in our own task
                // that may already be running somewhere in the history, and
                // we want to shuffle it to the front of the stack if so.
             ......
            }
            // An existing activity is starting this new activity, so we want
            // to keep the new one in the same task as the one that is starting
            // it.
           ......
        } else {
            // This not being started from an existing activity, and not part
            // of a new task...  just put it in the top task, though these days
            // this case should never happen.
          ......
        }

        ......

        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
                intent, r.getUriPermissionsLocked());

        if (newTask) {
            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
        }

        logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);//注释5
        startActivityLocked(r, newTask, doResume);//注释6
        return START_SUCCESS;
    }

frameworks\base\services\java\com\android\server\am\ActivityStack.java#startActivityLocked()

注意这里调用的是3个参数的startActivityLocked方法。并在注释1处调到了resumeTopActivityLocked方法。


    private final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume) {
        ......

        if (!newTask) {
            // If starting in an existing task, find where that is...
            ......
            for (int i = NH-1; i >= 0; i--) {
                ActivityRecord p = (ActivityRecord)mHistory.get(i);
                if (p.finishing) {
                    continue;
                }
                if (p.task == r.task) {
                    // Here it is!  Now, if this is not yet visible to the
                    // user, then just add it without starting; it will
                    // get started when the user navigates back to it.
                    ......
                    break;
                }
                if (p.fullscreen) {
                    startIt = false;
                }
            }
        }

        // Place a new activity at top of stack, so it is next to interact
        // with the user.
        ......

        // If we are not placing the new activity frontmost, we do not want
        // to deliver the onUserLeaving callback to the actual frontmost
        // activity
        ......

        // Slot the activity into the history stack and proceed
        ......
        if (NH > 0) {
            // We want to show the starting preview window if we are
            // switching to a new task, or the next activity's process is
            // not currently running.
              ......
            if (newTask) {
                // Even though this activity is starting fresh, we still need
                // to reset it to make sure we apply affinities to move any
                // existing activities from other tasks in to it.
                // If the caller has requested that the target task be
                // reset, then do so.
                ......
            }
            if (SHOW_APP_STARTING_PREVIEW && doShow) {
                // Figure out if we are transitioning from another activity that is
                // "has the same starting icon" as the next one.  This allows the
                // window manager to keep the previous window it had previously
                // created, if it still had one.
                ActivityRecord prev = mResumedActivity;
                if (prev != null) {
                    // We don't want to reuse the previous starting preview if:
                    // (1) The current activity is in a different task.
                    ......
                    // (2) The current activity is already displayed.
                    ......
                }
                mService.mWindowManager.setAppStartingWindow(
                        r, r.packageName, r.theme, r.nonLocalizedLabel,
                        r.labelRes, r.icon, prev, showStartingIcon);
            }
        } else {
            // If this is the first activity, don't do any fancy animations,
            // because there is nothing for it to animate on top of.
            mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
                    r.info.screenOrientation, r.fullscreen);
        }
        if (VALIDATE_TOKENS) {
            mService.mWindowManager.validateAppTokens(mHistory);
        }

        if (doResume) {
            resumeTopActivityLocked(null);//注释1
        }
    }

frameworks\base\services\java\com\android\server\am\ActivityStack.java#resumeTopActivityLocked()


    final boolean resumeTopActivityLocked(ActivityRecord prev) {
        // Find the first activity that is not finishing.
        ......

        // Remember how we'll process this pause/resume situation, and ensure
        // that the state is reset however we wind up proceeding.
        ......

        if (next == null) {
            // There are no more activities!  Let's just start up the
            // Launcher...
             if (mMainStack) {
                return mService.startHomeActivityLocked();
            }
        }

       ......


        if (next.app != null && next.app.thread != null) {

             ......

        } else {
            // Whoops, need to restart this activity!
            // resume一个新的activity(还未跟进程关联的Activity),
            // 进程可能还没起来。调用startSpecificActivityLocked(),
            // 在这个函数中会寻找目标进程,如果目标进程存在,
            // 那么就直接调用realStartActivityLocked(),
            // 如果目标进程不存在那么就先startProcess;
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                if (SHOW_APP_STARTING_PREVIEW) {
                    mService.mWindowManager.setAppStartingWindow(
                            next, next.packageName, next.theme,
                            next.nonLocalizedLabel,
                            next.labelRes, next.icon, null, true);
                }
                if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
            }
            startSpecificActivityLocked(next, true, true);
        }

        return true;
    }

重点关注方法尾部,它去掉用了startSpecificActivityLocked方法。

frameworks\base\services\java\com\android\server\am\ActivityStack.java#startSpecificActivityLocked

在这个函数中会寻找目标进程,如果目标进程存在,那么就直接调用realStartActivityLocked(),如果目标进程不存在那么就先startProcess。

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

        if (r.launchTime == 0) {
            r.launchTime = SystemClock.uptimeMillis();
            if (mInitialStartTime == 0) {
                mInitialStartTime = r.launchTime;
            }
        } else if (mInitialStartTime == 0) {
            mInitialStartTime = SystemClock.uptimeMillis();
        }

        if (app != null && app.thread != null) {
            try {
                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.
        }

        //如果目标进程不存在那么就先startProcess,Ams的方法
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false);
    }

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java#startProcessLocked(7参)

注意它调用的是7个参数的startProcessLocked方法,然后内部又调用了3个参数的startProcessLocked方法。


    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
        ProcessRecord app = getProcessRecordLocked(processName, info.uid);
        // We don't have to do anything more if:
        // (1) There is an existing application record; and
        // (2) The caller doesn't think it is dead, OR there is no thread
        //     object attached to it so we know it couldn't have crashed; and
        // (3) There is a pid assigned to it, so it is either starting or
        //     already running.
        ......

        startProcessLocked(app, hostingType, hostingNameStr);
        return (app.pid != 0) ? app : null;
    }

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java#startProcessLocked(3参)

在注释1处调用了Process.start方法,并传入了参数”android.app.ActivityThread”,那么我们进入Process.start方法瞧瞧。


    private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {

        ......

        try {
            ......

            int pid = Process.start("android.app.ActivityThread",
                    mSimpleProcessManagement ? app.processName : null, uid, uid,
                    gids, debugFlags, null);//注释1

            BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
            synchronized (bs) {
                if (bs.isOnBattery()) {
                    app.batteryStats.incStartsLocked();
                }
            }

            ......

            StringBuilder buf = mStringBuilder;
            buf.setLength(0);
            buf.append("Start proc ");
            buf.append(app.processName);
            buf.append(" for ");
            buf.append(hostingType);
            if (hostingNameStr != null) {
                buf.append(" ");
                buf.append(hostingNameStr);
            }
            buf.append(": pid=");
            buf.append(pid);
            buf.append(" uid=");
            buf.append(uid);
            buf.append(" gids={");
            if (gids != null) {
                for (int gi=0; gi<gids.length; gi++) {
                    if (gi != 0) buf.append(", ");
                    buf.append(gids[gi]);

                }
            }
            buf.append("}");

            Slog.i(TAG, buf.toString());

            if (pid == 0 || pid == MY_PID) {
                // Processes are being emulated with threads.
                app.pid = MY_PID;
                app.removed = false;
                mStartingProcesses.add(app);
            } else if (pid > 0) {
                app.pid = pid;
                app.removed = false;
                synchronized (mPidsSelfLocked) {
                    this.mPidsSelfLocked.put(pid, app);
                    Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
                    msg.obj = app;
                    mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
                }
            } else {
                app.pid = 0;
                RuntimeException e = new RuntimeException(
                        "Failure starting process " + app.processName
                        + ": returned pid=" + pid);
                Slog.e(TAG, e.getMessage(), e);
            }
        } catch (RuntimeException e) {
            // XXX do better error recovery.
            app.pid = 0;
            Slog.e(TAG, "Failure starting process " + app.processName, e);
        }
    }

frameworks\base\core\java\android\os\Process.java#start()

注释1处直接去调用了invokeMain方法。


    /**
     * Start a new process.
     * 
     * <p>If processes are enabled, a new process is created and the
     * static main() function of a <var>processClass</var> is executed there.
     * The process will continue running after this function returns.
     * 
     * <p>If processes are not enabled, a new thread in the caller's
     * process is created and main() of <var>processClass</var> called there.
     * 
     * <p>The niceName parameter, if not an empty string, is a custom name to
     * give to the process instead of using processClass.  This allows you to
     * make easily identifyable processes even if you are using the same base
     * <var>processClass</var> to start them.
     * 
     * @param processClass The class to use as the process's main entry
     *                     point.
     * @param niceName A more readable name to use for the process.
     * @param uid The user-id under which the process will run.
     * @param gid The group-id under which the process will run.
     * @param gids Additional group-ids associated with the process.
     * @param enableDebugger True if debugging should be enabled for this process.
     * @param zygoteArgs Additional arguments to supply to the zygote process.
     * 
     * @return int If > 0 the pid of the new process; if 0 the process is
     *         being emulated by a thread
     * @throws RuntimeException on fatal start failure
     * 
     * {@hide}
     */
    public static final int start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags,
                                  String[] zygoteArgs){

        if (supportsProcesses()) {
            try {
                return startViaZygote(processClass, niceName, uid, gid, gids,
                        debugFlags, zygoteArgs);
            } catch (ZygoteStartFailedEx ex) {
                Log.e(LOG_TAG,
                        "Starting VM process through Zygote failed");
                throw new RuntimeException(
                        "Starting VM process through Zygote failed", ex);
            }
        } else {
            // Running in single-process mode

            Runnable runnable = new Runnable() {
                        public void run() {
                            //注释1:这里的processClass时机上就是ActivityThread方法
                            Process.invokeStaticMain(processClass);
                        }
            };

            // Thread constructors must not be called with null names (see spec). 
            if (niceName != null) {
                new Thread(runnable, niceName).start();
            } else {
                new Thread(runnable).start();
            }

            return 0;
        }
    }

frameworks\base\core\java\android\os\Process.java#invokeStaticMain()

至此ActivityThread的main方法被执行了。


    private static void invokeStaticMain(String className) {
        Class cl;
        Object args[] = new Object[1];

        args[0] = new String[0];     //this is argv

        try {
            cl = Class.forName(className);
            cl.getMethod("main", new Class[] { String[].class })
                    .invoke(null, args);            
        } catch (Exception ex) {
            // can be: ClassNotFoundException,
            // NoSuchMethodException, SecurityException,
            // IllegalAccessException, IllegalArgumentException
            // InvocationTargetException
            // or uncaught exception from main()

            Log.e(LOG_TAG, "Exception invoking static main on " 
                    + className, ex);

            throw new RuntimeException(ex);
        }
    }

总结

当Zygote启动时,会分裂出system_server并进行不断地ipc轮询,system_server会创建AMS等服务。当你在桌面点击一个app图标时,并且这个app在内存中是无实例的。ams会通知system_server,由system_server通知Zygote去fork出子进程并执行ActivityThread的main方法。main方法的调用是在子进程的主线程中。

猜你喜欢

转载自blog.csdn.net/user11223344abc/article/details/81013641