博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《深入理解Android2》读书笔记(五)
阅读量:5232 次
发布时间:2019-06-14

本文共 39150 字,大约阅读时间需要 130 分钟。

接上篇

startActivity

Am

void run() throws RemoteException {    try {        printMessageForState();        mAm.setActivityController(this);        mState = STATE_NORMAL;        InputStreamReader converter = new InputStreamReader(System.in);        BufferedReader in = new BufferedReader(converter);        String line;        while ((line = in.readLine()) != null) {            boolean addNewline = true;            if (line.length() <= 0) {                addNewline = false;            } else if ("q".equals(line) || "quit".equals(line)) {                resumeController(RESULT_DEFAULT);                break;            } else if (mState == STATE_CRASHED) {                if ("c".equals(line) || "continue".equals(line)) {                    resumeController(RESULT_CRASH_DIALOG);                } else if ("k".equals(line) || "kill".equals(line)) {                    resumeController(RESULT_CRASH_KILL);                } else {                    System.out.println("Invalid command: " + line);                }            } else if (mState == STATE_ANR) {                if ("c".equals(line) || "continue".equals(line)) {                    resumeController(RESULT_ANR_DIALOG);                } else if ("k".equals(line) || "kill".equals(line)) {                    resumeController(RESULT_ANR_KILL);                } else if ("w".equals(line) || "wait".equals(line)) {                    resumeController(RESULT_ANR_WAIT);                } else {                    System.out.println("Invalid command: " + line);                }            } else if (mState == STATE_EARLY_ANR) {                if ("c".equals(line) || "continue".equals(line)) {                    resumeController(RESULT_EARLY_ANR_CONTINUE);                } else if ("k".equals(line) || "kill".equals(line)) {                    resumeController(RESULT_EARLY_ANR_KILL);                } else {                    System.out.println("Invalid command: " + line);                }            } else {                System.out.println("Invalid command: " + line);            }            synchronized (this) {                if (addNewline) {                    System.out.println("");                }                printMessageForState();            }        }    } catch (IOException e) {        e.printStackTrace();    } finally {        mAm.setActivityController(null);    }}
private void runStart() throws Exception {    Intent intent = makeIntent(UserHandle.USER_CURRENT);    if (mUserId == UserHandle.USER_ALL) {        System.err.println("Error: Can't start service with user 'all'");        return;    }    String mimeType = intent.getType();    if (mimeType == null && intent.getData() != null            && "content".equals(intent.getData().getScheme())) {        mimeType = mAm.getProviderMimeType(intent.getData(), mUserId);    }    do {        if (mStopOption) {            String packageName;            if (intent.getComponent() != null) {                packageName = intent.getComponent().getPackageName();            } else {                IPackageManager pm = IPackageManager.Stub.asInterface(                        ServiceManager.getService("package"));                if (pm == null) {                    System.err.println("Error: Package manager not running; aborting");                    return;                }                List
activities = pm.queryIntentActivities(intent, mimeType, 0, mUserId); if (activities == null || activities.size() <= 0) { System.err.println("Error: Intent does not match any activities: " + intent); return; } else if (activities.size() > 1) { System.err.println("Error: Intent matches multiple activities; can't stop: " + intent); return; } packageName = activities.get(0).activityInfo.packageName; } System.out.println("Stopping: " + packageName); mAm.forceStopPackage(packageName, mUserId); Thread.sleep(250); } System.out.println("Starting: " + intent); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ParcelFileDescriptor fd = null; ProfilerInfo profilerInfo = null; if (mProfileFile != null) { try { fd = openForSystemServer( new File(mProfileFile), ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE | ParcelFileDescriptor.MODE_READ_WRITE); } catch (FileNotFoundException e) { System.err.println("Error: Unable to open file: " + mProfileFile); System.err.println("Consider using a file under /data/local/tmp/"); return; } profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); } IActivityManager.WaitResult result = null; int res; final long startTime = SystemClock.uptimeMillis(); if (mWaitOption) { result = mAm.startActivityAndWait(null, null, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, null, mUserId); res = result.result; } else { res = mAm.startActivityAsUser(null, null, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, null, mUserId); } final long endTime = SystemClock.uptimeMillis(); PrintStream out = mWaitOption ? System.out : System.err; boolean launched = false; switch (res) { case ActivityManager.START_SUCCESS: launched = true; break; case ActivityManager.START_SWITCHES_CANCELED: launched = true; out.println( "Warning: Activity not started because the " + " current activity is being kept for the user."); break; case ActivityManager.START_DELIVERED_TO_TOP: launched = true; out.println( "Warning: Activity not started, intent has " + "been delivered to currently running " + "top-most instance."); break; case ActivityManager.START_RETURN_INTENT_TO_CALLER: launched = true; out.println( "Warning: Activity not started because intent " + "should be handled by the caller"); break; case ActivityManager.START_TASK_TO_FRONT: launched = true; out.println( "Warning: Activity not started, its current " + "task has been brought to the front"); break; case ActivityManager.START_INTENT_NOT_RESOLVED: out.println( "Error: Activity not started, unable to " + "resolve " + intent.toString()); break; case ActivityManager.START_CLASS_NOT_FOUND: out.println(NO_CLASS_ERROR_CODE); out.println("Error: Activity class " + intent.getComponent().toShortString() + " does not exist."); break; case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: out.println( "Error: Activity not started, you requested to " + "both forward and receive its result"); break; case ActivityManager.START_PERMISSION_DENIED: out.println( "Error: Activity not started, you do not " + "have permission to access it."); break; case ActivityManager.START_NOT_VOICE_COMPATIBLE: out.println( "Error: Activity not started, voice control not allowed for: " + intent); break; case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY: out.println( "Error: Not allowed to start background user activity" + " that shouldn't be displayed for all users."); break; default: out.println( "Error: Activity not started, unknown error code " + res); break; } if (mWaitOption && launched) { if (result == null) { result = new IActivityManager.WaitResult(); result.who = intent.getComponent(); } System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); if (result.who != null) { System.out.println("Activity: " + result.who.flattenToShortString()); } if (result.thisTime >= 0) { System.out.println("ThisTime: " + result.thisTime); } if (result.totalTime >= 0) { System.out.println("TotalTime: " + result.totalTime); } System.out.println("WaitTime: " + (endTime-startTime)); System.out.println("Complete"); } mRepeat--; if (mRepeat > 1) { mAm.unhandledBack(); } } while (mRepeat > 1);}

