Jimmy Chen

A Programmer

基于Android 9之应用冷启动过程分析(一)

Advertisements
Advertisements
Advertisements

  这次会先开始分析应用冷启动流程,即在系统中还没有对应的应用进程的情况下,点击应用在Launcher上图标到应用加载起来的一系列过程。下面直接开始进行分析:

点击Launcher上的应用图标

  在Launcher启动的时候会在桌面创建应用的图标,同时通过设置ItemClickHandler监听桌面图标的点击事件,当点击桌面应用图标的时候就会调用ItemClickHandler.onClick方法。下面用一张流程图简单说明一下吧,具体代码大家可以跟着流程图走:

《基于Android 9之应用冷启动过程分析(一)》

根据上面的流程图可以知道,在Launcher中,最后会调用到Activity.java中的startActivity,下面我们接着startActivity分析。

Android框架处理流程

// Launcher调用的时候传入的options != null
public void startActivity(Intent intent, @Nullable Bundle options) {
    // 调用startActivityForResult
    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);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            ............................
        }

        cancelInputsAndStartExitTransition(options);
    } else {
        .................
}

上面最后调用到Instrumentation的execStartActivity方法,虽然说Instrumentation是一个单元测试框架,但是Activity、Application的启动都会用到Instrumentation,下面接着看

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != null ? target.onProvideReferrer() : null;
    if (referrer != null) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    // 查看是否有想系统添加ActivityMonitor对象
    // 一般不会走这里
    if (mActivityMonitors != null) {
        ...........
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        // Binder调用,这里首先是获取AMS服务代理
        // 然后通过代理调用到AMS的startActivity
        int result = ActivityManager.getService()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

这里,mActivityMonitors是ActivityMonitor的一个集合,ActivityMonitor是用来监控应用中的活动,可以监控监控应用中的一些意图,一般用在单元测试过程中对应用的状态进行监控。

public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    // 调用startActivityAsUser方法,多添加一个userId参数
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            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 bOptions, int userId) {
    // 调用startActivityAsUser重载方法,多添加一个validateIncomingUser参数
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
            true /*validateIncomingUser*/);
}

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
        boolean validateIncomingUser) {
    enforceNotIsolatedCaller("startActivity");

    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

    // TODO: Switch to user app stacks here.
    // 下面obtainStarter获取到的是一个ActivityStarter对象
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)
            .execute();

}

上面最后一部分是通过mActivityStartController对象进行操作。我们看看obtainStarter完成的工作,首先要了解的是,在调用new ActivityStartController对象的时候,也会new DefaultFactory对象赋值给成员变量mFactory,

// ActivityStartController.java
ActivityStarter obtainStarter(Intent intent, String reason) {
    // 这里调用DefaultFactory对象的obtain方法
    return mFactory.obtain().setIntent(intent).setReason(reason);
}

// ActivityStart.java
@Override
public ActivityStarter obtain() {
    ActivityStarter starter = mStarterPool.acquire();

    if (starter == null) {
        starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
    }

    // 返回一个ActivityStarter
    return starter;
}

从上面的代码可以看到obtainStarter最后获取到的是一个ActivityStarter对象,所以在startActivityAsUser中,最后的setCaller、setMayWait、execute等等操作都是基于ActivityStarter对象的。

紧接着startActivityAsUser分析,最后调用的是ActivityStarter的execute方法

int execute() {
    try {
        // 在前面在获取到ActivityStarter后,有调用setMayWait方法,所以走这个分支
        if (mRequest.mayWait) {
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                    mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                    mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                    mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                    mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                    mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                    mRequest.inTask, mRequest.reason,
                    mRequest.allowPendingRemoteAnimationRegistryLookup,
                    mRequest.originatingPendingIntent);
        } else {
            .................
        }
    } finally {
        onExecutionComplete();
    }
}

下面直接开始看startActivityMayWait方法,startActivityMayWait内容比较多,这里做简要分析:

private 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 globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
        int userId, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup,
        PendingIntentRecord originatingPendingIntent) {
    // 拒绝intent中带文件描述符,防止文件描述符泄露
    if (intent != null && intent.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }
    mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
    boolean componentSpecified = intent.getComponent() != null;

    // 对调用者的PID和UID进行判断处理,省略
    final int realCallingPid = Binder.getCallingPid();
    .................

    // 对ephemeral应用的处理,这里不分析
    // Save a copy in case ephemeral needs it
    final Intent ephemeralIntent = new Intent(intent);
    ...........................

    // 查找获取与intent最相符的那个ResolveInfo,下面会分析resolveInten方法
    ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
            0 /* matchFlags */,
                    computeResolveFilterUid(
                            callingUid, realCallingUid, mRequest.filterCallingUid));
    // 如果上面没有获取到ResolveInfo,这里会做额外处理,略过
    if (rInfo == null) {
        .......................
    }
    // 根据上面得到的ResolveInfo,获取ActivityInfo
    ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);

    synchronized (mService) {
        final ActivityStack stack = mSupervisor.mFocusedStack;
        stack.mConfigWillChange = globalConfig != null
                && mService.getGlobalConfiguration().diff(globalConfig) != 0;
        if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                "Starting activity when config will change = " + stack.mConfigWillChange);

        final long origId = Binder.clearCallingIdentity();

        if (aInfo != null &&
                (aInfo.applicationInfo.privateFlags
                        & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 &&
                mService.mHasHeavyWeightFeature) {

            if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
                // mHeavyWeightProcess中保存当前正在运行的HeavyWeight(重量级)进程
                final ProcessRecord heavy = mService.mHeavyWeightProcess;
                // 这里通过判断当前要启动的进程是否为正在运行的重量级进程
                if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
                        || !heavy.processName.equals(aInfo.processName))) {
                // 重量级进程的处理,略过
                ....................................
            }
        }

        // 这里创建ActivityRecord数组
        final ActivityRecord[] outRecord = new ActivityRecord[1];
        // 调用startActivity
        int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);

        Binder.restoreCallingIdentity(origId);

        if (stack.mConfigWillChange) {
            // 调用者修改了调用配置
            mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                    "updateConfiguration()");
            stack.mConfigWillChange = false;
            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                    "Updating to new configuration after starting activity.");
            mService.updateConfigurationLocked(globalConfig, null, false);
        }

        // 通知ActivityMetricsLogger,Activity已经启动,随后ActivityMetricsLogger会等待界面描绘,并返回结果
        mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
        if (outResult != null) {
            outResult.result = res;

            final ActivityRecord r = outRecord[0];

            switch(res) {
                    // 判断Activity是否start成功
                    .................
                }
            }
        }

        return res;
    }
}

上面有调用到ActivityStackSupervisor类中的两个方法:resolveIntent和resolveActivity,下面做简单分析。

resolveIntent && resolveActivity

先看resolveIntent

// ActivityStackSupervisor.java
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags,
        int filterCallingUid) {
    synchronized (mService) {
        try {
            Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "resolveIntent");
            // 对Intent中带有的Flag进行处理
            int modifiedFlags = flags
                    | PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS;
            if (intent.isWebIntent()
                        || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
                modifiedFlags |= PackageManager.MATCH_INSTANT;
            }

            final long token = Binder.clearCallingIdentity();
            try {
                // 下面的调用过程最终会走到PackageManagerService中的resolveIntentInternal方法
                // 我们在下面直接分析PMS中的resolveIntentInternal方法
                return mService.getPackageManagerInternalLocked().resolveIntent(
                        intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
        }
    }
}

// PackageManagerService.java
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
        int flags, int userId, boolean resolveForStart, int filterCallingUid) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");

        // 判断当前用户是否存在
        if (!sUserManager.exists(userId)) return null;
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
        // 判断是否有相应的Permission
        mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
        // queryIntentActivitiesInternal是根据intent、resolvedType和flags选出符合的ResolveInfo集合
        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

        // chooseBaseActivity将上面选出的ResolveInfo集合选出最符合的那个ResolveInfo
        // 如果符合的ResolveInfo多于一个,则让用户进行选择
        final ResolveInfo bestChoice =
                chooseBestActivity(intent, resolvedType, flags, query, userId);
        return bestChoice;
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

OK,resolveIntent相关代码就看到这里,resolveIntent主要是确定和发过来的intent、resolvedType和flags相关的ResolveInfo有哪些,再从中选择最符合的ResolveInfo,返回给调用者。

后看resolveActivity

ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
        ProfilerInfo profilerInfo) {
    // 根据前面选出的ResolveInfo,获取到合适的ActivityInfo
    final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
    if (aInfo != null) {
        // 根据ActivityInfo中的信息,设置intent中的Component
        intent.setComponent(new ComponentName(
                aInfo.applicationInfo.packageName, aInfo.name));

        // 如果启动的进程是system的话,不会设置相关的debug标志位
        if (!aInfo.processName.equals("system")) {
            if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
                mService.setDebugApp(aInfo.processName, true, false);
            }

            if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
                mService.setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
            }

            if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {
                mService.setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
            }

            if (profilerInfo != null) {
                mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
            }
        }
        final String intentLaunchToken = intent.getLaunchToken();
        if (aInfo.launchToken == null && intentLaunchToken != null) {
            aInfo.launchToken = intentLaunchToken;
        }
    }
    // 将最终的ActivityInfo返回
    return aInfo;
}

OK,这篇分析到这里,上面我们分析到startActivityMayWait最后会调用startActivity来启动Activity,下一篇我会接着startActivity继续进行分析。

Advertisements
Advertisements
Advertisements

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

%d 博主赞过: