×

第二章 深入启动虎穴

96
Me豪
2017.07.29 17:40* 字数 3021

tips:部分读者可能对此文会引起不适,若有此感,敬请跳过。

“我就知道你还会再来的,说吧,这次想学习什么?”,还没等我出声,Story大神就开口了,“上一次我进来是学到了不少知识,而且app启动也优化了不少,但是这些都是表面的知识,我在优化的过程中突然就想到了,我点击图标的时候,app是怎么启动起来的?”我充满疑问的问道,“哈哈,我就知道你是孺子可教也,你确定要深入虎穴吗?这可是比较烧脑的环节哦!”,“确定!”,我想都没想就回答了,为了追求未知的知识,我还是比较坚定的。

虎穴,打开!

就在这时,一堆代码仿佛像挣脱了缰绳的马一样飞奔而来,并且整齐的列好队排列在我眼前。“请大家自我介绍一下”,Story大神对它们说道。

“你好,我是 Zygote,我是Android系统创造出来的,而我的作用就是为Android系统生孩子。

“我叫 ActivityManager,一听我的名字就知道我是一个Activity管理层(不单单是Activity的管理,更是其他三大组件的管理者),无论是创建还是跳转,都要经过我的审判,才能继续下去,也就是说我掌握着Activity的生死大权。还有,你看到站在我身边的都是我的手下,我左边的这个是 IActivityManager,它就是对我的命令进行了封装装饰,我右手边的是 ActivityManagerProxy ,它就是对封装装饰好的命令进行下传的,而我后面的那位是 ActivityManagerService ,它就是要对命令执行的人了,别看我衣着光鲜,其实还是挺累的,一个个 代理 着我的命令进行传递。”

“大家好,我叫 ActivityThread , 我的职责是管理应用进程的主线程的执行,比如快速处理UI界面的变化,还有一些需要在主线程上调度都是我的管辖范围。”

“我是 Process ,想要进程,就来我这里申领吧。”

听着它们讲了一大堆,我一直在点头,其实我内心是懵逼的,这是什么跟什么啊。貌似Story大神看出了我的疑问,就对我说了,“是不是没听懂它们在说什么?”,我点点头,“哈哈,来吧,走进它们的世界看一下你就会了如指掌的了,过来吧,”我还是心怀疑虑的走了过去。

简直是走进了Android系统的五章六腑,各个部门配合紧密,处理速度之迅猛。“到了”,Story大神带我走进了一个类似车间的一个工作室,眼前的那一幕是我从所未见的,当然,自从进来这里之后,每次都会刷新我的世界观和人生观!

刚刚还在自我介绍的它们,现在已经在认真地工作中了,Zygote 正在分裂复制着(fork),真的像它刚刚介绍的那样,在生孩子,所有的应用程序的进程都是又它生出来的。这时候从中间浮出一段文字。

应用程序的运行,都是基于 Android的虚拟机,而且每次启动都会带来很大的开销,而 Zygote 的生产方式则能够提升不小的效率。在这个生产的过程中,采用了Linux 的 写时拷贝技术 Copy-on-Write 的方式,重复利用了 Zygote 上的资源,达到了最大的效率。

首先, Zygote 会开启一个Socket:registerZygoteSocket(socketName),也就是Zygote Socket,这个Socket就是去监听应用程序的请求的,当有请求的话就会立刻通知 Zygote 进行生产,同时还启动了 SystemServer

SystemServer ?这又是什么来的?“刚刚因为它太忙了,所以没出来跟你打招呼,现在跟你介绍一下它吧”。

SystemServer ,是 Zygote 的大儿子,在生产过程中扮演中无比重要的角色,正如其名,系统中的所有服务都与它有着密切的关系,而且整个Android中的核心Service都在其中,比如刚刚跟你介绍的 ActivityManagerServiceZygote 统管着后宫大权(生孩子),而 SystemServer 则是名副其实的一人之上万人之下的统治者了!

紧接着, ActivityManager 出现了,只见最上层的编码者(就是我了),点击了app,这时, ActivityManager 开发工作了,发出 startActivity(intent) 的命令,app启动了,而在系统中,又多了一个进程出来,而系统又是一个进程,那么这个命令就由中间的管理服务者
ActivityManagerService来调度了,而这是属于两个进程间的通信,又设计到了跨进程通信了(IPC)。

掌权者 ActivityManager 是所有人都能看得到权力所有者,对接着所有的程序员,下发了命令之后通过 IActivityManager 的修饰封装,比如 startActivityfinishActivity等命令,通过 ActivityManagerProxy 把命令传递到执行者 ActivityManagerService 手中,再进行相应的处理。

还不明白吗?我们从上至下再详细讲解下这个流程吧。

当我们点击App时,调用了Activity的startActivity,接着调用了startActivityForResult。

    @Override
    public void startActivity(Intent intent) {
       this.startActivity(intent, null);  //  <------调用
    }
    
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);  //  <------调用
        } else {
            startActivityForResult(intent, -1);
        }
    }
    
    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);//  <------调用  来到这里: mInstrumentation.execStartActivity!!!
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }

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

看到代码,会调用startActivityForResult中的 mInstrumentation.execStartActivity,那这个Instrumentation又是有什么作用的呢?一环套着一环!

远处慢慢飘来Instrumentation的介绍。

Base class for implementing application instrumentation code. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's <instrumentation> tag.

这个是Android系统对它的一个定义,说了什么呢?我们来翻译一下,现在知道英语好的重要性了吗?

用于实现应用程序代码的基类。当使用Instrumentation进行运行时,该类将在任何应用程序代码之前为您实例化,允许您监视系统与应用程序之间的所有交互。Instrumentation实现了系统通过AndroidManifest. xml的<instrumentation>标签。

简单来说 Instrumentation ,它拥有强大的跟踪Application以及Activity生命周期的功能,而且一个应用有且仅有一个 Instrumentation,并且每个Activity都有一个 Instrumentation 的引用。ActivityThread 要创建或暂停某个Activity时,都需要通过 Instrumentation 来进行具体的操作。

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(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) {
        }
        return null;
    }

我们又发现了 startActivity 这个方法,刚刚我们说到了, Instrumentation 拥有强大的跟踪Application以及Activity生命周期的功能,那么说吧,它就是完成对Application以及Activity初始化和管理生命周期的一个大管家,我就举几个例子给你看看,什么叫证据!

    public void callActivityOnStart(Activity activity) {
        activity.onStart();
    }
    
    public void callActivityOnRestart(Activity activity) {
        activity.onRestart();
    }
    
    public void callActivityOnResume(Activity activity) {
        activity.mResumed = true;
        activity.onResume();
        
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    am.match(activity, activity, activity.getIntent());
                }
            }
        }
    }

这些方法都是Acitivity生命周期的方法吧?所以说,Instrumentation 是非常重要的,但是,你会发现,这个 Instrumentation 非常重要,你在编程的时候有用到这个东西吗?并没有,可见它只是在背后默默地做出自己的奉献!

介绍完 Instrumentation ,我们再回到 execStartActivity 这个方法,出现了一个新面孔 ActivityManagerNative ,直接来看下它的代码实现吧。

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
    /**
     * 将绑定对象插入活动管理器接口,如果需要生成代理。
     */
    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);  //  <------获取到了一个ActivityManagerProxy对象,而且传递了一个IBinder进去,这个IBidder就是用来进行IPC通信的。
    }

    /**
     * 检索系统的默认/全局活动管理器。
     */
    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;
        }
    };

从上面的代码我们可以了解到 ActivityManagerNative 是 Binder的一个子类,并且实现了IActivityManager 这个接口,得到 ActivityManagerProxy 这个对象,正如上面我们所说的:

下发了命令之后通过 IActivityManager 的修饰封装, startActivity 这个命令,通过 ActivityManagerProxy 把命令传递到执行者 ActivityManagerService 手中,再进行相应的处理。

我们已经到达了命令封装,然后叫给传达者 ActivityManagerProxy 这一步,接下来就是看传达者 ActivityManagerProxy 如何将命令交给执行者 ActivityManagerService 了。

我们走近一步,来瞧一瞧 ActivityManagerProxy 中的startActivity()方法是如何编写的。

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);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

相信你也可以看到,通过传到 ActivityManagerProxy 的IBinder,利用这个对象,调用了transact()方法,把所有参数封装成了Parcel对象,这样就向 ActivityManagerService 发射信号弹,进行通信了,执行者 ActivityManagerService 收到指令后立马进行了处理。

我深吸一口气,什么 ProxyActivityManagerService 等等一直在我脑海里回旋,突然想起了一个设计模式好像就是这样的啊,就是那个叫代理模式的。

代理:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

对,就是这样的,看来今天的知识要好好消化一下了。

“等等,先别想其他的,你以为到这一步就结束了吗?刚刚才到执行者这边呢,还有一段路要走啊,我们接着看吧”,还有啊...我当时的内心是崩溃的,还以为就这样结束了。

ActivityManagerService 接收到指令之后,正式开始启动Activity,这时,ActivityManagerService 要作出严格的审核过程。只见它把指令转换为了 ResolveInfo

ResolveInfo:从一个intent对应的IntentFilter所解析获取的信息。这部分地对应于从AndroidManifest .xml的<intent>标签。

然后 ActivityManagerService 调用 startActivityLocked() 方法进行下一步,再来到startSpecificActivityLocked() 方法,这时候就需要判断是否需要创建一个全新的进程,如果需要则调用startProcessLocked() 方法进行创建,而在这个方法的内部有一个Process.start的方法,这个时候正式到了我们的 ActivityThread 的工作,还记得在介绍 Zygote 时,它会打开一个Socket来监听需要创建 Process 的请求吗? Zygote 会不断取出建立的连接,再进行 fork 进程,这就是我们的应用进程了,而且返回了每个进程所对应的 process id,这时就回到了 ActivityThread ,众所周知的UI线程,进行处理页面的显示,它将和 ActivityManagerService 配合,一起完成接下来的工作,比如activity的管理。到此,整个应用启动完毕,所有的工作就告一段落了。

赠一个高清大图!

图一

虎穴,关闭!

“好了,本章的学习就要结束了,回去好好回味一下吧,老规矩,我还是要提一个问题给你,不过这个问题你可以回去好好想想的,不用着急回答我”。

既然,我们从底层去学习了整个app的启动过程,那对于上一章所讲到的优化启动时间有什么作用呢?

我带着整个问题回到了现实,只是,这一次回来之后感觉头脑一片模糊,知识量对于我这种新手来说确实是大了些,只能在以后的编程路上不断去琢磨了。

为了进步,只能不断地学习和总结!

AndroidStory
Web note ad 1