am最终将调用AMS的startActivityAndWait函数来处理这次启动请求。

@Overridepublic final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {    enforceNotIsolatedCaller("startActivityAndWait");    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,            false, ALLOW_FULL_ONLY, "startActivityAndWait", null);    WaitResult res = new WaitResult();    // TODO: Switch to user app stacks here.    mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,            null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,            options, false, userId, null, null);    return res;}
final void startActivityLocked(ActivityRecord r, boolean newTask,        boolean doResume, boolean keepCurTransition, Bundle options) {    TaskRecord rTask = r.task;    final int taskId = rTask.taskId;    // mLaunchTaskBehind tasks get placed at the back of the task stack.    if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {        // Last activity in task had been removed or ActivityManagerService is reusing task.        // Insert or replace.        // Might not even be in.        insertTaskAtTop(rTask, r);        mWindowManager.moveTaskToTop(taskId);    }    TaskRecord task = null;    if (!newTask) {        // If starting in an existing task, find where that is...        boolean startIt = true;        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {            task = mTaskHistory.get(taskNdx);            if (task.getTopActivity() == null) {                // All activities in task are finishing.                continue;            }            if (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.                if (!startIt) {                    if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "                            + task, new RuntimeException("here").fillInStackTrace());                    task.addActivityToTop(r);                    r.putInHistory();                    mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,                            r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,                            (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,                            r.userId, r.info.configChanges, task.voiceSession != null,                            r.mLaunchTaskBehind);                    if (VALIDATE_TOKENS) {                        validateAppTokensLocked();                    }                    ActivityOptions.abort(options);                    return;                }                break;            } else if (task.numFullscreen > 0) {                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    if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {        mStackSupervisor.mUserLeaving = false;        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,                "startActivity() behind front, mUserLeaving=false");    }    task = r.task;    // Slot the activity into the history stack and proceed    if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,            new RuntimeException("here").fillInStackTrace());    task.addActivityToTop(r);    task.setFrontOfTask();    r.putInHistory();    if (!isHomeStack() || numActivities() > 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.        boolean showStartingIcon = newTask;        ProcessRecord proc = r.app;        if (proc == null) {            proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);        }        if (proc == null || proc.thread == null) {            showStartingIcon = true;        }        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,                "Prepare open transition: starting " + r);        if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition);            mNoAnimActivities.add(r);        } else {            mWindowManager.prepareAppTransition(newTask                    ? r.mLaunchTaskBehind                            ? AppTransition.TRANSIT_TASK_OPEN_BEHIND                            : AppTransition.TRANSIT_TASK_OPEN                    : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);            mNoAnimActivities.remove(r);        }        mWindowManager.addAppToken(task.mActivities.indexOf(r),                r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);        boolean doShow = true;        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 ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {                resetTaskIfNeededLocked(r, r);                doShow = topRunningNonDelayedActivityLocked(null) == r;            }        } else if (options != null && new ActivityOptions(options).getAnimationType()                == ActivityOptions.ANIM_SCENE_TRANSITION) {            doShow = false;        }        if (r.mLaunchTaskBehind) {            // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we            // tell WindowManager that r is visible even though it is at the back of the stack.            mWindowManager.setAppVisibility(r.appToken, true);            ensureActivitiesVisibleLocked(null, 0);        } else 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.                if (prev.task != r.task) {                    prev = null;                }                // (2) The current activity is already displayed.                else if (prev.nowVisible) {                    prev = null;                }            }            mWindowManager.setAppStartingWindow(                    r.appToken, r.packageName, r.theme,                    mService.compatibilityInfoForPackageLocked(                            r.info.applicationInfo), r.nonLocalizedLabel,                    r.labelRes, r.icon, r.logo, r.windowFlags,                    prev != null ? prev.appToken : null, showStartingIcon);            r.mStartingWindowShown = true;        }    } else {        // If this is the first activity, don't do any fancy animations,        // because there is nothing for it to animate on top of.        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);        ActivityOptions.abort(options);        options = null;    }    if (VALIDATE_TOKENS) {        validateAppTokensLocked();    }    if (doResume) {        mStackSupervisor.resumeTopActivitiesLocked(this, r, options);    }}

startActivityLocked函数的主要工作包括

1.处理sourceRecord及resultRecord。其中,sourceRecord表示发起本次请求的Activity,resultRecord表示接收处理结果的Activity(启动一个Activity肯定需要它完成某项事情,当目标Activity将事情成后,就需要告知请求者该事情的处理结果)。在一般情况下,sourceRecord和resultRecord应指向同一个Activity。

2.处理app switch。如果AMS当前禁止app switch,则只能把本次启动请求保存起来,以待允许app switch时再处理。从代码中可知,AMS在处理本次请求前,会先调用doPendingActivityLaunchesLocked函数,在该函数内部将启动之前因系统禁止app switch而保存的Pending请求

3.调用startActivityUncheckedLocked处理本次Activity启动请求

@Overridepublic void stopAppSwitches() {    if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)            != PackageManager.PERMISSION_GRANTED) {        throw new SecurityException("Requires permission "                + android.Manifest.permission.STOP_APP_SWITCHES);    }    synchronized(this) {        mAppSwitchesAllowedTime = SystemClock.uptimeMillis()                + APP_SWITCH_DELAY_TIME;        mDidAppSwitch = false;        mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);        Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);        mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);    }}
public void resumeAppSwitches() {    if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)            != PackageManager.PERMISSION_GRANTED) {        throw new SecurityException("Requires permission "                + android.Manifest.permission.STOP_APP_SWITCHES);    }    synchronized(this) {        // Note that we don't execute any pending app switches... we will        // let those wait until either the timeout, or the next start        // activity request.        mAppSwitchesAllowedTime = 0;    }}

startActivityUncheckedLocked函数很长,但是目的比较简单,即为新创建的ActivityRecord找到一个合适的Task。

ActivityStack

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

resumeTopActivityLocked函数中有两个非常重要的关键点

1.如果mResumedActivity不为空,则需要先暂停(pause)这个Activity。由代码中的注释可知,mResumedActivity代表上一次启动的(即当前正显示的)Activity。现在要启动一个新的Activity,须先停止当前Activity,这部分工作由startPausingLocked函数完成

2.mResumeActivity什么时候为空呢?当然是在启动全系统第一个Activity时,即启动Home界面的时候。除此之外,该值都不会为空

resumeTopActivityLocked最后将调用另外一个startSpecificActivityLocked,该函数将真正创建一个应用进程。

private final void startProcessLocked(ProcessRecord app, String hostingType,        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {    long startTime = SystemClock.elapsedRealtime();    if (app.pid > 0 && app.pid != MY_PID) {        checkTime(startTime, "startProcess: removing from pids map");        synchronized (mPidsSelfLocked) {            mPidsSelfLocked.remove(app.pid);            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);        }        checkTime(startTime, "startProcess: done removing from pids map");        app.setPid(0);    }    if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,            "startProcessLocked removing on hold: " + app);    mProcessesOnHold.remove(app);    checkTime(startTime, "startProcess: starting to update cpu stats");    updateCpuStats();    checkTime(startTime, "startProcess: done updating cpu stats");    try {        try {            if (AppGlobals.getPackageManager().isPackageFrozen(app.info.packageName)) {                // This is caught below as if we had failed to fork zygote                throw new RuntimeException("Package " + app.info.packageName + " is frozen!");            }        } catch (RemoteException e) {            throw e.rethrowAsRuntimeException();        }        int uid = app.uid;        int[] gids = null;        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;        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));        }        checkTime(startTime, "startProcess: building args");        if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL                    && mTopComponent != null                    && app.processName.equals(mTopComponent.getPackageName())) {                uid = 0;            }            if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL                    && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {                uid = 0;            }        }        int debugFlags = 0;        if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {            debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;            // Also turn on CheckJNI for debuggable apps. It's quite            // awkward to turn on otherwise.            debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;        }        // Run the app in safe mode if its manifest requests so or the        // system is booted in safe mode.        if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||            mSafeMode == true) {            debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;        }        if ("1".equals(SystemProperties.get("debug.checkjni"))) {            debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;        }        String jitDebugProperty = SystemProperties.get("debug.usejit");        if ("true".equals(jitDebugProperty)) {            debugFlags |= Zygote.DEBUG_ENABLE_JIT;        } else if (!"false".equals(jitDebugProperty)) {            // If we didn't force disable by setting false, defer to the dalvik vm options.            if ("true".equals(SystemProperties.get("dalvik.vm.usejit"))) {                debugFlags |= Zygote.DEBUG_ENABLE_JIT;            }        }        String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");        if ("true".equals(genDebugInfoProperty)) {            debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;        }        if ("1".equals(SystemProperties.get("debug.jni.logging"))) {            debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;        }        if ("1".equals(SystemProperties.get("debug.assert"))) {            debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;        }        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;        // 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);        if (entryPoint == null) entryPoint = "android.app.ActivityThread";        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +                app.processName);        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!");        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        if (app.isolated) {            mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);        }        mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);        checkTime(startTime, "startProcess: done updating battery stats");        EventLog.writeEvent(EventLogTags.AM_PROC_START,                UserHandle.getUserId(uid), startResult.pid, uid,                app.processName, hostingType,                hostingNameStr != null ? hostingNameStr : "");        if (app.persistent) {            Watchdog.getInstance().processStarted(app.processName, startResult.pid);        }        checkTime(startTime, "startProcess: building log message");        StringBuilder buf = mStringBuilder;        buf.setLength(0);        buf.append("Start proc ");        buf.append(startResult.pid);        buf.append(':');        buf.append(app.processName);        buf.append('/');        UserHandle.formatUid(buf, uid);        if (!isActivityProcess) {            buf.append(" [");            buf.append(entryPoint);            buf.append("]");        }        buf.append(" for ");        buf.append(hostingType);        if (hostingNameStr != null) {            buf.append(" ");            buf.append(hostingNameStr);        }        Slog.i(TAG, buf.toString());        app.setPid(startResult.pid);        app.usingWrapper = startResult.usingWrapper;        app.removed = false;        app.killed = false;        app.killedByAm = false;        checkTime(startTime, "startProcess: starting to update pids map");        synchronized (mPidsSelfLocked) {            this.mPidsSelfLocked.put(startResult.pid, app);            if (isActivityProcess) {                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);                msg.obj = app;                mHandler.sendMessageDelayed(msg, startResult.usingWrapper                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);            }        }        checkTime(startTime, "startProcess: done updating pids map");    } catch (RuntimeException e) {        // XXX do better error recovery.        app.setPid(0);        mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);        if (app.isolated) {            mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);        }        Slog.e(TAG, "Failure starting process " + app.processName, e);    }}

1.FLAG_FROM_BACKGROUND标志发起这次启动的Task属于后台任务。很显然,手机中没有界面供用户操作位于后台Task中的Activity。如果没有设置该标志,那么这次启动请求就是由前台Task因某种原因而触发的(例如:用户单击某个按钮)

2.如果一个应用进程在1分钟内连续崩溃超过2次,则AMS会将其ProcessRecord加入所谓的mBadProcesses中。一个应用崩溃后,系统会弹出一个警告框以提醒用户。

ActivityThread

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());    AndroidKeyStoreProvider.install();    // Make sure TrustedCertificateStore looks in the right place for CA certificates    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());    TrustedCertificateStore.setDefaultUserDirectory(configDir);    Process.setArgV0("
"); 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");}

在main函数内部将创建一个消息循环Loop,接着调用ActivityThread的attach函数,最终将主线程加入消息循环

private void attach(boolean system) {    sCurrentActivityThread = this;    mSystemThread = system;    if (!system) {        ViewRootImpl.addFirstDrawHandler(new Runnable() {            @Override            public void run() {                ensureJitEnabled();            }        });        android.ddm.DdmHandleAppName.setAppName("
", UserHandle.myUserId()); RuntimeInit.setApplicationObject(mAppThread.asBinder()); final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore } // Watch for getting close to heap limit. BinderInternal.addGcWatcher(new Runnable() { @Override public void run() { if (!mSomeActivitiesChanged) { return; } Runtime runtime = Runtime.getRuntime(); long dalvikMax = runtime.maxMemory(); long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); if (dalvikUsed > ((3*dalvikMax)/4)) { if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024) + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024)); mSomeActivitiesChanged = false; try { mgr.releaseSomeActivities(mAppThread); } catch (RemoteException e) { } } } }); } else { // Don't set application object here -- if the system crashes, // we can't display an alert, we just want to die die die. android.ddm.DdmHandleAppName.setAppName("system_process", UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); ContextImpl context = ContextImpl.createAppContext( this, getSystemContext().mPackageInfo); mInitialApplication = context.mPackageInfo.makeApplication(true, null); mInitialApplication.onCreate(); } catch (Exception e) { throw new RuntimeException( "Unable to instantiate Application():" + e.toString(), e); } } // add dropbox logging to libcore DropBox.setReporter(new DropBoxReporter()); ViewRootImpl.addConfigCallback(new ComponentCallbacks2() { @Override public void onConfigurationChanged(Configuration newConfig) { synchronized (mResourcesManager) { // We need to apply this change to the resources // immediately, because upon returning the view // hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) { // This actually changed the resources! Tell // everyone about it. if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(newConfig)) { mPendingConfiguration = newConfig; sendMessage(H.CONFIGURATION_CHANGED, newConfig); } } } } @Override public void onLowMemory() { } @Override public void onTrimMemory(int level) { } });}

AMS创建一个应用进程后,会设置一个超时时间(一般是10秒)。如果超过这个时间,应用进程还没有和AMS交互,则断定该进程创建失败。所以,应用进程启动后,需要尽快和AMS交互,即调用AMS的attachApplication函数。在该函数内部将调用attachApplicationLocked。

attachApplicationLocked第一阶段的工作比较简单:

1.设置代表该应用进程的ProcessRecord对象的一些成员变量,如用于和应用进程交互的thread对象、jincheng 调度优先级及oom_adj的值等

2.从消息队列中撤销PROC_START_TIMEOUT_MSG

应用进程的创建及初始化总结

1.在应用进程启动后,需要尽快调用AMS的attachApplication函数,该函数是这个刚创建的应用进程第一次和AMS交互。此时的它还默默无名,连一个确定的进程名都没有。不过没关系,attachApplication函数将根据创建该应用进程之前所保存的ProcessRecord为其准备一切手续

2.attachApplication准备好一切后,将调用应用进程的bindApplication函数,在该函数内部将发消息给主线程,最终该消息由handleBindApplication处理。handleBindApplication将为该进程设置进程名,初始化一些策略和参数信息等。另外,它还创建一个Application对象。同时,如果该Application声明了ContentProvider,还需要为该进程安装ContentProvider。

AMS调用完bindApplication后,将通过realStartActivityLocked启动Activity。在此之前,要创建完应用进程并初始化Android运行环境

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {    // If we are getting ready to gc after going to the background, well    // we are back active so skip it.    unscheduleGcIdler();    mSomeActivitiesChanged = true;    if (r.profilerInfo != null) {        mProfiler.setProfiler(r.profilerInfo);        mProfiler.startProfiling();    }    // Make sure we are running with the most recent config.    handleConfigurationChanged(null, null);    if (localLOGV) Slog.v(        TAG, "Handling launch of " + r);    // Initialize before creating the activity    WindowManagerGlobal.initialize();    Activity a = performLaunchActivity(r, customIntent);    if (a != null) {        r.createdConfig = new Configuration(mConfiguration);        Bundle oldState = r.state;        handleResumeActivity(r.token, false, r.isForward,                !r.activity.mFinished && !r.startsNotResumed);        if (!r.activity.mFinished && r.startsNotResumed) {            // The activity manager actually wants this one to start out            // paused, because it needs to be visible but isn't in the            // foreground.  We accomplish this by going through the            // normal startup (because activities expect to go through            // onResume() the first time they run, before their window            // is displayed), and then pausing it.  However, in this case            // we do -not- need to do the full pause cycle (of freezing            // and such) because the activity manager assumes it can just            // retain the current state it has.            try {                r.activity.mCalled = false;                mInstrumentation.callActivityOnPause(r.activity);                // We need to keep around the original state, in case                // we need to be created again.  But we only do this                // for pre-Honeycomb apps, which always save their state                // when pausing, so we can not have them save their state                // when restarting from a paused state.  For HC and later,                // we want to (and can) let the state be saved as the normal                // part of stopping the activity.                if (r.isPreHoneycomb()) {                    r.state = oldState;                }                if (!r.activity.mCalled) {                    throw new SuperNotCalledException(                        "Activity " + r.intent.getComponent().toShortString() +                        " did not call through to super.onPause()");                }            } catch (SuperNotCalledException e) {                throw e;            } catch (Exception e) {                if (!mInstrumentation.onException(r.activity, e)) {                    throw new RuntimeException(                            "Unable to pause activity "                            + r.intent.getComponent().toShortString()                            + ": " + e.toString(), e);                }            }            r.paused = true;        }    } else {        // If there was an error, for any reason, tell the activity        // manager to stop us.        try {            ActivityManagerNative.getDefault()                .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);        } catch (RemoteException ex) {            // Ignore        }    }}

 

1.首先调用performLaunchActivity,该在函数内部通过Java反射机制创建目标Activity,然后调用它的onCreate及onStart函数

2.调用handleResumeActivity,会在其内部调用目标Activity的onResume函数。

 

startActivity总结

1.起点是am。我们利用am start命令,发起本次目标Activity的启动请求

2.接下来进入ActivityManagerService和ActivityStack这两个核心类。对于启动Activity来说,这段行程又可细分为两个阶段:第一阶段就是根据启动模式和启动标志找到活创建ActivityRecord及对应的TaskRecord;第二阶段就是处理Activity启动或切换相关的工作

3.然后AMS直接创建目标进程并运行Activity的流程,其中涉及目标进程的创建,目标进程中Android运行环境的初始化,目标Activity的创建以及onCreate、onStart及onResume等生命周期中重要函数的调用等相关知识

4.AMS先暂停当前Activity,然后再创建目标进程并运行Activity的流程,其中两个应用进程和AMS交互。

转载于:https://www.cnblogs.com/anni-qianqian/p/7053526.html

你可能感兴趣的文章
201771010125王瑜《面向对象程序设计(Java)》第十三周学习总结
查看>>
手机验证码执行流程
查看>>
python 基础 ----- 变量
查看>>
设计模式课程 设计模式精讲 2-2 UML类图讲解
查看>>
Silverlight 的菜单控件。(不是 Toolkit的)
查看>>
:hover 鼠标同时触发两个元素变化
查看>>
go语言学习十三 - 相等性
查看>>
Idea 提交代码到码云(提交到github也大同小异)
查看>>
c#连接excel2007未安装ISAM解决
查看>>
Mono 异步加载数据更新主线程
查看>>
初识lua
查看>>
我是插件狂人,jDuang,jValidator,jModal,jGallery
查看>>
张季跃 201771010139《面向对象程序设计(java)》第四周学习总结
查看>>
如何解除循环引用
查看>>
android中fragment的使用及与activity之间的通信
查看>>
jquery的contains方法
查看>>
python3--算法基础:二分查找/折半查找
查看>>
Perl IO:随机读写文件
查看>>
转:基于用户投票的排名算法系列
查看>>
WSDL 详解
查看>>