Binder

为什么是Binder

img

具体见QA。

一次完整的 Binder IPC 通信过程通常是这样:

其内存流向是这样的:

  1. 首先 Binder 驱动在内核空间创建一个数据接收缓存区;
  2. 接着在内核空间开辟一块内核缓存区,建立内核缓存区内核中数据接收缓存区之间的映射关系,以及内核中数据接收缓存区接收进程用户空间地址的映射关系;
  3. 发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。

如下图:

nzNJUA.png

Read more

PackageManager

img

PackageManger的核心作用:

  1. 在系统启动过程中,通过**PackageManagerService(PKMS)*对特定系统文件(如package.list, package.xml)进行扫描解析后,将所有app的信息整合存储,通过IPackageManger*对外暴露
  2. 通过PackageInstallerService提供Apk/Apex的安装、更新、卸载等操作(IPackageInstaller)
  3. 应用运行过程中的权限检查
Read more

Window

https://www.cnblogs.com/huan89/p/14111360.html

从来都没什么Window,有的只是一个个View树,每个窗口(activity/dialog/popupWindow)都是一个view树(代码中都是叫addView,直到WMS中才叫addWindow),在需要显示时被添加进WMS中,最后通过surfalceFlinger合成后渲染到屏幕中。

每个窗口都对应一个Token,一个应用只对应一个session。

从Window视角看ActivityStart

Activity

简述:首先回顾一下,activity是怎么显示出来的:

  1. 为activity创建PhoneWindow和WindowManager(WindowManagerImpl)对象

在handleLaunchActivity()被回调的时候,调用WindowManagerGlobal.initialize();初始化WindoWindowManagerGlobal,之后 Application app = r.packageInfo.makeApplication(false, mInstrumentation);创建Application(如果还没有创建过Application),然后调用activity.attach(),这里面 mWindow = new PhoneWindow(this, window, activityConfigCallback);初始化PhoneWindow并给它设置WindowManager

1
2
3
4
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

Window.setWindowManager()中通过WMS创建了WindowManagerImpl(其实就是个一百多行代码的壳)。

从这里可以看到是利用系统服务的windowManager来创建新的windowManagerImpl,因而这个应用所有的WindowManagerImpl都是同个内核windowManager,而创建出来的仅仅是包了个壳。

  1. setContentView实际上掉的是getWindow()(也就是上面的PhoneWindow)的setContentView(),其中调用PhoneWindow.installDecor(),
  • 首先看decorView创建了没有,没有的话创建DecorView
  • 把布局加载到DecorView中(LayoutInflater加载预设模板布局,见下)

DecorView是在PhoneWindow中预设好的一个布局,这个布局长这样:

decorView

他是一个垂直排列的布局,上面是ActionBar,下面是ContentView,他是一个FrameLayout。我们的Activity布局就加载到ContentView里进行显示。所以Decorview是Activity布局最顶层的viewGroup。

