Android Activity启动源码分析 (一)

源码使用API 16进行分析

Demo

创建两个Activity用于源码分析:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.startactivitydemo">
       ...
        <activity android:name=".TargetActivity" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        ...

MainActivity.java:

...
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, TargetActivity.class));
            }
        });
    }
}

TargetActivity.java:

...
public class TargetActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_target);
    }
}
...

向AMS发送startActivity请求

App启动Activity时,需要向系统发送请求启动信号,处理该请求的服务称为AMS(ActivityManagerService)。这里的跨进程操作发生在App进程和系统进程之间。
从onClick中的startActivity开始分析:
android.app.Activity#startActivity(android.content.Intent):

    @Override
    public void startActivity(Intent intent) {
        startActivity(intent, null);
    }

android.app.Activity#startActivity(android.content.Intent, android.os.Bundle)

    @Override
    public void startActivity(Intent intent, Bundle options) {
        if (options != null) {
                        ...
        } else {
            startActivityForResult(intent, -1);
        }
    }

android.app.Activity#startActivityForResult(android.content.Intent, int):

    public void startActivityForResult(Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
    }

android.app.Activity#startActivityForResult(android.content.Intent, int, android.os.Bundle):

    public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
    ...
      //mParent的使用场景很古老了,通常都是null
      if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            //ar始终是null,详见下文
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
        } else {
    ...
    }

android.app.Instrumentation#execStartActivity(android.content.Context, android.os.IBinder, android.os.IBinder, android.app.Activity, android.content.Intent, int, android.os.Bundle):

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        if (mActivityMonitors != null) {
           //InstrumentationTest相关逻辑
           ...
        }
        try {
           ...
           //这里向AMS发送启动信号
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, null, options);
            //处理AMS返回值
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }

跨进程发生在ActivityManagerNative.getDefault().startActivity(...)中,紧接着会对跨进程的返回值做处理。不考虑InstrumentationTest逻辑,该函数始终返回null。
android.app.Instrumentation#checkStartActivityResult:

static void checkStartActivityResult(int res, Object intent) {
        if (res >= ActivityManager.START_SUCCESS) {
            return;
        }
        
        switch (res) {
            case ActivityManager.START_INTENT_NOT_RESOLVED:
            case ActivityManager.START_CLASS_NOT_FOUND:
                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                    throw new ActivityNotFoundException(
                            "Unable to find explicit activity class "
                            + ((Intent)intent).getComponent().toShortString()
                            + "; have you declared this activity in your AndroidManifest.xml?");
                throw new ActivityNotFoundException(
                        "No Activity found to handle " + intent);
            case ActivityManager.START_PERMISSION_DENIED:
                throw new SecurityException("Not allowed to start activity "
                        + intent);
            case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                throw new AndroidRuntimeException(
                        "FORWARD_RESULT_FLAG used while also requesting a result");
            case ActivityManager.START_NOT_ACTIVITY:
                throw new IllegalArgumentException(
                        "PendingIntent is not an activity");
            default:
                throw new AndroidRuntimeException("Unknown error code "
                        + res + " when starting " + intent);
        }
    }

ActivityManager.START_SUCCESS的值是0,App进程无需处理返回值。其他的情况则依据返回值抛出对应的异常。当启动一个没有在xml中声明的,或者无权限启动的Activity,App会Crash,便是在这里产生的。

AMS跨进程发送信号

下面分析:ActivityManagerNative.getDefault().startActivity(...):

    ...
    static public IActivityManager getDefault() {
        return gDefault.get();
    }
    ...
        private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            //通过系统ServiceManager获取AMS句柄
            IBinder b = ServiceManager.getService("activity");
            ...
            //将句柄转换成IActivityManager接口,实际上是android.app.ActivityManagerProxy实例
            IActivityManager am = asInterface(b);
            ...
            return am;
        }
    };

可以看到ActivityManagerNative.getDefault()是个单例,返回值是从ServiceManager.getService("activity")中获取的。asInterface会检查Binder是否跨进程了,若跨进程了,会把IBinder封装成android.app.ActivityManagerProxy。Binder是Android实现跨进程的主要方式。
因此会调用到android.app.ActivityManagerProxy#startActivity中:

    public int startActivity(IApplicationThread caller, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, String profileFile,
            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        //Parcel data写入要传递给AMS的数据 start
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        data.writeString(profileFile);
        if (profileFd != null) {
            data.writeInt(1);
            profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        //Parcel data写入要传递给AMS的数据 end
        //跨进程
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        //reply是AMS所在进程返回的数据,检查是否需要处理异常
        reply.readException();
        //读取返回结果
        int result = reply.readInt();
        //回收Parcel
        reply.recycle();
        data.recycle();
        return result;
    }

该函数向AMS发送了跨进程数据,且获得了AMS的返回数据,一次握手就完成了。Parcel是配合Binder使用的,用于承载跨进程数据结构的,是Native实现。

startActivity跨进程传递的参数

android.app.ActivityManagerProxy#startActivity中的参数较多,这里单独分析一下:

  • caller:android.app.ActivityThread.ApplicationThread对象,用于区分请求方进程,当前的请求方就是当前APP进程。
  • intent:启动意图,表示要启动什么,怎么启动
  • resolvedType::Intent中包含的type,和当前场景无关
  • resultTo:android.app.Activity#mToken传递过来的,用于区分发起请求的Activity,也可以理解为:AMS要返回数据的接收方
  • resultWho:场景无关的参数,可不关心
  • requestCode:startActivityForResult时的requestCode,当前场景是-1,场景无关
  • startFlags:当前传入的0,场景无关
  • profileFile:当前传入null,场景无关
  • profileFd:当前传入null,场景无关
  • options:启动Activity的一些其他参数,当前场景是null,场景无关
  • START_ACTIVITY_TRANSACTION:AMS接收的操作有很多,它标识了当前是startActivity操作

核心参数是caller、START_ACTIVITY_TRANSACTION和intent、resultTo,分别阐述了:

  • 谁发起了请求?
  • 要请求什么?
  • 请求返回数据给谁?

总结

startActivity由App进程中发起,发向AMS,第一次握手的由此开始。App进程侧逻辑简单,系统进程中AMS的处理才是主角。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。