android App启动流程一-启动APP的两种方式

App启动流程分为2个部分,一个是系统开机,拉起Launcher APP。另一个流程分为Launcher APP点击桌面应用图标,然后启动APP。我们首先分析Launcher APP的启动。

Launcher APP的启动:

android启动流程-SystemServer一篇文章中我们简单提过Launcher APP启动的过程,本章我们具体分析一下Launcher APP是怎么启动的。

还是先从ActivityManagerService.systemReady看起,往下执行。

ActivityManagerService

ActivityManagerService.systemReady->ActivityTaskManagerInternal.startHomeOnAllDisplays

/**
* Ready. Set. Go!
*/
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {

    ...    

    if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
        t.traceBegin("startHomeOnAllDisplays");
        mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
        t.traceEnd();
    }

    ...
}

ActivityTaskManagerService

ActivityTaskManagerInternal.startHomeOnAllDisplays->ActivityTaskManagerService.startHomeOnAllDisplays->RootWindowContainer.startHomeOnAllDisplays

​
final class LocalService extends ActivityTaskManagerInternal {

    ...

    @Override
    public boolean startHomeOnAllDisplays(int userId, String reason) {
        synchronized (mGlobalLock) {
            return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
        }
    }

    ...

}
​

RootWindowContainer

boolean startHomeOnAllDisplays(int userId, String reason) {
    boolean homeStarted = false;
    for (int i = getChildCount() - 1; i >= 0; i--) {
        final int displayId = getChildAt(i).mDisplayId;
        homeStarted |= startHomeOnDisplay(userId, reason, displayId);
    }
    return homeStarted;
}

boolean startHomeOnDisplay(int userId, String reason, int displayId) {
    return startHomeOnDisplay(userId, reason, displayId, false /* allowInstrumenting */,
            false /* fromHomeKey */);
}

boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
                           boolean fromHomeKey) {
    // Fallback to top focused display or default display if the displayId is invalid.
    if (displayId == INVALID_DISPLAY) {
        final Task rootTask = getTopDisplayFocusedRootTask();
        displayId = rootTask != null ? rootTask.getDisplayId() : DEFAULT_DISPLAY;
    }

    final DisplayContent display = getDisplayContent(displayId);
    return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
                    result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
                            allowInstrumenting, fromHomeKey),
            false /* initValue */);
}


boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,boolean allowInstrumenting, boolean fromHomeKey) {
    
    ...    

    mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
            taskDisplayArea);
    return true;
}

ActivityStartController

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
                       TaskDisplayArea taskDisplayArea) {

    ...

    mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
            .setOutActivity(tmpOutRecord)
            .setCallingUid(0)
            .setActivityInfo(aInfo)
            .setActivityOptions(options.toBundle())
            .execute();
    mLastHomeActivityStartRecord = tmpOutRecord[0];
    if (rootHomeTask.mInResumeTopActivity) {
        // If we are in resume section already, home activity will be initialized, but not
        // resumed (to avoid recursive resume) and will stay that way until something pokes it
        // again. We need to schedule another resume.
        mSupervisor.scheduleResumeTopActivities();
    }
}

流程图:


 

Launcher APP点击普通APP的启动:

ItemClickHandler:

Launcher APP点击普通APP时,会触发onClick方法:

private static void onClick(View v) {

    if (tag instanceof WorkspaceItemInfo) {
        onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
    } else if (tag instanceof FolderInfo) {
        if (v instanceof FolderIcon) {
            onClickFolderIcon(v);
        }
    } else if (tag instanceof AppInfo) {
        startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
    } else if (tag instanceof LauncherAppWidgetInfo) {
        if (v instanceof PendingAppWidgetHostView) {
            onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
        }
    } else if (tag instanceof ItemClickProxy) {
        ((ItemClickProxy) tag).onItemClicked(v);
    }
}

//最终会执行到这里
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
    
    ...
    
    launcher.startActivitySafely(v, intent, item);
}  

