App 启动过程分析(Activity 启动过程)(一)

761 阅读6分钟

一个电话面中提及到的问题,忘了是App启动还是Activity启动(那就顺便都分析一遍)。这里进行一下源码的分析,给自己加深下印象。

源码准备

由于Android的源码部分有的是@hide标注的,所以呢在用AS找类的时候会比较的麻烦,一对报红的情况,所以呢在分析之前需要先解决一下这个问题。

解决办法有两个

方法一.

将SDK源码全部导入AS或Eclipse,依然麻烦,为了查看一两个API而导入上百M的代码很不划算!

方法二.

在GitHub已有人去除Android.jar中@hide注解 地址: github.com/anggrayudi/…

1.下载对应API版本Android.jar 2.替换路径SDK/platforms/android-版本/Android.jar 3.重新打开IDE就可以查看

方法二还有额外便利,就是可以直接使用隐藏API,不需要反射(浪费性能又麻烦又易写错) Android.jar并不会打包到APK,所以去除@hide的Android.jar,只是欺骗IDE/编译器,方便程序员查看使用!

我这里是用的方法二,替换了api28的包,准备好这些我们就可以开始了

源码分析

1.Launcher

1.1 Launcher的主Activity——Launcher.java中,点击app图标之后会回调其中的onclick方法。
Launcher代码地址

public void onClick(View v) {
    ...
    Object tag = v.getTag();
    if (tag instanceof ShortcutInfo) {
        // 从快捷方式图标启动
        onClickAppShortcut(v);
    } else if (tag instanceof FolderInfo) {
        // 文件夹
        if (v instanceof FolderIcon) {
           onClickFolderIcon(v);
        }
    } else if (v == mAllAppsButton) {
        // “所有应用”按钮
        onClickAllAppsButton(v);
    } else if (tag instanceof AppInfo) {
        // 从“所有应用”中启动的应用
        startAppShortcutOrInfoActivity(v);
    } else if (tag instanceof LauncherAppWidgetInfo) {
        // 组件
        if (v instanceof PendingAppWidgetHostView) {
            onClickPendingWidget((PendingAppWidgetHostView) v);
        }
    }
}

1.2 Launcher.onClickAppShortcut会调用startAppShortcutOrInfoActivity 方法:

@Thunk void startAppShortcutOrInfoActivity(View v) {
    Object tag = v.getTag();
    final ShortcutInfo shortcut;
    final Intent intent;
    if (tag instanceof ShortcutInfo) {
        shortcut = (ShortcutInfo) tag;
        // 取出对应的 Intent 对象
        intent = shortcut.intent;
        int[] pos = new int[2];
        v.getLocationOnScreen(pos);
        intent.setSourceBounds(new Rect(pos[0], pos[1],
                pos[0] + v.getWidth(), pos[1] + v.getHeight()));

    } else if (tag instanceof AppInfo) {
        shortcut = null;
        intent = ((AppInfo) tag).intent;
    } else {
        throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");
    }

    // 调用 startActivitySafely 方法
    boolean success = startActivitySafely(v, intent, tag);
    mStats.recordLaunch(v, intent, shortcut);

    if (success && v instanceof BubbleTextView) {
        mWaitingForResume = (BubbleTextView) v;
        mWaitingForResume.setStayPressed(true);
    }
}

1.3 用取出来的Intent调用startActivity

private boolean startActivity(View v, Intent intent, Object tag) {
    // 启动新的任务栈
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    try {
        ...
        if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
            try {            
                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
                        .penaltyLog().build());
                // 调用 Activity 的 startActivity 方法
                startActivity(intent, optsBundle);
            } finally {
                StrictMode.setVmPolicy(oldPolicy);
            }
        } else {
            launcherApps.startActivityForProfile(intent.getComponent(), user,
                    intent.getSourceBounds(), optsBundle);
        }
        return true;
    } catch (SecurityException e) {      
        ...
    }
    return false;
}

2.Activity启动部分(接下来会用到最开始导入的源码)

2.1 Activity.startActivityForResult
startactivity的几种重载方法都会调用startactivityForResult

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
           @Nullable Bundle options) {
    // mParent 代表的是ActivityGroup(api13废弃),是当前 Activity 的父类,此时条件成立
    if (mParent == null) {
        // 调用 Instrumentation 的 execStartActivity 方法
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this,
               mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
        ...
    } else {
        ...
    }
}

2.2 Instrumentation.execStartActivity

路径: Sdk/sources/android-28/android/app/Instrumentation.java

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
        ...
    try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            // 获取 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;
}

到这里可能会有些懵了,因为获取代理方法的代码和艺术探索里面的api21的有些不同,不过呢,查看ActivityManagerNative类的注释呢可以发现 @deprecated use IActivityManager.Stub.asInterface instead,在api28中由于还是在Launcher进程中,所以呢,这里asInterface获取到的就是AMS的代理对象。

public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

2.3ActivityManagerService.startactivity()

接着我们回到startactivity,现在的话就是调用的AMS的startactivity。其中又调用的startActivityAsUser方法,在这个方法里面,和api21的有所区别,api21是mStackSupervisor的.startActivityMaywait.startActivityMayWait,这里改成了变成了构建者模式,不过这个mActivityStartController的构造方法里面也能发现mStackSupervisor的踪迹

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

    }

构造者模式最后调用的 .execute()方法里面调用了startActivityMayWait。

int execute() {
        try {
            // TODO(b/64750076): Look into passing request directly to these methods to allow
            // for transactional diffs and preprocessing.
            if (mRequest.mayWait) {
                return
                //这里调用startActivityMayWait
                startActivityMayWait(mRequest.caller, ...
            } else {
                return startActivity(mRequest.caller, ...
            }
        } finally {
            onExecutionComplete();
        }
    }

然后在startActivityMayWait中调用了startActivity,其中又调用了一次startActivity,其中的处理过程很比较繁琐,最后会走到ActivityStackSupervisor的resumeFocusedStackTopActivityLocked,然后到ActivityStack

2.4 ActivityStack.resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options); ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }

        return result;
    }

2.5 resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
          if (){
              try {

              } catch (Exception e) {
                  // Whoops, need to restart this activity!
                  mStackSupervisor.startSpecificActivityLocked(next, true, false);
                  if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                  return true;
              }
          }
          else {
            // Whoops, need to restart this activity!

            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }

中间有很多情况的判断,总之就是需要启动的activity没启动的话,就调用StackSupervisor.startSpecificActivityLocked

2.6 StackSupervisor.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);
        getLaunchTimeTracker().setLaunchTime(r);

        if (app != null && app.thread != null) {
            try {
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException 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);
    }

这个ProcessRecord类app代表有关当前正在运行的特定进程的完整信息。 方法中先判断App是否启动,如果启动则执行realStartActivityLocked。如果未启动则调用ActivityManagerService.startProcessLocked方法启动App。
判断条件中的app.thread是interface IApplicationThread extends IInterface,因为继承自IInterface,所以他是一个Binder类型的接口。这个先放着,先看realStartActivityLocked方法。

2.7 StackSupervisor.realStartActivityLocked

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
                ...
                // Create activity launch transaction.
                final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                        r.appToken);
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));
                ...
                // Schedule transaction.
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);
                ...
    }

在scheduleTransaction中会执行LaunchActivityItem.execute

2.8 LaunchActivityItem.execute

 public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }

client是ClientTransactionHandler类,而这个类是抽象类,实现类是ActivityThread。

2.9 ActivityThread.handleLaunchActivity

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ...
        final Activity a = performLaunchActivity(r, customIntent);
        ...
 return a;
    }

这里ruturn了activity,说明这里完成了activity的创建。接下来看performLaunchActivity

2.10 ActivityThread.performLaunchActivity

注释中注明这里是活动启动的核心实现,那我们就仔细点分析下。 该方法主要做了这些事情。

  1. 从ActivityClientRecord获取带启动activity的信息
ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
  1. mInstrumentation.newActivity方法实用类加载器创建Activity
Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        }
  1. makeApplication创建Application,如果Application已经创建过,就不会再创建,说明一个应用只有一个Application(多进程情况除外)。Application穿件完毕后,会调用instrumentation.callApplicationOnCreate(app),这会调用Applicaition的onCreate方法。
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
  1. 创建Contextimpl并通过activity.attach进行数据初始化
ContextImpl appContext = createBaseContextForActivity(r);
appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
  1. 调用mInstrumentation.callActivityOnCreate,这个会调用activity的onCreate,至此点击app图标后activity的启动流程完毕
if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }

巨人的肩膀

《Android艺术开发探索》
虽然说Android版本不同,有些许差别,但是没有书的话,真的会迷失在各种调用里面,无法自拔 Android四大组件之Activity--应用进程与系统进程的通信

总结

其中还有一些部分没有分析完,activity第一次启动的进程创建部分还有和AMS通信的部分,还有详细的时序图,这个就先缓缓,Part2再写吧。

如果有错误的话,可以评论指出。如果觉得文章还不错,帮忙点个赞。