Android Activity的启动流程(Android-10)

前言

在Android开发中,我们经常会用到startActivity(Intent)方法,但是你知道startActivity(Intent)后Activity的启动流程吗?今天就专门讲一下最基础的startActivity(Intent)看一下Activity的启动流程,同时由于Launcher的启动后续和这里基本类似,就记录在一起。注意本章都是基于Android-10来讲解的。

客户端startActivity启动流程

startActivity启动流程本质上就是:向ActivityManagerService发送启动请求。由于发送端基本是在当前用户App进程或者Launcher进程(从桌面启动新的App)。除了SystemServer启动Launcher外,都需要借助AIDL发送请求。

1:客户端启动流程

startActivity方法在Activity,startActivity有两个重载方法,最终都会调用startActivityForResult(Intent,int, Bundle)方法,代码如下:

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

        if (options != null) {
   
   
             mParent.startActivityFromChild(this, intent, requestCode, options);
         } else {
   
   
             mParent.startActivityFromChild(this, intent, requestCode);
         }
     }
}

其中mParent是当前Activity的父Activity,目前我只能想到TabActivity场景下才会存在一个Activity中包含Activity的情况,虽然它已经被Fragment替代了。所以基本上代码都是走mParent == null的流程,调用Instrumentation的execStartActivity方法。当然,在startActivityFromChild 方法里也是如此(不难发现,该方法已经被废弃了),源码如下,俩个重载的方法均已经废弃:

    /** @deprecated */
    @Deprecated
    public void startActivityFromChild(@NonNull Activity child, Intent intent, int requestCode) {
   
   
        throw new RuntimeException("Stub!");
    }

    /** @deprecated */
    @Deprecated
    public void startActivityFromChild(@NonNull Activity child, Intent intent, int requestCode, @Nullable Bundle options) {
   
   
        throw new RuntimeException("Stub!");
    }

我们继续看execStartActivity方法的关键代码:

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
   
   
     //...
     try {
   
   
            intent.migrateExtraStreamToClipData(who);
            intent.prepareToLeaveProcess(who);
            	//备注一
            int result = ActivityTaskManager.getService().startActivity(whoThread,
                    who.getBasePackageName(), who.getAttributionTag(), 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;
}

其中,备注一处就是获取ActivityTaskManager服务并向其发送请求。备注二处会根据备注一处的返回结果检查Activity的启动状态,源码如下:

public static void checkStartActivityResult(int res, Object intent) {
   
   
        if (!ActivityManager.isStartResultFatalError(res)) {
   
   
            //如果没法发生启动错误,直接返回
            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");
            //...
            default:
                throw new AndroidRuntimeException("Unknown error code "
                        + res + " when starting " + intent);
        }
}

可以看到checkStartActivityResult在Activity里会根据启动失败的原因并抛出异常:注意里面的case ActivityManager.START_CLASS_NOT_FOUND,你一定知道如果没有在AndroidManifest.xml文件里声明Activity,就会抛出异常。没错,就是根据AMS返回的错误码,在这里抛出的异常。

当然,检查并不是在这里。checkStartActivityResult不负责任何启动Activity以及检查配置文件的工作,它之负责根据AMS的返回结果抛出异常。接下来回到备注一,看一下重点工作 ActivityTaskManager的getService方法

public static IActivityTaskManager getService() {
   
   
        return IActivityTaskManagerSingleton.get();
    }

@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
   
   
                @Override
                protected IActivityTaskManager create() {
   
   
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
            }
     };

代码比较简单,一个匿名内部类IActivityTaskManagerSingleton,里面的create 方法返回了一个IActivityTaskManager对象,根据方法里的内容就能猜出它个AIDL,该AIDL文件可在IActivityTaskManager源码里查看。

接着看一个ActivityTaskManagerSingleton.get()方法,get方法在它的父类Singleton中定义:

public abstract class Singleton<T> {
   
   

    @UnsupportedAppUsage
    public Singleton() {
   
   
    }

    @UnsupportedAppUsage
    private T mInstance;

    protected abstract T create();

    @UnsupportedAppUsage
    public final T get() {
   
   
        synchronized (this) {
   
   
            if (mInstance == null) {
   
   
                mInstance = create();
            }
            return mInstance;
        }
    }
}

很简单的代码,一个懒汉式单例。如果实例为空,就调用create()方法,也就是上文中匿名内部类中复写的方法。到这里,一切就明了了:这里就准备开始跨进程通讯了ActivityTaskManager.getService方法就是客户端(发起创建Activity的当前App进程)向服务端(AMS)获取获取Binder对象用于跨进程通讯。而关键代码就是IActivityTaskManager.Stub.asInterface(b)。(注意IActivityTaskManager只是个AIDL文件,是为了自动生成代码的工具,更多关于AIDL的知识请看Android里的多进程和跨进程通讯方式)

接下来看final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);,看它是如何获得Binder实例的:

private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();

public static IBinder getService(String name) {
   
   
    try {
   
   
            IBinder service = sCache.get(name);
            if (service != null) {
   
   
            // 有缓存,直接从缓存获取
                return service;
            } else {
   
   
            // 没有缓存重新通过ServiceManager获取
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
   
   
            Log.e(TAG, "error in getService", e);
        }
        return null;
}

上面是ServiceManager.getService方法的代码。ServiceManager是Android用来关系系统服务的,Android系统给我们提供了很多服务,每一个服务都有一个对应的类(AMS,WMS等),开发过程中我们就是通过这些类来获得我们所需要的服务。而ServiceManager则通过一个ArrayMap来缓存这些服务。这里也是如此:getService(Context.ACTIVITY_TASK_SERVICE)不难看出是要获得ActivityTaskManagerService的。看一下ActivityTaskManagerService:
在这里插入图片描述

它继承了IActivityTaskManager.Stub!!!就和上文中我们的AIDL文件对应上了。可以肯定ActivityTaskManagerService就是这次AIDL跨进程通讯的服务端了。

为了以防万一,我们还是要追踪一下ActivityTaskManagerService是如何添加到ServiceManager中的。这时,我们就要了解一下Android系统的启动流程了:ActivityTaskManagerService作为系统服务,是在SystemServer中被启动的:

 ActivityTaskManagerService atm = mSystemServiceManager.startService(
                ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
                mSystemServiceManager, atm);

其中SystemServiceManager.startService是通过反射创建Service的:

public <T extends SystemService> T startService(Class<T> serviceClass) {
   
   
        try {
   
   
            final String name = serviceClass.getName();
            //..
            final T service;
            try {
   
   
            		//通过反射创建实例
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            } catch (InstantiationException ex) {
   
   
                throw new RuntimeException("Failed to create service " + name
                        + ": service could not be instantiated", ex);
            } 
            //...
		//启动服务
            startService(service);
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值