// DecorView创建完成了,但还缺少了最重要的一步:把DecorView作为window添加到屏幕上。

  1. 在handleResumeActivity中,执行了最后的 wm.addView(mDecor, getWindow().getAttributes());

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
    String reason) {
    // 调用Activity的onResume方法
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    ...
    // 让decorView显示到屏幕上
    if (r.activity.mVisibleFromClient) {
    r.activity.makeVisible();
    }

    void makeVisible() {
    if (!mWindowAdded) {
    ViewManager wm = getWindowManager();
    wm.addView(mDecor, getWindow().getAttributes());
    mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
    }

    直接调用WindowManagerImpl的addView方法来吧decorView添加到屏幕上,至此,我们的Activity界面就会显示在屏幕上了。

    进一步需要看WindowManagerImpl.addView之后是怎么将View(即Window)添加入屏幕的

    1. wm.addView(mDecor, getWindow().getAttributes());其中wm是WindowManagerImpl实例,WindowManagerImpl.addView其实是通过桥接,调用WindowManagerGlobal的全局单例的方法WindowManagerGlobal.addView,该方法中会新建一个ViewRootImpl,然后将入参的decorView、新建的ViewRootImp等加入自身维护的mViews、mRoots列表中,同时将DecorView注入ViewRootImplroot.setView(view, wparams, panelParentView)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    WindowMangerGlobal.clss
    维护着WMS实例sWindowManagerService和以下列表

    //应用所有的decorView
    private final ArrayList<View> mViews = new ArrayList<View>();
    //应用所有的ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    //应用所有的WindowManager.LayoutParams
    private final ArrayList<WindowManager.LayoutParams> mParams =
    new ArrayList<WindowManager.LayoutParams>();

    public void addView(View view, ViewGroup.LayoutParams params,
    Display display, Window parentWindow) {
    //... 主要是校验参数和调整子窗口的参数
    synchronized (mLock) {
    ...
    // 这里新建了一个viewRootImpl,并设置参数
    root = new ViewRootImpl(view.getContext(), display);
    view.setLayoutParams(wparams);

    // 添加到windowManagerGlobal的三个重要list中,每一个window所对应的这三个对象都会保存在这里,之后对window的一些操作就可以直接来这里取对象了。当window被删除的时候,这些对象也会被从list中移除。
    mViews.add(view);
    mRoots.add(root);
    mParams.add(wparams);

    // 最后通过viewRootImpl来添加window
    try {
    root.setView(view, wparams, panelParentView);
    }
    ...
    }
    }

​ 5. ViewRootImpl.setView()将调用到

1
2
3
4
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);

这个mWindowSession来自于构造器的入参,是由WindowManagerGlobal.getWindowSession中来的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
...
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
...
});
}
...
}
return sWindowSession;
}
}

可以看出,这个session是一个单例,也就是整个应用的所有viewRootImpl的windowSession都是同一个,也就是一个应用只有一个windowSession

Session.addToDisplay实际上走的是WMS的addWindow方法,后面的逻辑就交给WMS去处理了,WMS就会创建window,然后结合参数计算window的高度等等,最后使用viewRootImpl进行绘制。

window的添加过程是通过PhoneWindow对应的WindowManagerImpl来添加window,内部会调用WindowManagerGlobal来实现。WindowManagerGlobal会使用viewRootImpl来进行跨进程通信让WMS执行创建window的业务。

每个应用都有一个windowSession,用于负责和WMS的通信,如ApplicationThread与AMS的通信。

Other Window

dialog和popupwindow的层级是10001999,在这个层级都属于子window而不是应用Window(199),子Window需要附属于父Window(Activity,也就是应用Window)才能显示,dialog虽然创建了一个PhoneWindow,但是popupWindow最终也创建了一个Window,只是它不是PhoneWindow而已,popupWindow和dialog的显示都需要依赖父Window的Token,其实两者都需要依赖于Activiy

那么,PopupWindow则是在构造器中时将入参的contentView直接执行 setContentView(contentView);,然后在showAtLocation()中调用了preparePopup() 创建它的decorView(PopupDecorView)之后invokePopup()调用执行mWindowManager.addView(decorView, p);

  • 根据参数构建popupDecorView
  • 把popupDecorView添加到屏幕上

dismiss()中调用mWindowManager.removeViewImmediate(decorView);

Dialog

dialog的创建过程Activity比较像:构造器创建PhoneWindow,setContentView初始化DecorView,show时候添加DecorView。

  • 构造函数中创建PhoneWindow,设置WindowManger(这里拿的是传入的context,实际上这context只能是actiivty,的WindowManager)
  • Dialog.setContentView时掉PhoneWindow.setContentView来初始化DecorView
  • show()时候调用了mWindowManager.addView(mDecor, l);
  • dismiss()时候调用mWindowManager.removeViewImmediate(mDecor);

总结

  • dialog和popupWindow不同,dialog创建了新的PhoneWindow,使用了PhoneWindow的DecorView模板。而popupWindow没有,popupWindow他也对应一个window,因为它也是通过windowManager添加上去的,不属于Activity的view树。
  • dialog的显示层级数更高,会直接显示在Activity上面,在dialog后添加的popUpWindow也会显示在dialog下
  • dialog的创建流程和activity非常像
Read more