然后执行到ActivityContext中:

default RunnableList startActivitySafely(
        View v, Intent intent, @Nullable ItemInfo item) {

    ...

    if (isShortcut) {
        // Shortcuts need some special checks due to legacy reasons.
        startShortcutIntentSafely(intent, optsBundle, item);
    } else if (user == null || user.equals(Process.myUserHandle())) {
        // Could be launching some bookkeeping activity
        context.startActivity(intent, optsBundle);
    } else {
        context.getSystemService(LauncherApps.class).startMainActivity(
                intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
    }

    ...

}

Activity:

然后会执行到Activity.startActivity:

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    getAutofillClientController().onStartActivity(intent, mIntent);
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

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

    }
    
    ...
}

然后执行Instrumentation.execStartActivity:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    
    ...
    
    int result = ActivityTaskManager.getService().startActivity(whoThread,
            who.getOpPackageName(), who.getAttributionTag(), intent,
            intent.resolveTypeIfNeeded(who.getContentResolver()), token,
            target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
    
    ...
    
}

ActivityTaskManagerService

上面代码中ActivityTaskManager.getService()获取到ActivityTaskManagerService,所以我们接下来看ActivityTaskManagerService:

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
                               String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
                               String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
                               Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
            resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}


private int startActivityAsUser(IApplicationThread caller, String callingPackage,
                                @Nullable String callingFeatureId, Intent intent, String resolvedType,
                                IBinder resultTo, String resultWho, int requestCode, int startFlags,
                                ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
    
    ...

    // TODO: Switch to user app stacks here.
    return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setCallingFeatureId(callingFeatureId)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(opts)
            .setUserId(userId)
            .execute();

}

流程图

 黑白屏现象分析

ActivityStarter

ActivityStarter它是一个用于解释如何启动一个Activity的控制器,用来配置actiivty的各种熟悉并加载启动 Activity 的类,此类记录所有逻辑,用于确定如何将意图和标志转换为Activity以及关联的任务和堆栈。 在ActivityStarter中包含了一个静态内部类Request,这个类或许非常恰当的说明ActivityStarter的作用。它的部分代码如下:

static class Request { 
...
    IApplicationThread caller;
    Intent intent;
    NeededUriGrants intentGrants;
    // A copy of the original requested intent, in case for ephemeral app launch. 
    Intent ephemeralIntent;
    String resolvedType;
    ActivityInfo activityInfo;
    ResolveInfo resolveInfo;
    IVoiceInteractionSession voiceSession;
    IVoiceInteractor voiceInteractor;
    IBinder resultTo;
    String resultWho;
    int requestCode;
    int callingPid = DEFAULT_CALLING_PID;
    int callingUid = DEFAULT_CALLING_UID;
    String callingPackage;
    @Nullable String callingFeatureId;
    int realCallingPid = DEFAULT_REAL_CALLING_PID;
    int realCallingUid = DEFAULT_REAL_CALLING_UID;
    int startFlags;
    SafeActivityOptions activityOptions;
    boolean ignoreTargetSecurity;
    boolean componentSpecified;
    boolean avoidMoveToFront;
    ActivityRecord[] outActivity;
    Task inTask;
    String reason;
    ProfilerInfo profilerInfo;
    Configuration globalConfig;
    int userId;
    WaitResult waitResult;
    int filterCallingUid;
    PendingIntentRecord originatingPendingIntent;
    boolean allowBackgroundActivityStart; 
    ...
} 

可以看到,这个类里面有非常多的参数,而这些参数就包含了启动activity的相关信息和被启动 Activity的相关信息。在启动activity之前把所有信息都准备全,这个工作就需要交给ActivityStarter类来做。另外,startActivity(new Intent(ActivityA.this,ActivityB.class))的参数信息只有三个:Intent,context和ActivityB.class,这些信息就会在ActivtyStarter类中被封装成为一个request, 有了这些信息,才能去进行启动的下一步工作。

