Android Activity应用窗口的创建过程分析

前言

所谓的窗口(Window)就是一个显示在手机屏幕上可视化视图的一片区域。在Android中窗口是一个抽象的概念,每一个Activity就对应着一个窗口,而所有的窗口都是由视图(View)来呈现,而我们知道View构成的一个树形结构的视图就组成了一个Activity的界面了。在Android系统中窗口分为三个类型:

  1. 应用窗口:所谓应用窗口指的就是该窗口对应一个Activity,因此,要创建应用窗口就必须在Activity中完成了。
  2. 子窗口:所谓子窗口指的是必须依附在某个父窗口之上。
  3. 系统窗口:所谓系统窗口指的是由系统进程创建,不依赖于任何应用或者不依附在任何父窗口之上。

在WindowManager类的内部类LayoutParams中定义了以上三种窗口类型,我们暂且不管WindowManager类是干嘛的,直接看其内部类LayoutParams的实现。内部类LayoutParams其实是一组用于描述窗口(Window)参数的数据类,其中包括窗口的大小,类型,特征,软键盘输入法模式,相对位置以及动画,背景图像格式等等。

1.窗口参数WinsowManager#LayoutParams

public interface WindowManager extends ViewManager {
    ...........
    public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable {

        //窗口的起点坐标
        public int x;
        public int y;

        //以下定义都是描述窗口的类型
        public int type;
        //第一个应用窗口
        public static final int FIRST_APPLICATION_WINDOW = 1;
        //所有程序窗口的base窗口,其他应用程序窗口都显示在它上面
        public static final int TYPE_BASE_APPLICATION   = 1;
        //所有Activity的窗口
        public static final int TYPE_APPLICATION        = 2;
        //目标应用窗口未启动之前的那个窗口
        public static final int TYPE_APPLICATION_STARTING = 3;
        //最后一个应用窗口
        public static final int LAST_APPLICATION_WINDOW = 99;

        //第一个子窗口
        public static final int FIRST_SUB_WINDOW        = 1000;
        // 面板窗口,显示于宿主窗口的上层
        public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
        // 媒体窗口(例如视频),显示于宿主窗口下层
        public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
        // 应用程序窗口的子面板,显示于所有面板窗口的上层
        public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2;
        //对话框窗口
        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
        //
        public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4;
        //最后一个子窗口
        public static final int LAST_SUB_WINDOW         = 1999;

        //系统窗口,非应用程序创建
        public static final int FIRST_SYSTEM_WINDOW     = 2000;
        //状态栏,只能有一个状态栏,位于屏幕顶端,其他窗口都位于它下方
        public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
        //搜索栏,只能有一个搜索栏,位于屏幕上方
        public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
        //电话窗口,它用于电话交互(特别是呼入),置于所有应用程序之上,状态栏之下
        public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
        //系统警告提示窗口,出现在应用程序窗口之上
        public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
        //锁屏窗口
        public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
        //信息窗口,用于显示Toast
        public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
        //系统顶层窗口,显示在其他一切内容之上,此窗口不能获得输入焦点,否则影响锁屏
        public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
        //电话优先,当锁屏时显示,此窗口不能获得输入焦点,否则影响锁屏
        public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
        //系统对话框窗口
        public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
        //锁屏时显示的对话框
        public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
        //系统内部错误提示,显示在任何窗口之上
        public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
        //内部输入法窗口,显示于普通UI之上,应用程序可重新布局以免被此窗口覆盖
        public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
        //内部输入法对话框,显示于当前输入法窗口之上
        public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
        //墙纸窗口
        public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
        //状态栏的滑动面板
        public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
        //安全系统覆盖窗口,这些窗户必须不带输入焦点,否则会干扰键盘
        public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
        //最后一个系统窗口
        public static final int LAST_SYSTEM_WINDOW      = 2999;

        ........

        //窗口特征标记
        public int flags;
        //当该window对用户可见的时候,允许锁屏
        public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;
        //窗口后面的所有内容都变暗
        public static final int FLAG_DIM_BEHIND        = 0x00000002;
        //Flag:窗口后面的所有内容都变模糊
        public static final int FLAG_BLUR_BEHIND        = 0x00000004;
        //窗口不能获得焦点
        public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
        //窗口不接受触摸屏事件
        public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;
        //即使在该window在可获得焦点情况下,允许该窗口之外的点击事件传递到当前窗口后面的的窗口去
        public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;
        //当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到触摸事件
        public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
        //当该window对用户可见时,屏幕出于常亮状态
        public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;
        //:让window占满整个手机屏幕,不留任何边界
        public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;
        //允许窗口超出整个手机屏幕
        public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;
        //window全屏显示
        public static final int FLAG_FULLSCREEN      = 0x00000400;
        //恢复window非全屏显示
        public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;
        //开启窗口抖动
        public static final int FLAG_DITHER             = 0x00001000;
        //安全内容窗口,该窗口显示时不允许截屏
        public static final int FLAG_SECURE             = 0x00002000;


        //锁屏时显示该窗口
        public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
        //系统的墙纸显示在该窗口之后
        public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
        //当window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕
        public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
        //该窗口显示,消失键盘
        public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
        //当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch
        public static final int FLAG_SPLIT_TOUCH = 0x00800000;
        //对该window进行硬件加速,该flag必须在Activity或Dialog的Content View之前进行设置
        public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
        //让window占满整个手机屏幕,不留任何边界
        public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
        //透明状态栏
        public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
        //透明导航栏
        public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;


        ..........
        //软输入法模式
        public int softInputMode;

        //用于描述软键盘显示规则的bite的mask
        public static final int SOFT_INPUT_MASK_STATE = 0x0f;
        //没有软键盘显示的约定规则
        public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
        //可见性状态softInputMode,请不要改变软输入区域的状态
        public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
        //用户导航(navigate)到你的窗口时隐藏软键盘
        public static final int SOFT_INPUT_STATE_HIDDEN = 2;
        //总是隐藏软键盘
        public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
        //用户导航(navigate)到你的窗口时显示软键盘
        public static final int SOFT_INPUT_STATE_VISIBLE = 4;
        //总是显示软键盘
        public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
        //显示软键盘时用于表示window调整方式的bite的mask
        public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
        //不指定显示软件盘时,window的调整方式
        public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
        //当显示软键盘时,调整window内的控件大小以便显示软键盘
        public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
        //当显示软键盘时,调整window的空白区域来显示软键盘,即使调整空白区域,软键盘还是有可能遮挡一些有内容区域,这时用户就只有退出软键盘才能看到这些被遮挡区域并进行
        public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
        //当显示软键盘时,不调整window的布局
        public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
        //用户导航(navigate)到了你的window
        public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;


        //窗口的对齐方式
        public int gravity;

        //期望的位图格式,默认为不透明,参考android.graphics.PixelFormat
        public int format;
        //窗口所使用的动画设置,它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序
        public int windowAnimations;
        //整个窗口的半透明值,1.0表示不透明,0.0表示全透明
        public float alpha = 1.0f;
        //当FLAG_DIM_BEHIND设置后生效,该变量指示后面的窗口变暗的程度,1.0表示完全不透明,0.0表示没有变暗
        public float dimAmount = 1.0f;

        public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
        public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
        public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
        public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
        //用来覆盖用户设置的屏幕亮度,表示应用用户设置的屏幕亮度,从0到1调整亮度从暗到最亮发生变化
        public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;

        public static final int ROTATION_ANIMATION_ROTATE = 0;
        public static final int ROTATION_ANIMATION_CROSSFADE = 1;
        public static final int ROTATION_ANIMATION_JUMPCUT = 2;
        //屏幕旋转动画
        public int rotationAnimation = ROTATION_ANIMATION_ROTATE;

        //窗口的标示符
        public IBinder token = null;
        //此窗口所在应用的包名
        public String packageName = null;
        //窗口屏幕方向
        public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

        //控制status bar是否可见,两种赋值  View#STATUS_BAR_VISIBLE;View#STATUS_BAR_HIDDEN
        public int systemUiVisibility;

        ......

    }
}

分析:WindowManager.LayoutParams继承自ViewGrop.LayoutParams用于描述Android窗口的参数。由上面代码定义我们知道关于窗口有以下几个重要的参数:

  • width:描述窗口的宽度,该变量是父类ViewGroup.LayoutParams的成员变量。
  • height:描述窗口的高度,该变量同样是父类ViewGroup.LayoutParams的成员变量。
  • x:描述窗口的起点X轴的坐标。
  • y:描述窗口起点Y轴的坐标。
  • type:窗口的类型,分为三个大类型:应用窗口,子窗口,系统窗口。
  • flag:窗口特征标记,比如是否全屏,是否隐藏标题栏等。
  • gravity:窗口的对齐方式,居中还是置顶或者置底等等。

接下来从源码角度分析Android系统中的以上三种窗口创建过程。

2.应用窗口创建过程分析

2.1Activity,Window,WindowManager之间的关系

一个应用窗口一般对应一个Activity对象,因此要创建应用窗口就必须创建一个Activity。由Activity的启动过程知道,所有Activity的启动都是有ActivityManagerService(简称Ams)通过Bindler进程间通信机制向客户端进程ActivityThread发送创建新的Activity对象通知,所有Activity的创建都在对应应用程序进程ActivityThread类中完成。Activity类的创建完成之后会调用Activity#attach方法,代码如下:

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback {

    private Window mWindow;

    private WindowManager mWindowManager;

    ........
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        attachBaseContext(context);
        //----- 1 ------
        mWindow = new PhoneWindow(this);
        //----- 2 ------
        mWindow.setCallback(this);
        //----- 3 ------
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        //----- 4 ------   
        mWindow.setWindowManager(            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        //----- 5 ------
        mWindowManager = mWindow.getWindowManager();
        .........
    }
    ........
}

分析: 
1. 在attach放法中首先创建一个PhoneWindow对象赋值给Attivity的成员变量mWindow,而Window类是一个抽象类,用于描述屏幕顶层视图和用户行为操作的窗口,而PhoneWindow是实现了抽象类Window的子类。 
2. 给Activity窗口Window类型的成员变量mWindow设置事件回调监听,而Activity实现了Window#Callback接口类,如此一来Activity就可以分发处理触摸事件了,这就是为什么按back键当前Activity会finish掉的原因。 
3. 给Activity窗口Window类型的成员变量mWindow设置窗口的消失回调监听,用于处理Activity的窗口消失时finish掉当前Activity。 
4. 获得当前Activity的窗口管理对象WindowManager,然后给Window类设置窗口管理服务,也就是赋值给Window类的成员变量mWindowManager。 
5. 获得Window类的窗口管理对象mWindowManager,然后赋值给Activity的成员变量mWindowManager,由此我们知道Activity的窗口管理和Window类的窗口管理指向的都是同一个WindowManager对象。

Window,WindowManager,Activity关系类图如下:

这里写图片描述

Activity的成员变量mWindow类型为Window,该类就是用于描述应用程序窗口类,因此一个Activity对应着一个Window也就是应用窗口。

Activity的成员变量mWindowManager类型为WindowManager,它用来管理当前Activity的窗口,因此一个Activity也对应着一个WindowManager窗口管理器。有前面分析得知Window类的成员变量mWindowManager和Activity的成员变量mWindowManager都是指向同一个WindowManager对象,而WindowManager对象是调用如下代码获取:

(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)
  • 1

而我们知道Activity是继承Context类的,ContextImpl类中实现了WindowManager服务的注册,代码如下:

class ContextImpl extends Context {
static {
    registerService(WINDOW_SERVICE, new ServiceFetcher() {
                Display mDefaultDisplay;
                public Object getService(ContextImpl ctx) {
                    Display display = ctx.mDisplay;
                    if (display == null) {
                        if (mDefaultDisplay == null) {
                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
                                    getSystemService(Context.DISPLAY_SERVICE);
                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
                        }
                        display = mDefaultDisplay;
                    }
                    return new WindowManagerImpl(display);
                }});
    .......
    }
}

有上面代码可知,在ContextImpl类中注册服务是一个静态代码块,也就是说值执行main方法之前就已经完成了WindowManager服务的注册。在整个应用第一次创建Context对象的时候就已经创建WindowManagerImpl对象了,然而WindowManager是个抽象类,具体实现指向WindowManagerImpl。整个应用程序的窗口管理服务都是指向同一个WindowManagerImpl对象,言外之意,不管一个应用程序中有多少个Activity,但只有一个WindowManagerImpl对象。

2.2 Activity窗口添加视图View的过程分析

前面我们说了,一个Activity对应着一个窗口(Window),而窗口只是一个抽象的概念,所有的窗口都有视图(View)来呈现,因此我们来分析下视图View是怎么添加到窗口Window上的?

每个Activity都会调用setContextView方法来加载布局视图,而这其实就是视图View添加到Activity窗口上的一个过程。加载布局视图代码如下Activity#setContentView

 public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
  •  

由于getWindow方法获得的是Activity的成员变量mWindow,而Window对象其实指向PhoneWindow类,因此这里仅仅做了一个转发,其实现在PhoneWindow#setContentView方法中。代码如下:

 public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            //给窗口安装装饰视图DecorView
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            //加载xml布局视图内容到视图容器mContentParent中
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
    }

分析: 
1. 调用installDecor方法给窗口安装视图装饰,所谓视图装饰指的就是界面上看到的标题栏,导航栏Actionbar,也就是窗口的标题栏;而视图装饰的内容就是layout.xml布局,也就是窗口所加载的视图View。

installDecor方法实现的代码如下:

 private void installDecor() {
        if (mDecor == null) {
            //
            mDecor = generateDecor();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
         }
        ........
}

该方法中主要做了两件事:

  • 调用generateDecor方法获得DecorView对象,该对象是ViewGroup类型,用于描述窗口Window的顶层视图。
  • 调用generateLayout方法给窗口添加标题栏,同时获得装载窗口内容的容器mContentParent,该成员变量也是ViewGroup类型。

2.调用inflate方法将布局视图内容加载到刚刚获得的内容容器mContentParent上。

到此,Activity窗口Window添加视图View的流程就结束了。现总结一下他们之间的关系:一个Activity中有一个Window对象用于描述当前应用的窗口,而Window是抽象类,实际上指向PhoneWindow类。PhoneWindow类中有一个内部类DecorView用于描述窗口的顶层视图,该类实际上是ViewGroup类型。当往DecorView上添加标题栏和窗口内容容器之后,最后将layout.xml布局添加到窗口的内容容器中,即完成了窗口Window添加视图View了。最后用之前博客中的一张图片来描述以上关系:

这里写图片描述

【转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树】

2.3 Activity添加窗口Window的过程

有上一小节知道一个Activity对应着一个窗口Window,而窗口Window也完成了视图View的添加,最后视图View是怎么绘制到手机屏幕上的呢?

在Activity创建完成之后,Ams利用Bindler进程间的通信机制通知客户端调用ActivityThread类中的handleResumeActivity方法来启动Activity。代码如下:

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        ........
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;

            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) {
                //客户端Activity的窗口Window对象
                r.window = r.activity.getWindow();
                //窗口的顶层视图DecorView对象
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                //客户端Activity窗口的窗口管理器对象WindowManager
                ViewManager wm = a.getWindowManager();
                //窗口的参数
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                //窗口的类型为基础应用窗口
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                //窗口的软输入法模式
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    //标记客户端Activity添加窗口成功
                    a.mWindowAdded = true;
                    //添加窗口
                    wm.addView(decor, l);
                }
    ........
        }
    }

分析: 
首先获得客户端Activity的窗口对象Window,然后获得该窗口的顶层视图DecorView赋值给本地变量decor,再获得客户端Activity的窗口管理对象WindowManager赋值给本地变量wm,之后再来构造窗口Window的参数WindowManager.LayoutParams,将当前窗口的类型type赋值为TYPE_BASE_APPLICATION,由文章开头我们知道该类型就是应用窗口类型。最后调用WindowManager类中的addView方法完成当前窗口Window的添加。

在这个过程中最主要的操作就是调用了WindowManager#addView方法,而WindowManager是个接口类,继承自ViewManager。

ViewManager源码如下:

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
  •  

该接口类仅仅定义了三个接口方法:

  • addView:添加View视图
  • updateViewLayout:更新视图
  • removeView:移除视图

所以该类是用来管理视图View状态的类,也就是管理视图View的添加,更新,移除。从此处也可以看出,所谓的WindowManager窗口管理其实就是对窗口的视图View进行管理。

WindowManager类源码如下:

public interface WindowManager extends ViewManager {
    ........
     public Display getDefaultDisplay();
     public void removeViewImmediate(View view);
     public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable {
    ........
    }
}
  • 1

该类继承自ViewManager,也是一个接口类,里面定义了两个接口方法和一个内部类LayoutParams类用来描述窗口Window参数。关于WindowManager真正的实现其实在WindowManagerImpl类中。

WindowManagerImpl源码如下:

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;

    private IBinder mDefaultToken;

    public WindowManagerImpl(Display display) {
        this(display, null);
    }

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }
@Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

    @Override
    public Display getDefaultDisplay() {
        return mDisplay;
    }
}

分析: 
该来中实现了接口类ViewManager中的三个方法。但是细心的你会发现,其实这三个方法内部将实际操作转发到mClobal对象的三个对应的方法中去了,而mGlobal成员变量的类型是WindowManagerGlobal类。

WindowManagerGlobal类源码:

public final class WindowManagerGlobal {
    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    ........
    //单例模式构造方法
    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }
     ........
     //窗口的添加过程
     public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            final Context context = view.getContext();
            if (context != null
                    && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {    
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };

            }
            //不能重复添加窗口
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }       
            }
            //判断当前窗口是否为子窗口,如果是则获得其父窗口并保存在panelParentView变量中
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }
            //每一个窗口对应着一个ViewRootImpl对象
            root = new ViewRootImpl(view.getContext(), display);
            //给当前窗口视图设置参数
            view.setLayoutParams(wparams);
            //保存三个数组
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        try {
            //真正执行窗口的视图View绘制工作的方法
            root.setView(view, wparams, panelParentView);
        } 
    }

 //主要更新当前窗口的参数LayoutParams
 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

        view.setLayoutParams(wparams);

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
            root.setLayoutParams(wparams, false);
        }
    }
    //从三个数组里面分别移除DecorView对象,ViewRootIpl对象,WindowManager.LayoutParams对象
    public void removeView(View view, boolean immediate) { 
        synchronized (mLock) {
            int index = findViewLocked(view, true);
            View curView = mRoots.get(index).getView();
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }
        }
    }

分析: 
在WindowManagerGlobal类中维系着三个数组分别是:

  • mViews:保存着当前应用所有窗口的顶层视图DecorView对象
  • mRoots:保存着当前应用所有窗口的视图绘制类ViewRootImpl
  • mParams:保存着当前应用所有窗口的参数 WindowManager.LayoutParams

在2.1小节的最后我们知道,一个应用中不管有多少个Activity,都共用一个WindowManagerImpl对象,而在WindowManagerImpl类中是单例模式获得WindowManagerGlobal对象,因此:一个应用中也就只有一个WindowManagerGlobal对象了。而在该对象中通过维护以上三个数组来维护一个应用中所有窗口的管理。

addView方法:

  • 首先检查当前窗口是否已经添加过,不允许重复添加窗口。
  • 判断如果添加的窗口为子窗口类型,则找到他的父窗口,然后保存在变量panelParentView中作为后面setView方法的参数。
  • 在该方法中创建ViewRootImpl对象,每一个Window对象都持有一个ViewRootImpl对象,然后为当前窗口视图设置窗口参数,在将当前窗口视图View,ViewRootImpl对象,以及窗口参数分别保存到三个数组里。
  • 最后调用ViewRootImpl#setView方法来完成当前窗口视图的绘制。ViewRootImpl类里面会依次执行measure(测量),layout(布局),draw(绘制)三个方法来完成视图View绘制到手机屏上的一个过程,此处不详解,具体参考博客:从ViewRootImpl类分析View绘制的流程。此处才是真正将视图View绘制到手机屏幕的地方。

updateViewLayout方法:

先找到指定的窗口视图View,然后将旧的参数wparams从数组mParams移除,往数组mParams添加新的窗口参数,最后给窗口视图重新设置一下参数即完成了窗口视图的更新操作。

removeView方法:

依次将三个参数从数组中移除,然后调用相应的方法销毁视图View的绘制。

总结

  1. 一个Activity就对应着一个应用窗口PhoneWindow对象,该对象用于描述窗口的。

  2. PhoneWindow类内部有一个DecorView类,该类是ViewGroup类型,用于描述窗口的顶层视图的,该视图才是真正装载layout.xml布局内容的。

  3. 一个应用不管有多少个Activity,都只有一个WindowManager窗口管理器,也就只有一个WindowManagerGlobal对象通过维护三个数组 mViews,mRoots,mParams来管理所有窗口的添加,更新,删除。

  4. 一个窗口对应着一个ViewRootImpl类,该类主要的作用就是将窗口的顶层视图DecorView内容绘制到手机屏幕上。

最后给出以上所有类图关系图如下:

这里写图片描述
点击看大图

Android - Activity 启动过程

概述

从点击桌面应用图标到应用显示的过程我们再熟悉不过了,下面我们来分析下这个过程都做了什么。

本文主要对以下问题分析:

  • ActivityThread 是什么,它是一个线程吗,如何被启动的?
  • ActivityClientRecord 与 ActivityRecord 是什么?
  • Context 是什么,ContextImpl,ContextWapper 是什么?
  • Instrumentation 是什么?
  • Application 是什么,什么时候创建的,每个应用程序有几个 Application?
  • 点击 Launcher 启动 Activity 和应用内部启动 Activity 的区别?
  • Activity 启动过程,onCreate(),onResume() 回调时机及具体作用?

Launcher

如不了解 Android 是如何从开机到 Launcher 启动的过程,请先阅读Android - 系统启动过程

这里写图片描述

我们知道 Android 系统启动后已经启动了 Zygote,ServiceManager,SystemServer 等系统进程;ServiceManager 进程中完成了 Binder 初始化;SystemServer 进程中 ActivityManagerService,WindowManagerService,PackageManagerService 等系统服务在 ServiceManager 中已经注册;最后启动了 Launcher 桌面应用。

其实 Launcher 本身就是一个应用程序,运行在自己的进程中,我们看到的桌面就是 Launcher 中的一个 Activity。

应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出这个 apk 的信息写入到 packages.xml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。

同时桌面 Launcher 会为安装过的应用生成不同的应用入口,对应桌面上的应用图标,下面分析点击应用图标的到应用启动的过程。

点击 Launcher 中应用图标

这里写图片描述

点击 Launcher 中应用图标将会执行以下方法

Launcher.startActivitySafely()
Launcher.startActivity()
//以上两个方法主要是检查将要打开的 Activity 是否存在

Activity.startActivity()
//这段代码大家已经很熟悉,经常打开 Activity 用的就是这个方法

Activity.startActivityForResult()
//默认 requestCode = -1,也可通过调用 startActivityForResult() 传入 requestCode。 
//然后通过 MainThread 获取到 ApplicationThread 传入下面方法。

Instrumentation.execStartActivity()
//通过 ActivityManagerNative.getDefault() 获取到 ActivityManagerService 的代理为进程通讯作准备。

ActivityManagerNative.getDefault().startActivity()
ActivityManagerProxy.startActivity()
//调用代理对象的 startActivity() 方法,发送 START_ACTIVITY_TRANSACTION 命令。
  •  

在 system_server 进程中的服务端 ActivityManagerService 收到 START_ACTIVITY_TRANSACTION 命令后进行处理,调用 startActivity() 方法。

ActivityManagerService.startActivity() -> startActivityAsUser(intent, requestCode, userId)
//通过 UserHandle.getCallingUserId() 获取到 userId 并调用 startActivityAsUser() 方法。

ActivityStackSupervisor.startActivityMayWait() -> resolveActivity()
//通过 intent 创建新的 intent 对象,即使之前 intent 被修改也不受影响。 然后调用 resolveActivity()。
//然后通过层层调用获取到 ApplicationPackageManager 对象。

PackageManagerService.resolveIntent() -> queryIntentActivities()
//获取 intent 所指向的 Activity 信息,并保存到 Intent 对象。

PackageManagerService.chooseBestActivity()
//当存在多个满足条件的 Activity 则会弹框让用户来选择。

ActivityStackSupervisor.startActivityLocked()
//获取到调用者的进程信息。 通过 Intent.FLAG_ACTIVITY_FORWARD_RESULT 判断是否需要进行 startActivityForResult 处理。 
//检查调用者是否有权限来调用指定的 Activity。 
//创建 ActivityRecord 对象,并检查是否运行 App 切换。

ActivityStackSupervisor.startActivityUncheckedLocked() -> startActivityLocked()
//进行对 launchMode 的处理[可参考 Activity 启动模式],创建 Task 等操作。
//启动 Activity 所在进程,已存在则直接 onResume(),不存在则创建 Activity 并处理是否触发 onNewIntent()。

ActivityStack.resumeTopActivityInnerLocked()
//找到 resume 状态的 Activity,执行 startPausingLocked() 暂停该 Activity,同时暂停所有处于后台栈的 Activity,找不到 resume 状态的 Activity 则回桌面。
//如果需要启动的 Activity 进程已存在,直接设置 Activity 状态为 resumed。 调用下面方法。

ActivityStackSupervisor.startSpecificActivityLocked()
//进程存在调用 realStartActivityLocked() 启动 Activity,进程不存在则调用下面方法。

fork 新进程

从 Launcher 点击图标,如果应用没有启动过,则会 fork 一个新进程。创建新进程的时候,ActivityManagerService 会保存一个 ProcessRecord 信息,Activity 应用程序中的AndroidManifest.xml 配置文件中,我们没有指定 Application 标签的 process 属性,系统就会默认使用 package 的名称。每一个应用程序都有自己的 uid,因此,这里 uid + process 的组合就可以为每一个应用程序创建一个 ProcessRecord。每次在新建新进程前的时候会先判断这个 ProcessRecord 是否已存在,如果已经存在就不会新建进程了,这就属于应用内打开 Activity 的过程了。

ActivityManagerService.startProcessLocked()
//进程不存在请求 Zygote 创建新进程。 创建成功后切换到新进程。
  •  

进程创建成功切换至 App 进程,进入 app 进程后将 ActivityThread 类加载到新进程,并调用 ActivityThread.main() 方法

ActivityThread.main()
//创建主线程的 Looper 对象,创建 ActivityThread 对象,ActivityThread.attach() 建立 Binder 通道,开启 Looper.loop() 消息循环。

ActivityThread.attach()
//开启虚拟机各项功能,创建 ActivityManagerProxy 对象,调用基于 IActivityManager 接口的 Binder 通道 ActivityManagerProxy.attachApplication()。

ActivityManagerProxy.attachApplication()
//发送 ATTACH_APPLICATION_TRANSACTION 命令
  •  

此时只创建了应用程序的 ActivityThread 和 ApplicationThread,和开启了 Handler 消息循环机制,其他的都还未创建, ActivityThread.attach(false) 又会最终到 ActivityMangerService 的 attachApplication,这个工程其实是将本地的 ApplicationThread 传递到 ActivityMangerService。然后 ActivityMangerService 就可以通过 ApplicationThread 的代理 ApplicationThreadProxy 来调用应用程序 ApplicationThread.bindApplication,通知应用程序的 ApplicationThread 已和 ActivityMangerService 绑定,可以不借助其他进程帮助直接通信了。此时 Launcher 的任务也算是完成了。

在 system_server 进程中的服务端 ActivityManagerService 收到 ATTACH_APPLICATION_TRANSACTION 命令后进行处理,调用 attachApplication()。

ActivityMangerService.attachApplication() -> attachApplicationLocked()
//首先会获取到进程信息 ProcessRecord。 绑定死亡通知,移除进程启动超时消息。 获取到应用 ApplicationInfo 并绑定应用 IApplicationThread.bindApplication(appInfo)。
//然后检查 App 所需组件。
  •  
  • Activity: 检查最顶层可见的 Activity 是否等待在该进程中运行,调用 ActivityStackSupervisor.attachApplicationLocked()。
  • Service:寻找所有需要在该进程中运行的服务,调用 ActiveServices.attachApplicationLocked()。
  • Broadcast:检查是否在这个进程中有下一个广播接收者,调用 sendPendingBroadcastsLocked()。

此处讨论 Activity 的启动过程,只讨论 ActivityStackSupervisor.attachApplicationLocked() 方法。

ActivityStackSupervisor.attachApplicationLocked() -> realStartActivityLocked()
//将该进程设置为前台进程 PROCESS_STATE_TOP,调用 ApplicationThreadProxy.scheduleLaunchActivity()。

ApplicationThreadProxy.scheduleLaunchActivity()
//发送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令

发送送完 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,还会发送 BIND_APPLICATION_TRANSACTION 命令来创建 Application。

ApplicationThreadProxy.bindApplication()
//发送 BIND_APPLICATION_TRANSACTION 命令
  • 1
  • 2

App 进程初始化

在 app 进程中,收到 BIND_APPLICATION_TRANSACTION 命令后调用 ActivityThread.bindApplication()。

ActivityThread.bindApplication()
//缓存 Service,初始化 AppBindData,发送消息 H.BIND_APPLICATION。
  • 1
  • 2

ApplicationThreadProxy.bindApplication(…) 会传来这个应用的一些信息,如ApplicationInfo,Configuration 等,在 ApplicationThread.bindApplication 里会待信息封装成A ppBindData,通过

sendMessage(H.BIND_APPLICATION, data)
  • 1

将信息放到应用里的消息队列里,通过 Handler 消息机制,在 ActivityThread.handleMeaasge 里处理 H.BIND_APPLICATION 的信息,调用 AplicationThread.handleBindApplication。

handleBindApplication(AppBindData data) {
    Process.setArgV0(data.processName);//设置进程名
    ...
    //初始化 mInstrumentation
    if(data.mInstrumentation!=null) {
        mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance();
    } else {
        mInstrumentation = new Instrumentation();
    }
    //创建Application,data.info 是个 LoadedApk 对象。
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    mInitialApplication = app;
    //调用 Application 的 onCreate()方法。
    mInstrumentation.callApplicationOnCreate(app);
}

public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {

    if (mApplication != null) {   
       return mApplication;
    }

    String appClass = mApplicationInfo.className;
    java.lang.ClassLoader cl = getClassLoader();

    //此时新建一个 Application 的 ContextImpl 对象,
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

    //通过在 handleBindApplication 创建的 mInstrumentation 对象新建一个 Application 对象,同时进行 attach。
    app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
    appContext.setOuterContext(app);
}

//设置进程名,获取 LoadedApk 对象,创建 ContextImpl 上下文
//LoadedApk.makeApplication() 创建 Application 对象,调用 Application.onCreate() 方法。

Instrumentation:

public Application newApplication(ClassLoader cl, String className, Context context) {    
    return newApplication(cl.loadClass(className), context);
}
Instrumentation类:
static public Application newApplication(Class<?> clazz, Context context)  {
    //实例化 Application
    Application app = (Application)clazz.newInstance();     

    // Application 和 context绑定
    app.attach(context);    
    return app;
}
//attach 就是将新建的 ContextImpl 赋值到 mBase,这个 ContextImpl 对象就是所有Application 内 Context 的具体实现,同时赋值一些其他的信息如 mLoadedApk。
final void attach(Context context) {    
    mBase = base;  
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

这时 Application 就创建好了,这点很重要,很多资料里说 Application 是在performLaunchActivity() 里创建的,因为 performLaunchActivity() 也有mInstrumentation.newApplication 这个调用,newApplication() 函数中可看出会先判断是否以及创建了 Application,如果之前已经创建,就返回已创建的 Application 对象。

Activity 启动

上面 fork 进程时会发送 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令,在 app 进程中,收到 SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION 命令后调用 ApplicationThread.scheduleLaunchActivity()。

ApplicationThread.scheduleLaunchActivity()
//发送消息 H.LAUNCH_ACTIVITY。

sendMessage(H.LAUNCH_ACTIVITY, r);

ActivityThread.handleLaunchActivity()
//最终回调目标 Activity 的 onConfigurationChanged(),初始化 WindowManagerService。
//调用 ActivityThread.performLaunchActivity()

ActivityThread.performLaunchActivity() {
    //类似 Application 的创建过程,通过 classLoader 加载到 activity.
    activity = mInstrumentation.newActivity(classLoader, 
               component.getClassName(), r.intent);
    //因为 Activity 有界面,所以其 Context 是 ContextThemeWrapper 类型,但实现类仍是ContextImpl.
    Context appContext = createBaseContextForActivity(r, activity);
    activity.attach(context,mInstrumentation,application,...);
    //与 Window 进行关联

    //attach 后调用 activity 的 onCreate()方法。
    mInstrumentation.callActivityOnCreate(activity,...)

}
//在ActivityThread.handleLaunchActivity里,接着调用

Activity.performCreate() -> onCreate()
//最终回调目标 Activity 的 onCreate()。

Activity.setContentView()
//设置 layout 布局

ActivityThread.performResumeActivity()
//最终回调目标 Activity 的 onResume()。
  •  

与 Window 进行关联,具体过程详见:Activity,Window,View 之间的关系

总结

Activity 的整体启动流程如图所示:

这里写图片描述

  • ActivityThread 是什么,它是一个线程吗,如何被启动的?

它不是一个线程,它是运行在 App 进程中的主线程中的一个方法中。当 App 进程创建时会执行 ActivityThread.main(),ActivityThread.main() 首先会创建 Looper 执行 Looper.prepareMainLooper();然后创建 ActivityThread 并调用 ActivityThread.attach() 方法告诉 ActivityManagerService 我们创建了一个应用 并将 ApplicationThread 传给 ActivityManagerService;最后调用 Looper.loop()。

  • ActivityClientRecord 与 ActivityRecord 是什么?

记录 Activity 相关信息,比如:Window,configuration,ActivityInfo 等。 
ActivityClientRecord 是客户端的,ActivityRecord 是 ActivityManagerService 服务端的。

  • Context 是什么,ContextImpl,ContextWapper 是什么?

Context 定义了 App 进程的相关环境,Context 是一个接口,ContextImpl 是子类,ContextWapper 是具体实现。

应用资源是在 Application 初始化的时候,也就是创建 Application,ContextImpl 的时候,ContextImpl 就包含这个路径,主要就是对就是 ResourcesManager 这个单例的引用。

可以看出每次创建 Application 和 Acitvity 以及 Service 时就会有一个 ContextImpl 实例,ContentProvider 和B roadcastReceiver 的 Context 是其他地方传入的。

所以 Context 数量 = Application 数量 + Activity 数量 + Service 数量,单进程情况下 Application 数量就是 1。

  • Instrumentation 是什么?

管理着组件Application,Activity,Service等的创建,生命周期调用。

  • Application 是什么,什么时候创建的,每个应用程序有几个 Application?

Application 是在 ActivityThread.handleBindApplication() 中创建的,一个进程只会创建一个 Application,但是一个应用如果有多个进程就会创建多个 Application 对象。

  • 点击 Launcher 启动 Activity 和应用内部启动 Activity 的区别?

点击 Launcher 时会创建一个新进程来开启 Activity,而应用内打开 Activity,如果 Activity 不指定新进程,将在原来进程打开,是否开启新进程实在 ActivityManagerService 进行控制的,上面分析得到,每次开启新进程时会保存进程信息,默认为 应用包名 + 应用UID,打开 Activity 时会检查请求方的信息来判断是否需要新开进程。Launcher 打开 Activity 默认 ACTIVITY_NEW_TASK,新开一个 Activity 栈来保存 Activity 的信息。

  • Activity 启动过程,onCreate(),onResume() 回调时机及具体作用?

Activity.onCreate() 完成了 App 进程,Application,Activity 的创建,调用 setContentView() 给 Activity 设置了 layout 布局。

Activity.onResume() 完成了 Activity 中 Window 与 WindowManager 的关联,并对所有子 View 进行渲染并显示。

参考资料

Android - 系统启动过程

计算机是如何启动的?

首先熟悉一些概念,计算机的硬件包括:CPU,内存,硬盘,显卡,显示器,键盘鼠标等其他输入输出设备。 所有的软件(比如:操作系统)都是存放在硬盘上,程序执行时需要将程序从硬盘上读取到内存中然后加载到 CPU 中来运行。 当我们按下开机键时,此时内存中什么都没有,因此需要借助某种方式,将操作系统加载到内存中,而完成这项任务的就是 BIOS。

  • 引导阶段

BIOS: Basic Input/Output System(基本输入输出系统),在 IBM PC 兼容系统上,是一种业界标准的固件接口(来自维基百科)。 BIOS 一般是主板芯片上的一个程序,计算机通电后,第一件事就是读取它。

BIOS 程序首先检查计算机硬件能否满足运行的基本条件,这叫做"硬件自检"(Power-On Self-Test),缩写为 POST。 如果硬件出现问题,主板会发出不同含义的蜂鸣,启动中止。 如果没有问题,屏幕就会显示出 CPU,内存,硬盘等信息。

硬件自检完成后,BIOS 把控制权转交给下一阶段的启动程序。 这时 BIOS 需要知道,下一阶段的启动程序到底存放在哪一个设备当中。 也就是说 BIOS 需要有一个外部存储设备的排序,排在前面的设备就是优先转交控制权的设备。 这种排序叫做启动排序,也就是我们平时进入 BIOS 界面时能看到的 Boot Sequence。

如果我们没有进行特殊操作的话,那么 BIOS 就会按照这个启动顺序将控制权交给下一个存储设备。 我们在使用 U 盘光盘之类的装系统时就是在这里将启动顺序改变了,将本来要移交给硬盘的控制权交给了 U 盘或者光盘。

第一存储设备被激活后,计算机读取该设备的第一个扇区,也就是读取最前面的 512 个字节。 如果这 512 个字节的最后两个字节是 0x55 和 0xAA ,表明这个设备可以用于启动;如果不是,表明设备不能用于启动,控制权于是被转交给“启动顺序”中的下一个设备。

这最前面的 512 个字节,就叫做"主引导记录"(Master boot record,缩写为 MBR)。 主引导记录 MBR 是位于磁盘最前边的一段引导代码。它负责磁盘操作系统对磁盘进行读写时分区合法性的判别、分区引导信息的定位,它由磁盘操作系统在对硬盘进行初始化时产生的。 硬盘的主引导记录 MBR 是不属于任何一个操作系统的,它先于所有的操作系统而被调入内存,并发挥作用,然后才将控制权交给主分区内的操作系统,并用主分区信息表来管理硬盘。

MBR 只有512个字节,放不了太多东西。 它的主要作用是,告诉计算机到硬盘的哪一个位置去找操作系统。 我们找到可用的 MBR 后,计算机从 MBR 中读取前面 446 字节的机器码之后,不再把控制权转交给某一个分区,而是运行事先安装的"启动管理器"(boot loader),由用户选择启动哪一个操作系统。

  • 加载内核阶段

选择完操作系统后,控制权转交给操作系统,操作系统的内核首先被载入内存。

以 Linux 系统为例,先载入 /boot 目录下面的 kernel。 内核加载成功后,第一个运行的程序是 /sbin/init。 它根据配置文件(Debian 系统是 /etc/initab )产生 init 进程。 这是 Linux 启动后的第一个进程,pid 进程编号为 1,其他进程都是它的后代。

然后,init 线程加载系统的各个模块,比如:窗口程序和网络程序,直至执行 /bin/login 程序,跳出登录界面,等待用户输入用户名和密码。

至此,全部启动过程完成。

Android 手机的启动过程

Android 系统虽然也是基于 Linux 系统的,但是由于 Android 属于嵌入式设备,并没有像 PC 那样的 BIOS 程序。 取而代之的是 Bootloader —— 系统启动加载器。 它类似于 BIOS,在系统加载前,用以初始化硬件设备,建立内存空间的映像图,为最终调用系统内核准备好环境。 在 Android 里没有硬盘,而是 ROM,它类似于硬盘存放操作系统,用户程序等。 ROM 跟硬盘一样也会划分为不同的区域,用于放置不同的程序,在 Android 中主要划分为一下几个分区:

  • /boot:存放引导程序,包括内核和内存操作程序
  • /system:相当于电脑c盘,存放Android系统及系统应用
  • /recovery:恢复分区,可以进入该分区进行系统恢复
  • /data:用户数据区,包含了用户的数据:联系人、短信、设置、用户安装的程序
  • /cache:安卓系统缓存区,保存系统最常访问的数据和应用程序
  • /misc:包含一些杂项内容,如系统设置和系统功能启用禁用设置
  • /sdcard:用户自己的存储区,可以存放照片,音乐,视频等文件

那么 Bootloader 是如何被加载的呢?跟 PC 启动过程类似,当开机通电时首先会加载 Bootloader,Bootloader 会读取 ROM 找到操作系统并将 Linux 内核加载到 RAM 中。

当 Linux 内核启动后会初始化各种软硬件环境,加载驱动程序,挂载根文件系统,Linux 内核加载的最后阶段会启动执行第一个用户空间进程 init 进程。

init 进程

init 是 Linux 系统中用户空间的第一个进程(pid=1),Kernel 启动后会调用 /system/core/init/Init.cpp 的 main() 方法。

  • Init.main()

首先初始化 Kernel log,创建一块共享的内存空间,加载 /default.prop 文件,解析 init.rc 文件。

init.rc 文件

init.rc 文件是 Android 系统的重要配置文件,位于 /system/core/rootdir/ 目录中。 主要功能是定义了系统启动时需要执行的一系列 action 及执行特定动作、设置环境变量和属性和执行特定的 service。

init.rc 脚本文件配置了一些重要的服务,init 进程通过创建子进程启动这些服务,这里创建的 service 都属于 native 服务,运行在 Linux 空间,通过 socket 向上层提供特定的服务,并以守护进程的方式运行在后台。

通过 init.rc 脚本系统启动了以下几个重要的服务:

  • service_manager:启动 binder IPC,管理所有的 Android 系统服务
  • mountd:设备安装 Daemon,负责设备安装及状态通知
  • debuggerd:启动 debug system,处理调试进程的请求
  • rild:启动 radio interface layer daemon 服务,处理电话相关的事件和请求
  • media_server:启动 AudioFlinger,MediaPlayerService 和 CameraService,负责多媒体播放相关的功能,包括音视频解码
  • surface_flinger:启动 SurfaceFlinger 负责显示输出
  • zygote:进程孵化器,启动 Android Java VMRuntime 和启动 systemserver,负责 Android 应用进程的孵化工作

在这个阶段你可以在设备的屏幕上看到 “Android” logo 了。

以上工作执行完,init 进程就会进入 loop 状态。

service_manager 进程

ServiceManager 是 Binder IPC 通信过程中的守护进程,本身也是一个 Binder 服务。ServiceManager 进程主要是启动 Binder,提供服务的查询和注册。

具体过程详见 Binder:Android Binder 进程间通讯

surface_flinger 进程

SurfaceFlinger 负责图像绘制,是应用 UI 的核心,其功能是合成所有 Surface 并渲染到显示设备。SurfaceFlinger 进程主要是启动 FrameBuffer,初始化显示系统。

media_server 进程

MediaServer 进程主要是启动 AudioFlinger 音频服务,CameraService 相机服务。负责处理音频解析播放,相机相关的处理。

Zygote 进程

fork 创建进程过程: 

Zygote 进程孵化了所有的 Android 应用进程,是 Android Framework 的基础,该进程的启动也标志着 Framework 框架初始化启动的开始。

Zygote 服务进程的主要功能:

  • 注册底层功能的 JNI 函数到虚拟机
  • 预加载 Java 类和资源
  • fork 并启动 system_server 核心进程
  • 作为守护进程监听处理“孵化新进程”的请求

当 Zygote 进程启动后, 便会执行到 frameworks/base/cmds/app_process/App_main.cpp 文件的 main() 方法。

App_main.main() //设置进程名,并启动 AppRuntime。
AndroidRuntime::start() //创建 Java 虚拟机,注册 JNI 方法,调用 ZygoteInit.main() 方法。
ZygoteInit.main()   //为 Zygote 注册 socket,预加载类和资源,启动 system_server 进程。

然后 Zygote 进程会进入 loop 状态,等待下次 fork 进程。

system_server 进程

system_server 进程 由 Zygote 进程 fork 而来。接下来看下 system_server 启动过程。

//首先会调用 ZygoteInit.startSystemServer() 方法
ZygoteInit.startSystemServer()  
//fork 子进程 system_server,进入 system_server 进程。

ZygoteInit.handleSystemServerProcess()  
//设置当前进程名为“system_server”,创建 PathClassLoader 类加载器。

RuntimeInit.zygoteInit()    
//重定向 log 输出,通用的初始化(设置默认异常捕捉方法,时区等),初始化 Zygote -> nativeZygoteInit()。

nativeZygoteInit()  
//方法经过层层调用,会进入 app_main.cpp 中的 onZygoteInit() 方法。

app_main::onZygoteInit()// 启动新 Binder 线程。

applicationInit()   
//方法经过层层调用,会抛出异常 ZygoteInit.MethodAndArgsCaller(m, argv), ZygoteInit.main() 会捕捉该异常。

ZygoteInit.main()   
//开启 DDMS 功能,preload() 加载资源,预加载 OpenGL,调用 SystemServer.main() 方法。

SystemServer.main() 
//先初始化 SystemServer 对象,再调用对象的 run() 方法。

SystemServer.run()  
//准备主线程 looper,加载 android_servers.so 库,该库包含的源码在 frameworks/base/services/ 目录下。

system_server 进程启动后将初始化系统上下文(设置主题),创建系统服务管理 SystemServiceManager,然后启动各种系统服务:

startBootstrapServices(); // 启动引导服务
//该方法主要启动服务 ActivityManagerService,PowerManagerService,LightsService,DisplayManagerService,PackageManagerService,UserManagerService。
//设置 ActivityManagerService,启动传感器服务。

startCoreServices();      // 启动核心服务
//该方法主要
//启动服务 BatteryService 用于统计电池电量,需要 LightService。
//启动服务 UsageStatsService,用于统计应用使用情况。
//启动服务 WebViewUpdateService。

startOtherServices();     // 启动其他服务
//该方法主要启动服务 InputManagerService,WindowManagerService。
//等待 ServiceManager,SurfaceFlinger启动完成,然后显示启动界面。
//启动服务 StatusBarManagerService,
//准备好 window, power, package, display 服务:
//	- WindowManagerService.systemReady()
//	- PowerManagerService.systemReady()
//	- PackageManagerService.systemReady()
//	- DisplayManagerService.systemReady()

所有的服务启动完成后会注册到 ServiceManager。 ActivityManagerService 服务启动完成后,会进入 ActivityManagerService.systemReady(),然后启动 SystemUI,WebViewFactory,Watchdog,最后启动桌面 Launcher App。

最后会进入循环 Looper.loop()。

ActivityManagerService 启动

启动桌面 Launcher App 需要等待 ActivityManagerService 启动完成。我们来看下 ActivityManagerService 启动过程。

ActivityManagerService(Context) 
//创建名为“ActivityManager”的前台线程,并获取mHandler。
//通过 UiThread 类,创建名为“android.ui”的线程。
//创建前台广播和后台广播接收器。
//创建目录 /data/system。
//创建服务 BatteryStatsService。

ActivityManagerService.start()  //启动电池统计服务,创建 LocalService,并添加到 LocalServices。

ActivityManagerService.startOtherServices() -> installSystemProviders()
//安装所有的系统 Provider。

ActivityManagerService.systemReady()
//恢复最近任务栏的 task。
//启动 WebView,SystemUI,开启 Watchdog,启动桌面 Launcher App。
//发送系统广播。

启动桌面 Launcher App,首先会通过 Zygote 进程 fork 一个新进程作为 App 进程,然后创建 Application,创建启动 Activity,最后用户才会看到桌面。

完整启动过程

参考资料

基于Android 6.0的源码剖析, Android启动过程概述

一. 概述

Android系统底层基于Linux Kernel, 当Kernel启动过程会创建init进程, 该进程是uoyou用户空间的鼻祖, init进程会启动servicemanager(binder服务管家), Zygote进程(Java进程的鼻祖). Zygote进程会创建 system_server进程以及各种app进程.

android-booting

二. init

init是Linux系统中用户空间的第一个进程(pid=1), Kerner启动后会调用/system/core/init/Init.cpp的main()方法.

2.1 Init.main

int main(int argc, char** argv) {
    ...
    klog_init();  //初始化kernel log
    property_init(); //创建一块共享的内存空间,用于属性服务
    signal_handler_init();  //初始化子进程退出的信号处理过程

    property_load_boot_defaults(); //加载/default.prop文件
    start_property_service();   //启动属性服务器(通过socket通信)
    init_parse_config_file("/init.rc"); //解析init.rc文件

    //执行rc文件中触发器为 on early-init的语句
    action_for_each_trigger("early-init", action_add_queue_tail);
    //执行rc文件中触发器为 on init的语句
    action_for_each_trigger("init", action_add_queue_tail);
    //执行rc文件中触发器为 on late-init的语句
    action_for_each_trigger("late-init", action_add_queue_tail);

    while (true) {
        if (!waiting_for_exec) {
            execute_one_command();
            restart_processes();
        }
        int timeout = -1;
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }
        if (!action_queue_empty() || cur_action) {
            timeout = 0;
        }

        epoll_event ev;
        //循环 等待事件发生
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)();
        }
    }
    return 0;
}

init进程的主要功能点:

  • 分析和运行所有的init.rc文件;
  • 生成设备驱动节点; (通过rc文件创建)
  • 处理子进程的终止(signal方式);
  • 提供属性服务property service。

2.2 启动Zygote

当init解析到下面这条语句,便会启动Zygote进程

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main //伴随着main class的启动而启动
    socket zygote stream 660 root system //创建socket
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media  //当zygote重启时,则会重启media
    onrestart restart netd  // 当zygote重启时,则会重启netd

当init子进程(Zygote)退出时,会产生SIGCHLD信号,并发送给init进程,通过socket套接字传递数据,调用到wait_for_one_process()方法,根据是否是oneshot,来决定是重启子进程,还是放弃启动。由于缺省模式oneshot=false,因此Zygote一旦被杀便会再次由init进程拉起.

init_oneshot

接下来,便是进入了Zygote进程.

三. Zygote

Zygote进程启动后, 便会执行到frameworks/base/cmds/app_process/App_main.cpp文件的main()方法. 整个调用流程:

App_main.main
    AndroidRuntime.start
        AndroidRuntime.startVm
        AndroidRuntime.startReg
        ZygoteInit.main (首次进入Java世界)
            registerZygoteSocket
            preload
            startSystemServer
            runSelectLoop

3.1 App_main.main

int main(int argc, char* const argv[]) {
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    while (i < argc) {
        ...//参数解析
    }

    //设置进程名
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {
        // 启动AppRuntime
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    }
    ...
}

3.2 AndroidRuntime::start

[-> AndroidRuntime.cpp]

void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
    ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
            className != NULL ? className : "(unknown)");
    ...
    // 虚拟机创建
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);

    // JNI方法注册
    if (startReg(env) < 0) {
        return;
    }
    ...
    // 调用ZygoteInit.main()方法[见小节3.3]
    env->CallStaticVoidMethod(startClass, startMeth, strArray);

3.3 ZygoteInit.main

[–>ZygoteInit.java]

public static void main(String argv[]) {
    try {
        ...
        registerZygoteSocket(socketName); //为Zygote注册socket
        preload(); // 预加载类和资源[见小节3.4]
        ...
        if (startSystemServer) {
            startSystemServer(abiList, socketName);//启动system_server【见小节3.6】
        }
        Log.i(TAG, "Accepting command socket connections");
        runSelectLoop(abiList); //进入循环模式[见小节3.5]
        ...
    } catch (MethodAndArgsCaller caller) {
        caller.run(); //启动system_server中会讲到。
    }
    ...
}

3.4 ZygoteInit.preload

[–>ZygoteInit.java]

static void preload() {
    Log.d(TAG, "begin preload");
    preloadClasses();
    preloadResources();
    preloadOpenGL();
    preloadSharedLibraries();
    WebViewFactory.prepareWebViewInZygote();
    Log.d(TAG, "end preload");
}

3.5 ZygoteInit.runSelectLoop

[–>ZygoteInit.java]

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

    //sServerSocket是socket通信中的服务端,即zygote进程
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        ...
        Os.poll(pollFds, -1);

        for (int i = pollFds.length - 1; i >= 0; --i) {
            //采用I/O多路复用机制,当客户端发出连接请求或者数据处理请求时,跳过continue,执行后面的代码
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {
                //创建客户端连接
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                //处理客户端数据事务
                boolean done = peers.get(i).runOnce();
                if (done) {
                    peers.remove(i);
                    fds.remove(i);
                }
            }
        }
    }
}

3.6 ZygoteInit.startSystemServer

[–>ZygoteInit.java]

private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {
    ...

    // fork子进程system_server
    pid = Zygote.forkSystemServer(
            parsedArgs.uid, parsedArgs.gid,
            parsedArgs.gids,
            parsedArgs.debugFlags,
            null,
            parsedArgs.permittedCapabilities,
            parsedArgs.effectiveCapabilities);
    ...

    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
        //进入system_server进程[见小节4.1]
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}

Zygote进程创建Java虚拟机,并注册JNI方法, 真正成为Java进程的母体,用于孵化Java进程. 在创建完[小节4.1]system_server进程后,zygote功成身退,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。

四. system_server

Zygote通过fork后创建system_server进程。

4.1 handleSystemServerProcess

[–>ZygoteInit.java]

private static void handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs) throws ZygoteInit.MethodAndArgsCaller {
    ...
    if (parsedArgs.niceName != null) {
         //设置当前进程名为"system_server"
        Process.setArgV0(parsedArgs.niceName);
    }

    final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
    if (systemServerClasspath != null) {
        //执行dex优化操作,比如services.jar
        performSystemServerDexOpt(systemServerClasspath);
    }

    if (parsedArgs.invokeWith != null) {
        ...
    } else {
        ClassLoader cl = null;
        if (systemServerClasspath != null) {
            cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
            Thread.currentThread().setContextClassLoader(cl);
        }
        //[见小节4.2]
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }
}

system_server进程创建PathClassLoader类加载器.

4.2 RuntimeInit.zygoteInit

[–> RuntimeInit.java]

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
    redirectLogStreams(); //重定向log输出

    commonInit(); // 通用的一些初始化
    nativeZygoteInit(); // zygote初始化
    applicationInit(targetSdkVersion, argv, classLoader); // [见小节3.4]
}

nativeZygoteInit()方法经过层层调用,会进入app_main.cpp中的onZygoteInit()方法, Binder线程池的创建也是在这个过程,如下:

virtual void onZygoteInit() {
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //启动新binder线程
}

applicationInit()方法经过层层调用,会抛出异常ZygoteInit.MethodAndArgsCaller(m, argv), ZygoteInit.main() 会捕捉该异常, 见下文.

4.3 ZygoteInit.main

[–>ZygoteInit.java]

public static void main(String argv[]) {
    try {
        startSystemServer(abiList, socketName); //抛出MethodAndArgsCaller异常
        ....
    } catch (MethodAndArgsCaller caller) {
        caller.run(); //此处通过反射,会调用SystemServer.main()方法 [见小节4.4]
    } catch (RuntimeException ex) {
        ...
    }
}

采用抛出异常的方式,用于栈帧清空,提供利用率, 以至于现在大家看到的每个Java进程的调用栈如下:

...
at com.android.server.SystemServer.main(SystemServer.java:175)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

4.4 SystemServer.main

[–>SystemServer.java]

public final class SystemServer {
    ...
    public static void main(String[] args) {
        //先初始化SystemServer对象,再调用对象的run()方法
        new SystemServer().run();
    }
}

4.5 SystemServer.run

[–>SystemServer.java]

private void run() {
    if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
        Slog.w(TAG, "System clock is before 1970; setting to 1970.");
        SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
    }
    ...

    Slog.i(TAG, "Entered the Android system server!");
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());

    Looper.prepareMainLooper();// 准备主线程looper

    //加载android_servers.so库,该库包含的源码在frameworks/base/services/目录下
    System.loadLibrary("android_servers");

    //检测上次关机过程是否失败,该方法可能不会返回[见小节3.6.1]
    performPendingShutdown();

    createSystemContext(); //初始化系统上下文

    //创建系统服务管理
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

    //启动各种系统服务[见小节3.7]
    try {
        startBootstrapServices(); // 启动引导服务
        startCoreServices();      // 启动核心服务
        startOtherServices();     // 启动其他服务[见小节4.6]
    } catch (Throwable ex) {
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    }

    //一直循环执行
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

4.6 服务启动

public final class SystemServer {

    private void startBootstrapServices() {
      ...
      //phase100
      mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
      ...
    }

    private void startOtherServices() {
        ...
        //phase480 和phase500
        mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
        mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        ...
        //[见小节4.7]
        mActivityManagerService.systemReady(new Runnable() {
           @Override
           public void run() {
               //phase550
               mSystemServiceManager.startBootPhase(
                       SystemService.PHASE_ACTIVITY_MANAGER_READY);
               ...
               //phase600
               mSystemServiceManager.startBootPhase(
                       SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
            }
        }
    }
}
  • start: 创建AMS, PMS, LightsService, DMS.
  • phase100: 进入Phase100, 创建PKMS, WMS, IMS, DBMS, LockSettingsService, JobSchedulerService, MmsService等服务;
  • phase480 && 500: 进入Phase480, 调用WMS, PMS, PKMS, DisplayManagerService这4个服务的systemReady();
  • Phase550: 进入phase550, 执行AMS.systemReady(), 启动SystemUI, WebViewFactory, Watchdog.
  • Phase600: 进入phase600, 执行AMS.systemReady(), 执行各种服务的systemRunning().
  • Phase1000: 进入1000, 执行finishBooting, 启动启动on-hold进程.

4.7 AMS.systemReady

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    public void systemReady(final Runnable goingCallback) {
        ... //update相关
        mSystemReady = true;

        //杀掉所有非persistent进程
        removeProcessLocked(proc, true, false, "system update done");
        mProcessesReady = true;

        goingCallback.run();  //[见小节1.6.2]

        addAppLocked(info, false, null); //启动所有的persistent进程
        mBooting = true;

        //启动home
        startHomeActivityLocked(mCurrentUserId, "systemReady");
        //恢复栈顶的Activity
        mStackSupervisor.resumeTopActivitiesLocked();
    }
}

System_server主线程的启动工作,总算完成, 进入Looper.loop()状态,等待其他线程通过handler发送消息再处理.

五. app

对于普通的app进程,跟system_server进程的启动过来有些类似.不同的是app进程是向发消息给system_server进程, 由system_server向zygote发出创建进程的请求.

理解Android进程创建流程, 可知进程创建后 接下来会进入ActivityThread.main()过程。

5.1 ActivityThread.main

public static void main(String[] args) {
    ...
    Environment.initForCurrentUser();
    ...
    Process.setArgV0("<pre-initialized>");
    //创建主线程looper
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false); //attach到系统进程

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

    //主线程进入循环状态
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

app进程的主线程调用栈的栈底如下:

...
at android.app.ActivityThread.main(ActivityThread.java:5442)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

跟前面介绍的system_server进程调用栈对比:

at com.android.server.SystemServer.main(SystemServer.java:175)
at java.lang.reflect.Method.invoke!(Native method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

六. 实战分析

以下列举启动部分重要进程以及关键节点会打印出的log

/system/bin/vold: 383
/system/bin/lmkd: 432
/system/bin/surfaceflinger: 434
/system/bin/debuggerd64: 537
/system/bin/mediaserver: 540
/system/bin/installd: 541
/system/vendor/bin/thermal-engine: 552

zygote64: 557
zygote: 558
system_server: 1274

1. before zygote

//启动vold, 再列举当前系统所支持的文件系统.  执行到system/vold/main.cpp的main()
11-23 14:36:47.474   383   383 I vold    : Vold 3.0 (the awakening) firing up  
11-23 14:36:47.475   383   383 V vold    : Detected support for: ext4 vfat   
//使用内核的lmk策略
11-23 14:36:47.927   432   432 I lowmemorykiller: Using in-kernel low memory killer interface
//启动SurfaceFlinger
11-23 14:36:48.041   434   434 I SurfaceFlinger: SurfaceFlinger is starting
11-23 14:36:48.042   434   434 I SurfaceFlinger: SurfaceFlinger's main thread ready to run. Initializing graphics H/W... // 开机动画 11-23 14:36:48.583 508 508 I BootAnimation: bootanimation launching ... // debuggerd 11-23 14:36:50.306 537 537 I : debuggerd: starting // installd启动 11-23 14:36:50.311 541 541 I installd: installd firing up // thermal守护进程 11-23 14:36:50.369 552 552 I ThermalEngine: Thermal daemon started 

2. zygote

// Zygote64进程(Zygote): AndroidRuntime::start
11-23 14:36:51.260   557   557 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
// Zygote64进程: AndroidRuntime::startVm
11-23 14:36:51.304   557   557 D AndroidRuntime: CheckJNI is OFF

// 执行ZygoteInit.preload()
11-23 14:36:52.134   557   557 D Zygote  : begin preload
// 执行ZygoteInit.preloadClasses(), 预加载3860个classes, 花费时长746ms
11-23 14:36:52.134   557   557 I Zygote  : Preloading classes...
11-23 14:36:52.881   557   557 I Zygote  : ...preloaded 3860 classes in 746ms.

// 执行ZygoteInit.preloadClasses(), 预加载86组资源, 花费时长179ms
11-23 14:36:53.114   557   557 I Zygote  : Preloading resources...
11-23 14:36:53.293   557   557 I Zygote  : ...preloaded 86 resources in 179ms.

// 执行ZygoteInit.preloadSharedLibraries()
11-23 14:36:53.494   557   557 I Zygote  : Preloading shared libraries...
11-23 14:36:53.503   557   557 D Zygote  : end preload

// 执行com_android_internal_os_Zygote_nativeForkSystemServer(),成功fork出system_server进程
11-23 14:36:53.544   557   557 I Zygote  : System server process 1274 has been created
// Zygote开始进入runSelectLoop()
11-23 14:36:53.546   557   557 I Zygote  : Accepting command socket connections

3. system_server

//进入system_server, 建立跟Zygote进程的socket通道
11-23 14:36:53.586  1274  1274 I Zygote  : Process: zygote socket opened, supported ABIS: armeabi-v7a,armeabi
// 执行SystemServer.run()
11-23 14:36:53.618  1274  1274 I SystemServer: Entered the Android system server!   <===> boot_progress_system_run
// 等待installd准备就绪
11-23 14:36:53.707  1274  1274 I Installer: Waiting for installd to be ready.

//服务启动
11-23 14:36:53.732  1274  1274 I ActivityManager: Memory class: 192

//phase100
11-23 14:36:53.883  1274  1274 I SystemServiceManager: Starting phase 100
11-23 14:36:53.902  1274  1274 I SystemServer: Package Manager
11-23 14:37:03.816  1274  1274 I SystemServer: User Service
...
11-23 14:37:03.940  1274  1274 I SystemServer: Init Watchdog
11-23 14:37:03.941  1274  1274 I SystemServer: Input Manager
11-23 14:37:03.946  1274  1274 I SystemServer: Window Manager
...
11-23 14:37:04.081  1274  1274 I SystemServiceManager: Starting com.android.server.MountService$Lifecycle
11-23 14:37:04.088  1274  2717 D MountService: Thinking about reset, mSystemReady=false, mDaemonConnected=true
11-23 14:37:04.088  1274  1274 I SystemServiceManager: Starting com.android.server.UiModeManagerService
11-23 14:37:04.520  1274  1274 I SystemServer: NetworkTimeUpdateService

//phase480 && 500
11-23 14:37:05.056  1274  1274 I SystemServiceManager: Starting phase 480
11-23 14:37:05.061  1274  1274 I SystemServiceManager: Starting phase 500
11-23 14:37:05.231  1274  1274 I ActivityManager: System now ready  <==> boot_progress_ams_ready
11-23 14:37:05.234  1274  1274 I SystemServer: Making services ready
11-23 14:37:05.243  1274  1274 I SystemServer: WebViewFactory preparation

//phase550
11-23 14:37:05.234  1274  1274 I SystemServiceManager: Starting phase 550
11-23 14:37:05.237  1274  1288 I ActivityManager: Force stopping com.android.providers.media appid=10010 user=-1: vold reset

//Phase600
11-23 14:37:06.066  1274  1274 I SystemServiceManager: Starting phase 600
11-23 14:37:06.236  1274  1274 D MountService: onStartUser 0

4. logcat小技巧

通过adb bugreport抓取log信息.先看zygote是否起来, 再看system_server主线程的运行情况,再看ActivityManager情况

adb logcat -s Zygote
adb logcat -s SystemServer
adb logcat -s SystemServiceManager
adb logcat | grep "1359 1359" //system_server情况
adb logcat -s ActivityManager

现场调试命令

  1. cat proc/[pid]/stack ==> 查看kernel调用栈
  2. debuggerd -b [pid] ==> 也不可以不带参数-b, 则直接输出到/data/tombstones/目录
  3. kill -3 [pid] ==> 生成/data/anr/traces.txt文件
  4. lsof [pid] ==> 查看进程所打开的文件

七. 总结

各大核心进程启动后,都会进入各种对象所相应的main()方法,如下

进程 主方法
init进程 Init.main()
zygote进程 ZygoteInit.main()
app_process进程 RuntimeInit.main
system_server进程 SystemServer.main()
app进程 ActivityThread.main()

注意其中app_process进程是指通过/system/bin/app_process来启动的进程,且后面跟的参数不带–zygote,即并非启动zygote进程。 比如常见的有通过adb shell方式来执行am,pm等命令,便是这种方式。

关于重要进程重启的过程,会触发哪些关联进程重启名单:

  • zygote:触发media、netd以及子进程(包括system_server进程)重启;
  • system_server: 触发zygote重启;
  • surfaceflinger:触发zygote重启;
  • servicemanager: 触发zygote、healthd、media、surfaceflinger、drm重启

所以,surfaceflinger,servicemanager,zygote自身以及system_server进程被杀都会触发Zygote重启。

 

猜你喜欢

转载自blog.csdn.net/kdsde/article/details/82622909