再谈Activity启动流程(1)

前面已经分析过Activity的启动流程,本篇再继续重新整理,深入拓展一番,如有缺漏,敬请谅解。

注:以下分析过程不会贴出所有的代码,在末尾附上的文章里面有详细的代码调用。

部分文件路径
frameworks/base/core/java/android/app/Activity.java
frameworks/base/core/java/android/app/Instrumentation.java
frameworks/base/core/java/android/app/ActivityManagerNative.java
frameworks/base/core/java/android/os/ServiceManager.java
frameworks/base/core/java/android/os/Binder.java(BinderProxy在内部定义)
frameworks/base/core/java/android/view/WindowManagerImpl.java
frameworks/base/core/java/android/view/ViewRootImpl.java
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/java/com/android/server/am/WindowManagerService.java
frameworks/base/services/java/com/android/server/am/Session.java

frameworks/native/cmds/servicemanager/service_manager.c
frameworks/native/libs/binder/BpBinder.cpp
frameworks/native/libs/binder/ProcessState.cpp

一、Activity的启动方式
最开始接触android的时候,接触到的启动一个界面方式是调用startActivity,就和最开始学习编程一样,用最简洁的语句打印hello wolrd,虽然简洁,但其实不简单,下面来介绍一下startActivity到底做了什么。
我们知道桌面也是一个Activity,从桌面点击图标,启动某个应用,其实调用的也是startActivity方法,最终调用到Activity的startActivityForResult方法
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());
            }
           ...
        } 

    ...
}
接着调用Instrumentation的execStartActivity方法
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        ...
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            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) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }
ActivityManagerNative.getDefault()调用的是下面的方法
    static public IActivityManager getDefault() {
        return gDefault.get();
    }

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);//返回为空
        if (in != null) {
            return in;
        }

        return new ActivityManagerProxy(obj);
    }
ActivityManagerNative继承自Binder,因为从 ServiceManager.getService("activity")获取到IBinder对象和当前的Activity对象不在一个进程里面,因此调用asInterface时,实际上返回的是new ActivityManagerProxy(obj)对象。也就是说ActivityManagerNative.getDefault().startActivity
实际上调用的是ActivityManagerProxy对象的startActivity方法。毫无疑问,它是一个代理对象。这里涉及到2个知识点,ServiceManager.getService("activity")获取到的是什么,以及为什么可以通过调用代理对象启动Activity。

二、ServiceManager
2.1 ServiceManager是什么
上面的ServiceManager.java文件并不是具体的实现,具体的实现是在native层。看一下ServiceManager类的getService方法。
   public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

   private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }
前面Binder再探系列文章中也有提到的,BinderInternal.getContextObject()相当于new BinderProxy(),其中BinderProxy的成员变量mObject指向BpBinder,其中BpBinder的handle值为0,上面的getIServiceManager的返回值,是Binder驱动上下文管理者Service Manager的引用。我们要获取服务,首先要将服务在Service Manager中注册。
2.2 服务的注册
上面我们要获取ActivityManagerService(也就是AMS),首先要进行注册,其调用是在SystemServer中,然后调用AMS的setSystemProcess中进行注册。
首先是在SystemServer调用startBootstrapServices
private void startBootstrapServices() {
       ...

        // Set up the Application instance for the system process and get started.
        mActivityManagerService.setSystemProcess();

        ...
 }
然后调用AMS的setSystemProcess进行注册
  public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
            ...
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(
                    "Unable to find android system package", e);
        }
    }
2.3 服务的获取
服务的获取,上面已经看到,传入服务名,然后获取服务对象的Binder引用。

小结:对上述所有过程进行描述和拓展。
开机启动的时候,会启动Service Manager进程和System Server进程,其中Service Manager进程做了如下几件事。
1.打开Binder驱动,此时binder驱动会给Service Manager进程创建一个binder_proc节点,并初始化todo队列
2.申请内存,此时binder驱动会为Service Manager进程创建和传入的数值相等的内核空间(128k),并且分配物理内存(初始只有一页,后面按照最佳匹配算法来动态分配物理内存),并且将Service Manager进程虚拟空间和内核虚拟空间映射到同一块物理空间中,然后把进程虚拟空间和内核虚拟空间之间的偏移地址保存下来,如此其他进程传给Service Manager进程的数据,首先是拷贝到内核空间,然后我们直接通过偏移地址就可以让Service Manager进程访问到这一块的数据了,而不需要从内核空间再拷贝到Service Manager进程中,因此Binder驱动就只需要一次拷贝即可。
3.申请成为服务上下文管理者,此时Binder驱动将会创建一个全局的binder_node指向Service Manager,并且定义handle为0时,指向的就是这个全局的binder_node,于是所有的进程只要是获取handle为0的binder_node一律指向Service Manager。
4.然后开始无限循环读取service manager读写缓存区是否有数据。