我们继续执行:

 ActivityStarter obtainStarter(Intent intent, String reason) {
     return mFactory.obtain().setIntent(intent).setReason(reason);
 }

static class DefaultFactory implements Factory {
    @Override
    public ActivityStarter obtain() {
        ActivityStarter starter = mStarterPool.acquire();

        if (starter == null) {
            if (mService.mRootWindowContainer == null) {
                throw new IllegalStateException("Too early to start activity.");
            }
            starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
        }
  
        return starter;
    }
}

int execute() {
    ...

    try {
        res = executeRequest(mRequest);

    } finally {
        mRequest.logMessage.append(" result code=").append(res);
        Slog.i(TAG, mRequest.logMessage.toString());
        mRequest.logMessage.setLength(0);
    }
        
    ...

}

继续执行executeRequest:

private int executeRequest(Request request) {
    ActivityInfo aInfo = request.activityInfo;
    ResolveInfo rInfo = request.resolveInfo;
    String resultWho = request.resultWho;
    Task inTask = request.inTask;

    ActivityRecord sourceRecord = null;//code 1 
    ActivityRecord resultRecord = null;//code 2 

    if (resultTo != null) {
        sourceRecord = mRootWindowContainer.isInAnyStack(resultTo); //code 3 
        ......
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    } 
    ......
    //code 4 
    final ActivityRecord r = new ActivityRecord(mService,callerApp, callingPid,
            callingUid, callingPackage, callingFeatureId, intent, resolvedType,
            aInfo,mService.getGlobalConfiguration(), resultRecord, resultWho,
            requestCode,request.componentSpecified, voiceSession != null,
            mSupervisor, checkedOptions, sourceRecord);

    //code 5 
    mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
            request.voiceInteractor, startFlags, checkedOptions,
            inTask, inTaskFragment, balCode, intentGrants, realCallingUid);

    if (request.outActivity != null) {
        request.outActivity[0] = mLastStartActivityRecord;
    }

    return mLastStartActivityResult;
} 
  1. 上面代码中code 1 &code 2 定义了两个ActivityRecord;
  2. code 3 处初始化sourceRecord,这个sourceRecord,就是构建了当前Activity在AMS中的 ActivtyRecord。比如ActivityA启动ActivityB,那么这个ActivityRecord就是ActivityA 在AMS中的存在形式。当然这也 就是说要在启动新Activity之前要知道sourceReord是谁。
  3. code4 new了一个ActivityRecord,它就是要被启动的Activity。
  4. code5 调了startActivityUnchecked()方法,执行下一步的生命周期流程的调度。
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                                   IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                                   int startFlags, ActivityOptions options, Task inTask,
                                   TaskFragment inTaskFragment, @BalCode int balCode,
                                   NeededUriGrants intentGrants, int realCallingUid) {

    ...

   
    try {
        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
        result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, options, inTask, inTaskFragment, balCode,
                intentGrants, realCallingUid);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
        startedActivityRootTask = handleStartResult(r, options, result, newTransition,
                remoteTransition);
    }
    
    ...

    return result;
}

黑白屏现象

在app启动的时候,在AcitivityStarter启动activity的时候会有一个特殊的过程,这个过程就是启动一个黑白屏,用于提醒用户,正在启动新的app。那么这个启动黑白屏的过程是怎样的的呢?

int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
                       IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                       int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                       boolean restrictedBgActivity, NeededUriGrants intentGrants) {
    //初始化配置,mStartActivity、mLaunchMode等
    setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
                  voiceSession, voiceInteractor, balCode, realCallingUid);
    // 计算要启动的Activity的task标志,也就是计算启动模式 
    computeLaunchingTaskFlags();
    //将mLaunchFlags设置给Intent,也就是设置启动模式
    mIntent.setFlags(mLaunchFlags);
    ...
    // code1 
    // 创建启动黑白屏window 
    mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,mOptions, sourceRecord);
    if (mDoResume) {
        if (!mTargetRootTask.isTopActivityFocusable()
                      || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                      && mStartActivity != topTaskActivity)) {
            ...
        } else {
            ...
            //code2 将启动流程交给RootWindowContainer去执行,并通过 
            mRootWindowContainer.resumeFocusedStacksTopActivities(
                    mTargetStack, mStartActivity, mOptions);
        }
    }
    ...
    return START_SUCCESS;
}

函数一开始先初始化启动activity需要的配置,然后再基于配置参数计算出启动模式,并将启动模式设置给Intent作为后期备用的变量。接着会运行到code1,此时便是创建一个黑白屏。

那为什么在Activity进程创建之前会启动黑白屏么? 因为当用户点击Launcher界面app icon的时候,为了让用户在第一时间能够感受到点击的响应,此时必须要有界面切换来证明变化的存在。在app启动流程中,如果在app进程创建后才显示这个黑白屏,那么Launcher界面将出现一个 比较长的等待时间,这将会被用户错误的认知为点击没有及时响应。因此,在app进程还没有创建的时候,在启动 activity的过程中,一旦设置了activity的启动模式就立刻创建一个黑白屏,用于衔接点击app icon到app真正显示这中间的时间间隙。

至于解决方案,可以在界面的主题中设置背景页的方式解决。

RootWindowContainer

Android10新增的类,当activity启动的时候,会将整个启动流程转交给RootWindowContainer去执行,RootWindowContainer是窗口容器(WindowContainer)的根容器,管理了所有窗口容器,设备上所有的窗口 (Window)、显示(Display)都是由它来管理的。resumeFocusedStacksTopActivities函数会恢复对应任务栈顶 部的Activity。这个方法会检查一些可见性相关的属性,如果当前需要resume的activityStack 是可见的,这个时候才 resume,而可见性是由RootWindowContainer中的窗口控制的。所以,每个activity都有自己的窗口,为了控制 activity窗口的可见性,Activity的启动必须经过RootWindowContainer。

我们继续分析源码可知(Android 14),RootWindowContainer.resumeFocusedStacksTopActivities方法会触发到Task类,最终会执行到ActivityTaskSupervisor.startSpecificActivity。

在Android11中,会执行到ActivityStack,最终到ActivityStackSupervisor.startSpecificActivity。

ActivityStackSupervisor

我们看一下ActivityStackSupervisor.startSpecificActivity:

void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    final WindowProcessController wpc =
            mService.getProcessController(r.processName, r.info.applicationInfo.uid);

    boolean knownToBeDead = false;
    //code 1 如果应用进程已经启动
    if (wpc != null && wpc.hasThread()) {
        try {
            realStartActivityLocked(r, wpc, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        // restart the application.
        knownToBeDead = true;
        // Remove the process record so it won't be considered as alive.
        mService.mProcessNames.remove(wpc.mName, wpc.mUid);
        mService.mProcessMap.remove(wpc.getPid());
    } else if (r.intent.isSandboxActivity(mService.mContext)) {
        Slog.e(TAG, "Abort sandbox activity launching as no sandbox process to host it.");
        r.finishIfPossible("No sandbox process for the activity", false /* oomAdj */);
        r.launchFailed = true;
        r.detachFromProcess();
        return;
    }

    r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

    final boolean isTop = andResume && r.isTopRunningActivity();
    //code 2 未创建进程
    mService.startProcessAsync(r, knownToBeDead, isTop,
            isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
                    : HostingRecord.HOSTING_TYPE_ACTIVITY);
}

根据上面代码可知,在该方法中,有一个if (wpc != null && wpc.hasThread())判断,通过processName和applicationInfo.uid获取到的WindowProcessController来判断要启动的Activity的进程是否已经启动。

如果启动,执行ActivityStackSupervisor.realStartActivityLocked();

如果未启动,去创建进程,执行ActivityTaskManagerService.startProcessAsync();

流程图

最后附一下整理很久的流程图:

  • 46
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值