android-App启动过程

前言
APP启动流程涉及的类和调用的方法还是蛮多的,做为android应用开发其实知道整个流程和重要的调用方法就够了。但是在了解整个流程前,得先知道涉及的相关知识,这样才能更好理解后面整个流程。后面源码分析基于Android-2.2_r1。

Zygote
zygote名字翻译叫受精卵,首先要知道zygote进程的创建是由Linux系统中init进程创建的,Android中所有的进程都是直接或者间接的由init进程fork出来的,Zygote进程负责其他进程的创建和启动,比如创建SystemServer进程。当需要启动一个新的android应用程序的时候,ActivityManagerService就会通过Socket通知Zygote进程为这个应用创建一个新的进程

Launcher
我们要知道手机的桌面也是一个App我们叫它launcher,每一个手机应用都是在Launcher上显示,而Launcher的加载是在手机启动的时候加载Zygote,然后Zygote启动SystenServer,SystenServer会启动各种ManageService, 包括ActivityManagerService,并将这些ManageService注册到ServiceManage 容器中,然后ActivityManagerService就会启动Home应用程序Launcher.

ActivityManagerService
ActivityManagerService我们简称AMS,首先当我们看到名字的时候,我们以为他是管理Activity的,其实四大组件都归它管,四大组件的跨进程通信都要和它合作,后面讲Binder时候会提到它。
AMS管理Activity主要是管理什么呢? 这就要说到AMS的相关类:

ProcessRecord 表示应用进程记录,每个应用进程都有对应的ProcessRecord对象
ActivityStack 该类主要管理回退栈
ActviityRecord 每次启动一个Activity会有一个对应的ActivityRecord对象,表示一个Activity的一个记录
ActivityInfo Activity信息,比如启动模式,taskAffinity,flag信息
TaskRecord Task记录信息,一个Task可能有多个ActivityRecord,但是一个ActivityRecord只能属于一个TaskRecord
Binder
Binder是Android跨进程通信(IPC)的一种方式,也是Android系统中最重要的特性之一,android 四大组件以及不同的App都运行在不同的进程,它则是各个进程的桥梁将不同的进程粘合在一起。
学习Binder首先要知道相关客户端、服务端的概念,然后去把AIDL弄透彻, 知道系统生成的Aidl Java文件中每一个类所代表的是什么角色,然后看源码,能将ActivityManageService 用来跨进程同通信中各个角色弄明白就算是理解了,不过这只是一部分部分,得多总结归纳。

ActivityThread
首先ActivityThread并不是一个Thread,其作用就是在main方法内做消息循环。那我们常说的主线程是什么?主线程就是承载ActivityThread的Zygote fork而创建的进程 ,这里可能有人会不能理解进程和线程的区别,这里不详细讲述自行学习。ActivityThread的调用是在ActivityManageService.startProcessLocked()方法里调用并创建,这个类主要做了这几个事

创建Looper,开启Looper循环
创建内部类 H,H继承于Handler 用于跨进程通信切换线程
创建ApplicationThread跨进程Binder对象mAppThread。 这里要说一点,ActivityThread通过ApplicationThread与AMS进行通信,ApplicationThread通过H与ActivityThread进行通信(handler机制),处理Activity的事务
启动方式
app的启动我们将其分为两种:

冷启动:当应用启动的时候,后台没有当前应用的进程,这时系统会创建一个新的进程分配给应用。
热启动:当前应用已经打开,但是被按下返回键或者Home键退出到桌面或者去到其他App,当再次回到应用时就是热启动。
这里我们主要介绍冷启动过程,首先简单介绍下冷启动的的整个流程,然后再根据关键代码讲解。
App启动5步走
借用GITYUAN大神的一张图结合启动App逻辑讲一下App启动的整个流程,不过这是一张Launcher App启动的图,和我们要说的有点不一样,我们根据老罗所说的将App启动分为5步

Launcher通过Binder进程间通信机制通知ActivityManagerService,
它要启动一个Activity;
ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态, 于是ActivityManagerServicey利用Zygote.fork()创建一个新的进程,用来启动一个ActivityThread实例, 即将要启动的Activity就是在这个ActivityThread实例中运行;
ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,
以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
ActivityManagerService通过Binder进程间通信机制通知ActivityThread,
现在一切准备就绪,它可以真正执行Activity的启动操作了。

第一步1-3
Launcher的点击监听
首先我们在物理上点击了手机屏幕上的App快捷键图标,这里Launcher是这么操作的呢?我看位于android.launcher2下的源码Launcher

1、 这里可以看到,Launcher继承于Activity,并在其onClick()事件中监听了app的图标点击,调用了Launcher的startActivitySafely()方法


public final class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
...

 /**
     * Launches the intent referred by the clicked shortcut.
     *
     * @param v The view representing the clicked shortcut.
     */
    public void onClick(View v) {
        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            // Open shortcut
            final Intent intent = ((ShortcutInfo) tag).intent;
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0], pos[1],
                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
            startActivitySafely(intent, tag);
        } else if (tag instanceof FolderInfo) {
            handleFolderClick((FolderInfo) tag);
        } else if (v == mHandleView) {
            if (isAllAppsVisible()) {
                closeAllApps(true);
            } else {
                showAllApps(true);
            }
        }
    }
...

}

2、这里将这个启动方式使用Intent.FLAG_ACTIVITY_NEW_TASK, 创建了一个新的TASK栈,然后继续调用父类ActivitystartActivity()方法

 void startActivitySafely(Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
        } catch (SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Launcher does not have the permission to launch " + intent +
                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
                    "or use the exported attribute for this activity. "
                    + "tag="+ tag + " intent=" + intent, e);
        }
    }

3、Activity的startActivity()方法中传递了默认为-1的requestCode,表示不需要返回值,然后调用了startActivityForResult(),在这个方法中我们看到一个mInstrumentation变量,这个变量是Instrumentation对象的实例,具体是在Activity的attach()方法中进行赋值的。然后startActivityForResult()方法中调用了mInstrumentation.execStartActivity()方法,然后在其中传递了两个参数我们要介绍下,

mMainThread.getApplicationThread():mMainThread变量声明是 ActivityThread对象,而getApplicationThread()方法则返回的是ApplicationThread的实例。
mToken :的声明为 private IBinder mToken;
这里为什么传递这两个参数我们后面说,我们继续看execStartActivity()方法。

 @Override
    public void startActivity(Intent intent) {
        startActivityForResult(intent, -1);
    }
public void startActivityForResult(Intent intent, int requestCode) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }

第二步4-7
4、我们继续看位于android/app/Instrumentation.java中的execStartActivity方法,最后调用了ActivityManagerNative.getDefault().startActivity()方法,就要和AMS进行Binder的ICP通信了,AMS会收到startActivity的请求,执行startActivity()方法。
 

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode) {
      IApplicationThread whoThread = (IApplicationThread) contextThread;
      if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i = 0; i < N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        int result = ActivityManagerNative.getDefault().startActivity(whoThread, intent,
            intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token,
            target != null ? target.mEmbeddedID : null, requestCode, false, false);
        checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}

5、首先我们知道Launcher本来就是一个Activity,并单独处于一个进程中,现在要启动另一个我们所点击的APP的Activity,而AMS是管理所有Activity的,那么我们就会和AMS使用Binder进行跨进程通信。
这里我们也具体了解下是谁和AMS进行跨进程通信?
使用Binder进行通信,就首先得有Server进程和Client进程,
首先Server会提供一套接口函数供Client调用,这个时候通常会采用Proxy设计模式。将接口定义在一个抽象类中,Server和Client都会以该抽象类为基础实现所有函数。 而在Client端会具有Server端的代理对象Proxy,Proxy具有和Server一样的方法,Client使用代理对象经过Binder的转换,跨进程调用Server的服务。具体理解这一块先看看AIDl相关。

再回到步骤4 的ActivityManagerNative.getDefault().startActivity()方法,这个方法后面调用asInterface()然后返回ActivityManagerProxy对象,这个对象其实就是AMS在客户端的代理对象,ActivityManagerProxy实现IActivityManager接口,具有AMS所提供的方法,不同的是,ActivityManagerProxy并没有实现方法,ActivityManagerProxy只是将客服端发起的请求进行参数进行打包封装,并在每一个方法中添加唯一表示,然后将请求发送到Binder,Binder就会将请求转发给server,server根据唯一表示调用相应的server的相关方法。
再看下AMS:AMS继承了ActivityManagerNative同样实现了IActivityManager接口。这里就能

也就是说与AMS通信的其实是AMS的代理对象ActivityManagerProxy,通过:ActivityManagerProxy -> Binder驱动 -> AMS
 

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {}

public abstract class ActivityManagerNative extends Binder implements IActivityManager{}

class ActivityManagerProxy implements IActivityManager{}


private final class ApplicationThread extends ApplicationThreadNative {}
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
。。。
 static public IActivityManager getDefault()
    {
      ...
        IBinder b = ServiceManager.getService("activity");
        if (Config.LOGV) Log.v(
            "ActivityManager", "default service binder = " + b);
        gDefault = asInterface(b);
      ...
        return gDefault;
    }


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

class ActivityManagerProxy implements IActivityManager{}
...
}

6、Activity通过Binder将消息传递到了AMS,AMS的startActivity()方法接收到方法开始一系列的调用,这里整个AMS会做几个操作

对参数intent的内容进行解析,保存到ResolveInfo对象中
从传进来的参数得到调用者的进程信息,保存到ProcessRcord对象中,这里获取的就是Launcher应用程序的进程
创建即将要启动的Activity的相关信息 保存到ActivityRecord对象
根据intent的参数设置启动模式,并创建一个新的Task来启动这个Activity
将创建的Task保存到ActivityManagerService
将Launcher推入Paused状态

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值