×
广告

Android c/s模式分析Activity启动机制

96
牛晓伟
2018.02.04 23:35* 字数 1418

android中大家经常要接触Activity,比如startActivity或者在Activity的生命周期函数onResume,onPause中做一些事情,既然Activity很重要那我们就来从源码来分析下Activity启动机制

涉及到的类

先看图


Activity启动涉及到的类.png

我以server,client,server与client桥接者三个维度对这些类进行了一个划分。
为啥是这三个维度呢?因为应用程序进程在与系统进程之间进行通信的时候其实它就是一个c/s的模式,系统进程被称为server端,应用程序进程称为client端,当然了android中进程之间的通信用的是binder机制,c与s之间进行通信需要定义一些协议,因此就出现了server与client桥接者。

那我们通过一张图来先对Activity启动有一个大概了解


c/s交互.png

从上图可知:启动一个Activity,就是client进程与server进程之间进行交互的一个过程,client进程通过ActivityManagerNative给server进程发送启动request,server进程中的ActivityManagerService处理完毕后通过ApplicationThread给Client进程response

那我们就从client给server发送request, server处理request,
server给client发送response, client处理response来进行分析

client给server发送request

那我们就先找一个发起启动命令的入口activity.startActivity(intent)方法,那我们就从这个方法入手开始分析

public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
    if (mParent == null) {
        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());
        }
    }
        ......省略代码
}

上面代码展示activity.startActivity(intent)方法最终是调用mInstrumentation.execStartActivity方法来进行启动的,那我们来看这方法

 public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    ......省略代码
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        int result = ActivityManagerNative.getDefault()
            .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) {
    }
    return null;
}

上面代码中出现了ActivityManagerNative这个类,这个类是client给server端的ActivityManagerService发送命令的桥接者,ActivityManagerNative.getDefault() .startActivity其实最终通过binder机制调用ActivityManagerServicestartActivity方法

server处理request

现在client端的命令server端已经收到了,那来看下ActivityManagerServicestartActivity方法

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        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 options, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, userId, null, null);
}

mStackSupervisor.startActivityMayWait这行代码表明最终是调用ActivityStackSupervisorstartActivityMayWait方法来执行启动Activity,看代码

final 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 config,
        Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {
    ......省略代码
    // Don't modify the client's object!
    intent = new Intent(intent);

    // Collect information about the target of the Intent.
    ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
            profilerInfo, userId);

    ActivityContainer container = (ActivityContainer)iContainer;
    synchronized (mService) {
        ......省略代码

        int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                voiceSession, voiceInteractor, resultTo, resultWho,
                requestCode, callingPid, callingUid, callingPackage,
                realCallingPid, realCallingUid, startFlags, options,
                componentSpecified, null, container, inTask);

        ......省略代码
        return res;
    }
}

看下这函数

final int startActivityLocked(IApplicationThread caller,
        Intent intent, String resolvedType, ActivityInfo aInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode,
        int callingPid, int callingUid, String callingPackage,
        int realCallingPid, int realCallingUid, int startFlags, Bundle options,
        boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
        TaskRecord inTask) {
    int err = ActivityManager.START_SUCCESS;
    //调用者的进程信息
    ProcessRecord callerApp = null;
    if (caller != null) {
        callerApp = mService.getRecordForAppLocked(caller);
       ......省略代码
    }

    .......省略代码
   
    //启动当前activity的activity
    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    //同理也是启动当前activity的activity,只不过它需要当前activity把处理结果返回,即通过startActivityForResult方式启动
    if (resultTo != null) {
        sourceRecord = isInAnyStackLocked(resultTo);
        if (DEBUG_RESULTS) Slog.v(
            TAG, "Will send result to " + resultTo + " " + sourceRecord);
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    }

   ......省略掉的代码  进行了各种异常的判断还有各种权限判断
    
    //创建一个启动activity的记录信息
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, this, container, options);

    ......省略代码

    /*把挂起的处理掉*/
    doPendingActivityLaunchesLocked(false);

    //调用该方法进行启动
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
            startFlags, true, options, inTask);

    if (err < 0) {
        // If someone asked to have the keyguard dismissed on the next
        // activity start, but we are not actually doing an activity
        // switch...  just dismiss the keyguard now, because we
        // probably want to see whatever is behind it.
        notifyActivityDrawnForKeyguard();
    }
    return err;
}

上面的代码做的事情有:做了各种异常判断,权限判断;同时创建了ActivityRecord实例,该实例记录了server端启动的Activity的信息,ActivityRecordmToken属性很重要;最终调用startActivityUncheckedLocked方法,那我们来看下该方法

final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
        boolean doResume, Bundle options, TaskRecord inTask) {
   ......省略代码
    /*在ActivityStack种开始启动*/
    targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    if (!launchTaskBehind) {
        // Don't set focus on an activity that's going to the back.
        mService.setFocusedActivityLocked(r, "startedActivity");
    }
    return ActivityManager.START_SUCCESS;
}

该方法的代码实在是太多了,该方法主要做了以下的事情:

  • 找当前正在启动的Activity的存放任务栈

  • SingleTask,SingleTop,SingleInstance启动模式进行处理

  • 找到目标ActivityStack来启动Activity
    targetStack.startActivityLocked方法就是调用ActivityStackstartActivityLocked方法,那来看下该方法

    final void startActivityLocked(ActivityRecord r, boolean newTask,
    boolean doResume, boolean keepCurTransition, Bundle options) {
    TaskRecord rTask = r.task;
    final int taskId = rTask.taskId;
    ......省略的代码主要是把task加入activitystack栈中

    if (doResume) {
        mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
    }
    

    }
    该方法做的事情是:把ActivityRecord加入TaskRecord中;mStackSupervisor.resumeTopActivitiesLocked(this, r, options)又到ActivityStackSupervisor类中的resumeTopActivitiesLocked方法来进行,那看下这方法:

    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
        Bundle targetOptions) {
    
        ......省略代码
    
        result = targetStack.resumeTopActivityLocked(target, targetOptions);
    
        ......省略代码
        return result;
    

    }
    又再次调用ActivityStackresumeTopActivityLocked方法,看该方法

    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
     
        ......省略代码
        boolean result = false;
        try {
         ......省略代码
        result = resumeTopActivityInnerLocked(prev, options);
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }
    return result;
    

    }

resumeTopActivityInnerLocked(prev, options)调用了该方法

  final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
   
        ......省略一大堆代码

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

该方法大致做了通知WindmanagerService进行页面切换等操作,最终还是调用了ActivityStackSupervisor类的startSpecificActivityLocked方法来启动activity,那就来看下这方法

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

    r.task.stack.setLaunchTime(r);

    if (app != null && app.thread != null) {
        try {
            ......省略代码
            //开始真正的启动一个Activity
            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.
    }
    /*进程根本就没启动,这时候进行启动操作*/
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

该方法所做的事情是:查找当前的activity的所在进程是否启动了,没启动则进行启动;否则开始启动activity;针对没启动的情况我们暂时不分析,realStartActivityLocked方法来真正的执行启动activity任务,那来看下代码

  final boolean realStartActivityLocked(ActivityRecord r,
        ProcessRecord app, boolean andResume, boolean checkConfig)
        throws RemoteException {

        ......省略一大堆代码

        /*通知activitythread开始启动activity*/
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
                r.icicle, r.persistentState, results, newIntents, !andResume,
                mService.isNextTransitionForward(), profilerInfo);

    ......省略一小堆代码
    return true;
}

上面的代码我们来详细的分析下:app是一个ProcessRecord对象,app.thread这里的thread就是IApplicationThread的子类ApplicationThread,其实这时候通过binder机制最终调用了ActivityThread里的ApplicationThreadscheduleLaunchActivity方法,这时候会把intent等参数传递给client,参数中又一个很重要的参数r.appToken它是server端的ActivityRecord与client端的ActivityClientRecord对应关系的一个依据

现在server已经给client发送了response

client接收response,处理response

ActivityThreadApplicationThreadscheduleLaunchActivity方法会接收server发过来的response,我们来看下代码

    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
            PersistableBundle persistentState, List<ResultInfo> pendingResults,
            List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
            ProfilerInfo profilerInfo) {

        updateProcessState(procState, false);

        ActivityClientRecord r = new ActivityClientRecord();

        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.referrer = referrer;
        r.voiceInteractor = voiceInteractor;
        r.activityInfo = info;
        r.compatInfo = compatInfo;
        r.state = state;
        r.persistentState = persistentState;

        r.pendingResults = pendingResults;
        r.pendingIntents = pendingNewIntents;

        r.startsNotResumed = notResumed;
        r.isForward = isForward;

        r.profilerInfo = profilerInfo;

        updatePendingConfiguration(curConfig);

        sendMessage(H.LAUNCH_ACTIVITY, r);
    }

上面代码很简单,最终会构造一个ActivityClientRecord对象,该对象是client端的activity封装类,最终会通过Handler的方式来调用ActivityThread里的handleLaunchActivity方法,看下该方法

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......省略代码
    Activity a = performLaunchActivity(r, customIntent);
    .......省略其他代码
}

调用performLaunchActivity方法,看下该方法

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

          ......省略代码

           Activity activity = null;
 
           java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        
  
            ......省略代码

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

            ......省略代码

            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            //必须调用onCreate方法否则抛异常
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }

          ......省略代码

        return activity;
}

代码是在太长了,我就总结下这方法所做的事情:

  • 调用InstrumentationnewActivity方法构造一个Activity实例
  • 若Application没初始化,进行初始化
  • 创建title,appContext等实例
  • 调用Activityattach方法进行初始化
  • 调用InstrumentationcallActivityOnCreate方法,其实最终调用ActivityonCreate方法

到此为止一个Activity就被创建,并且正常调用了,剩下的代码大家感兴趣可以在自行研究,整个Activity启动机制分析到此。

总结

  • 我们最终生成的Activity的实例是在client端存储着,也就是在ActivityThread的mActivities属性中存储着
  • ActivityClientRecord是client端的activity的封装类
  • ActivityRecord是server端的activity的封装类
  • ActivityClientRecord与ActivityRecord之间是一一对应关系,是通过toke即ActivityRecord里的Token对应起来的

下图是ActivityStackSupervisor,ActivityStack,TaskRecord,ActivityRecord之间的关系图


关系图
Android
Web note ad 1