System Server进程启动之后,会将服务AMS注册到System Server进程中,这个注册过程做了如下几件事。
1.首先获取Service Manager,刚才提到了Service Manager的binder_node是一个全局的,用handle为0指向这个binder_node,因此上面代码中直接传入handle为0,构造了BpBinder,然后初始化一个BinderProxy作为返回值,其中BinderProxy的成员变量指向BpBinder,之后调用BinderProxy接口,也就会调用到BpBinder接口,最后通过Binder驱动,调用到Service Manager中。
2.我们通过getIServiceManager获取Service Manager引用的时候,Binder驱动会在System Server进程的binder_proc中创建一个binder_ref,指向Service Manager的binder_node。
3.注册Service,通过调用addService,将AMS的服务名和AMS作为参数传入,会调用BinderProxy的transact方法,然后接着调用了BpBinder的transact函数,最后通过IPCThreadState来调用ioctl将数据传入到Binder驱动。
4.Binder驱动收到数据之后,进行解析处理,首先通过handle为0,找到binder_ref节点,然后找到Service Manager的binder_node,也就找到了Service Manager的进程binder_proc节点,然后把刚才传入的数据进行打包,作为一个binder_transaction事务打包到binder_proc的todo队列中(优先扔到binder_thread的todo队列),这里涉及到一次拷贝了,其中还要注意的是,AMS是一个Binder实体,它首先会在System Server进程的binder_proc中创建一个binder_node节点,然后在打包成binder_transaction事务的时候,还要做一次转换,它会在Service Manager进程所在的binder_proc中生成一个最小handle,生成一个binder_ref指向AMS的binder_node,将handle指向这个binder_ref节点,然后讲handle传入到service manager中
5.service manader的读写缓冲区中有了数据之后,将其从todo队列中取出,然后解析数据,获取到服务名和handle,然后把它们打包到一个结构体中(svcinfo),并且放到列表。

服务的获取和上面过程是类似的。
1.首先也是handle为0,获取Service Manager的引用,binder驱动为该进程创建binder_ref指向service manader的binder_node
2.传入服务名,binder驱动把它打包到todo列表中,service manager取出之后,遍历列表,找到这个handle返回
3.binder驱动通过handle找到binder_ref,然后找到服务的binder_node节点,然后又会在当前进程的binder_proc中创建binder_ref节点,
然后生成一个最小未分配handle,指向这个binder_ref,然后讲handle打包到binder_transaction事务中,放到当前进程的todo列表
4.当前进程获取到todo列表数据之后,解析,然后获取到handle,然后封装到BpBinder中,BpBinder的handle也就是这个handle,接着构造一个BinderProxy对象,BinderProxy的成员变量指向这个BpBinder。

回到上面代码中的ActivityManagerNative.getDefault()方法,我们的目的是获取AMS服务的引用,传入了AMS服务名,在binder驱动中(内核层)为该进程所在的binder_proc节点中,创建了binder_ref指向service manager的binder_node、创建了binder_ref指向AMS的binder_node,并且生成了最小未分配handle指向binder_ref节点(binder驱动通过键值对的方式映射),native层构造了BpBinder,让handle作为其构造参数,然后再native反射构造java层的BinderProxy,让其成员(mObject)指向BpBinder,然后返回,这里也解释了obj.queryLocalInterface返回为什么是空的,因为BinderProxy的这个方法返回的就是空值。

public IInterface queryLocalInterface(String descriptor) {
        return null;
 }

因此我们通过ActivityManagerNative.getDefault()获取到了代理对象ActivityManagerProxy,其中BinderProxy作为构造参数传入。

上面的过程,在结尾的附录中,都有对应的文章来说明。
三、Activity的启动
我们开始调用ActivityManagerProxy的startActivity开始启动Activity,附录对于整个java层的代码调用都有了详细的说明,这里只讲解关键的。
    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.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);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);//mRemote是BinderProxy对象
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
ActivityManagerProxy绝对不辜负代理对象的称号,这里它直接把调用扔出去了,核心的地方是下面
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
其中我们知道在构建ActivityManagerProxy的时候,构造方法的参数是BinderProxy,因此这里的mRemote就是BinderProxy对象
接着就是调用BinderProxy的transact方法了。
   public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
        return transactNative(code, data, reply, flags);
    }
然后它调用到了transactNative,这是一个native方法(附录中binder再探(2)中有详细的调用过程),后面一次调用到了BpBinder的transact函数,IPCThreadState的transact函数,然后调用到了内核方法ioctl,内陷进入binder驱动里面的调用了,过程和前面的一样了,通过BpBinder保存的handle,找到binder_ref,然后找到AMS的binder_node,然后封装成binder_transaction事务,插入到system_server进程binder_proc或者binder_thread的todo队列,然后取出来,解析,调用了AMS的binder实体的transact方法,然后就调用到了AMS的startActivity方法。android 7.1和android 6.0在AMS的调用稍微有一些变化,有一部分代码被抽出来放到了新加的ActivityStarter类中,不过过程基本相似,中间的细节不做过多介绍。
在启动Activity的过程中,如果进程没有起来的时候,就会去先启动进程,这一块在附录的进程的启动流程有介绍,主要流程是AMS通过socket和zygote通信,zygote通过fork方式启动一个新的进程,因为fork方式除了后面走的流程不一致,共享库,还有环境都和父进程一致,这样就实现了用最小代价创建一个新进程。同时要说明的还有3点。
1.在调用ActivityThread的main方法之前,在zygote中fork一个新进程之后,有调用nativeZygoteInit,这个流程走下来,会先初始化ProcessState,打开binder驱动,申请内存,设置最大binder_thread个数等,然后开启一个新线程来读binder读写缓存的数据,这也是为什么AMS可以跨进程调用到当前进程的Activity的原因了,这一块在binder初探这篇文章有介绍。
2.ActivityThread 的main方法,最后会调用Looper.loop,这就决定了以后所有运行在主线程的任务只能通过消息模型实现,也可以解释Activity、Service、ContentProvider、BroadcastReceiver的生命周期这些,因为它都是基于消息模型的。
   public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        ...
        Looper.loop();//决定了主线程的所有操作只能基于消息模型

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
3.上面代码中可以看到还有一个比较重要的是 thread.attach,它把ApplicationThread传到了AMS中,至此,AMS就可以通过ApplicationThread来管理四大组件等的生命周期了(ApplicationThread是一个Binder实体),而通过ApplicationThread的调用,并不是在主线程中,在第2点提到的ProcessThread初始化之后,启动的那个线程,因此我们要在主线程使用必须要通过handler,这也就是为什么ActivityThread中,存在一个H的handler的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值