安卓预面试总结

1、内存优化

内存泄漏和内存溢出的区别?

内存溢出:指申请内存时,没有足够的内存空间供其使用,出现oom,系统为每个应用申请到的内存有限,一般为64M或128M,我们可以在清单文件中配置android:largeheap="true"从而给app申请更大的内存空间。

内存泄漏:申请内存后,被某个对象一直持有,无法释放已申请的内存空间,内存泄漏堆积会造成无论多少内存,迟早被吃光。

方法区:存储运行时常量池、已被虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等数据。
虚拟机栈:存放方法运行时所需的数据,称为栈帧
堆:存储实例对象

内存溢出分类:堆内存溢出、栈内存溢出

内存泄漏分类:方法区 堆 虚拟栈

实例1:内存溢出,如注册回调,忘记注销。添加到队列,忘记控制队列大小

ArrayList list = new ArrayList();
while(true) {
	list.add(new Heap());//添加到队列,忘记控制队列大小
}

实例2:fastjson对象转json string 解决循环引用报错(溢出)

间接循环引用
安卓预面试总结_第1张图片
堆内存溢出:对象添加到变量
栈内存溢出:递归

1.1 内存泄漏优化

1.1.1 单例(变量生命周期不一致导致内存泄漏)

import android.content.Context;

public class AppSettings {

    private static AppSettings sInstance;
    private Context mContext;

    private AppSettings(Context context) {
        this.mContext = context;
    }

    public static AppSettings getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppSettings(context);
        }
        return sInstance;
    }
}

修改:

import android.content.Context;

public class AppSettings {

    private static AppSettings sInstance;
    private Context mContext;

    private AppSettings(Context context) {
        this.mContext = context.getApplicationContext();
    }

    public static AppSettings getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppSettings(context);
        }
        return sInstance;
    }
}

1.1.2 静态内部类(存在于整个进程中导致内存泄漏)

静态变量导致内存泄漏:静态变量存储在方法区,它的生命周期从类加载开始到整个进程结束。一旦变量初始化后,它所持有的引用只有等到进程结束才会释放。

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private static Info sInfo;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (sInfo == null) {
            sInfo = new Info(this);
        }
    }
}

class Info {

    Activity activity;

    public Info(Activity activity) {
        this.activity = activity;
    }
}

修改:

package com.example.vip05;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private static Info sInfo;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (sInfo == null) {
            sInfo = new Info(this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (sInfo != null) {
            sInfo = null;
        }
    }
}

class Info {

    Activity activity;

    public Info(Activity activity) {
        this.activity = activity;
    }
}

1.1.3 非静态内部类(存在于整个进程中导致内存泄漏)

非静态内部类(包括匿名内部类)默认就会持有外部类的引用,当非静态内部类对象的生命周期比外部类对象生命周期长,就会导致内存泄漏,常见(Handler,Thread,AsyncTask)

Handler会被底层ThreadLocal绑定导致生命周期很长


import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }


    //Handler会被底层ThreadLocal绑定导致生命周期很长
    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(@NonNull Message msg) {
            if (msg.what == 1) {
                //执行
            }
            //super.handleMessage(msg);
        }
    };
}

修改:


import android.os.Handler;
import android.os.Message;

import androidx.annotation.NonNull;

import java.lang.ref.WeakReference;

public class MyHandler extends Handler {

    private WeakReference<MainActivity> activityWeakReference;
    
    public MyHandler(MainActivity activity) {
        activityWeakReference = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(@NonNull Message msg) {
        //super.handleMessage(msg);
        MainActivity activity = activityWeakReference.get();
        if (activity != null) {
            if (msg.what == 1) {
                //执行
            }
        }
    }
}

1.1.4 匿名内部类(存在于整个进程中导致内存泄漏)

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

修改:activity改为软引用

1.1.5 未取消注册或回调(导致内存泄漏)


import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.registerReceiver(mReceiver, new IntentFilter());
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
                  
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.unregisterReceiver(mReceiver);
    }
}

1.1.6 集合中的对象未清理(导致内存泄漏)

在循环中把引用O释放了,但是它是被添加到objectList中,所以objectList也持有对象的引用,此时该对象是无法被GC回收的。因此对象如果添加到集合中,还必须从中删除,最简单防止内存泄漏的方法

public class MainActivity extends AppCompatActivity {

    List<Object> objectList = new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        for (int i=0; i< 10;i++) {
            Object o = new Object();
            objectList.add(o);
            o= null;
        }
    }
}

修改:
因此对象如果添加到集合中,还必须从中删除,最简单防止内存泄漏的方法

1.1.7 webview(导致内存泄漏)

webview下面持有activity引用,造成webview内存无法释放,即使是调用webview.destory也无法解决

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <WebView
            android:id="@+id/webview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>

</LinearLayout>

    WebView mWebview = null;
    FrameLayout mWebViewContainer = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebview = findViewById(R.id.webview);
        mWebViewContainer = findViewById(R.id.container);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mWebViewContainer.removeView(mWebview);
        
    }

修改:在销毁webview之前需要先将webview从父容器中移除,然后再销毁webview

    WebView mWebview = null;
    FrameLayout mWebViewContainer = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebview = findViewById(R.id.webview);
        mWebViewContainer = findViewById(R.id.container);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mWebViewContainer.removeView(mWebview);//在销毁webview之前需要先将webview从父容器中移除,然后再销毁webview
        mWebview.stopLoading();
        mWebview.getSettings().setJavaScriptEnabled(false);
        mWebview.clearHistory();
        mWebview.removeAllViews();
        mWebview.destroy();
    }

1.2 内存抖动 json转javabean

内存抖动:短时间内有大量对象被创建或被内存回收的现象,内存抖动出现的原因主要是频繁在循环里创建对象,如果抖动很频繁,会导致垃圾回收机制频繁运行

内存抖动的解决办法:

1、避免在循环体内创建对象,应该把对象创建移到循环体外

2、自定义view的onDraw()方法会被频繁调用,所以在这里不应该频繁创建对象

3、当需要大量使用Bitmap时,把他们缓存到数组中实现复用

4、对于能够复用的对象,同理可以使用对象池将它们缓存起来

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setAlpha(0);
        canvas.drawColor(0);
    }

解决:复用

1.3 垃圾回收机制

GCRoot 引用链

垃圾回收算法(标记-清除)

  1. GC分为两个阶段
  2. 标记和清除。首先标记所有可回收的对象,在标记完成后统一回收所有被标记的对象。同时会产生不连续的内存碎片。
  3. 碎片过多会导致以后程序运行时需要分配较大对象时,无法找到足够的连续内存,而不得已再次触发GC

垃圾回收算法(标记-整理)

  1. 分为2个阶段,首先标记可回收的对象,再将存活的对象都向一端移动,然后清理掉边界以外的内存。
  2. 此方法避免标记-清除算法的碎片问题,同时也避免了复制算法的空间问题。
  3. 一般年轻代中执行GC后,会有少量的对象存活,就会选用复制算法,只要付出少量的存活对象复制成本就可以完成收集。
  4. 而老年代中因为对象存活率高,没有额外过多内存空间分配,就需要使用标记-清理或者标记-整理算法来进行回收。

static变量,类放在方法区
Fruit fruit ,int z, string[] args放在栈区
new Fruit 对象放在堆区

开辟线程,int k 会放在新的栈区

        new Thread() {
            @Override
            public void run() {
                super.run();
                int k = 100;
            }
        }.start();
class Fruit {
      static int x = 10;
        static BigWaterMelon bigWaterMelon_1 = new BigWaterMelon(x);
        
        int y = 20;
        BigWaterMelon bigWaterMelon_2 = new BigWaterMelon(y);
        
        public static void main(String[] args) {
            
            final Fruit fruit = new Fruit();
            int z = 30;
            BigWaterMelon bigWaterMelon_3 = new BigWaterMelon(z);
            
            new Thread() {
                @Override
                public void run() {
                    int k = 100;
                    setWeight(k);
                }
     
                void setWeight(int waterMelonWeight) {
                    fruit.bigWaterMelon_2.weight = waterMelonWeight;
                }
            }.start();
        }
    }
    
    class BigWaterMelon {
     
        public BigWaterMelon(int weight) {
            this.weight = weight;
        }
     
        public int weight;
    }

final去修饰,会变成全局变量共享的

2、性能优化

3、Binder

周六 Binder面试系列,带你读懂binder进程通信机制
1 进程通信本质,内存拷贝详解
2 一次拷贝的实现方式
3 mmap函数实现内存与磁盘的映射关系

1、谈谈你对binder的理解?

binder 是 Android 中主要的跨进程通信方式,binder 驱动和 service manager 分别相当于网络协议中的路由器和 DNS,并基于 mmap 实现了 IPC 传输数据时只需一次拷贝。

binder 包括 BinderProxy、BpBinder 等各种 Binder 实体,以及对 binder 驱动操作的 ProcessState、IPCThreadState 封装,再加上 binder 驱动内部的结构体、命令处理,整体贯穿 Java、Native 层,涉及用户态、内核态,往上可以说到 Service、AIDL 等,往下可以说到 mmap、binder 驱动设备,是相当庞大、繁琐的一个机制。

2、基于 mmap 又是如何实现一次拷贝的?
安卓预面试总结_第2张图片
Client 与 Server 处于不同进程有着不同的虚拟地址规则,所以无法直接通信。而一个页框可以映射给多个页,那么就可以将一块物理内存分别与 Client 和 Server 的虚拟内存块进行映射。

如图, Client 就只需 copyfromuser 进行一次数据拷贝,Server 进程就能读取到数据了。另外映射的虚拟内存块大小将近 1M (1M-8K),所以 IPC 通信传输的数据量也被限制为此值。

3、怎么理解页框和页?

页框是指一块实际的物理内存,页是指程序的一块内存数据单元。内存数据一定是存储在实际的物理内存上,即页必然对应于一个页框,页数据实际是存储在页框上的。

页框和页一样大,都是内核对内存的分块单位。一个页框可以映射给多个页,也就是说一块实际的物理存储空间可以映射给多个进程的多个虚拟内存空间,这也是 mmap 机制依赖的基础规则。

4、简单说下 binder 的整体架构

安卓预面试总结_第3张图片
​ Client 通过 ServiceManager 或 AMS 获取到的远程 binder 实体,一般会用 Proxy 做一层封装,比如 ServiceManagerProxy、 AIDL 生成的 Proxy 类。而被封装的远程 binder 实体是一个 BinderProxy。

​ BpBinder 和 BinderProxy 其实是一个东西:远程 binder 实体,只不过一个 Native 层、一个 Java 层,BpBinder 内部持有了一个 binder 句柄值 handle。

​ ProcessState 是进程单例,负责打开 Binder 驱动设备及 mmap;IPCThreadState 为线程单例,负责与 binder 驱动进行具体的命令通信。

​ 由 Proxy 发起 transact() 调用,会将数据打包到 Parcel 中,层层向下调用到 BpBinder ,在 BpBinder 中调用 IPCThreadState 的 transact() 方法并传入 handle 句柄值,IPCThreadState 再去执行具体的 binder 命令。

​ 由 binder 驱动到 Server 的大概流程就是:Server 通过 IPCThreadState 接收到 Client 的请求后,层层向上,最后回调到 Stub 的 onTransact() 方法。

​ 当然这不代表所有的 IPC 流程,比如 Service Manager 作为一个 Server 时,便没有上层的封装,也没有借助 IPCThreadState,而是初始化后通过 binder_loop() 方法直接与 binder 驱动通信的。

4、Activity启动

安卓预面试总结_第4张图片
E:\架构师\码牛学院VIP课程\第一轮\(2)FrameWork源码与UI新技术\VIP25-2020.8.27-AMS服务执行流程详解 -David

5、AMS服务执行流程

周四 AMS服务执行流程详解
1Activity的管理与生命周期执行机制
2ActivityThread源码分析
3 Apk的启动流程与Activity启动机制
4 项目应用(Hook Ams中的startActivity方法实现集中式登录)
5 AMS与PMS 面试技巧总结

反射PMS demo

package com.maniu.pmsmniu;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import dalvik.system.DexClassLoader;

public class MyPackageParser {
    public    void parserReceivers(Context context, File apkFile) throws Exception {
        /**
         *  PackageParser pp = new PackageParser();
         *  pr.pkg = parsePackage(pp, scanFile, parseFlags);
         *  pms解析一个apk的过程
         *  应用也想解析    解析apk    换肤   热修复   插件
         */
        Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
//        8.0  9.0  10.0  优化了很多
        Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class,boolean.class);
        Object packageParser = packageParserClass.newInstance();
        parsePackageMethod.setAccessible(true);

//  pp.parsePackage(Fil);适配
        Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_RECEIVERS, false);
        Field receiversField = packageObj.getClass().getDeclaredField("receivers");

        List receivers = (List) receiversField.get(packageObj);
//        recervers  拉出来    然后动态注册这个广播    下载下了
//dex加载的优化
        DexClassLoader dexClassLoader = new DexClassLoader(apkFile.getAbsolutePath(),
                context.getDir("plugin", Context.MODE_PRIVATE).getAbsolutePath(),
                null, context.getClassLoader());
// 99号
        Class<?> componentClass = Class.forName("android.content.pm.PackageParser$Component");

        Field intentsField = componentClass.getDeclaredField("intents");


///ActivityInfo   -----  BroadcastReceiver
//
//
// com.maniu.receive.DavidReceiver  类名怎么获取     david  采取


        for (Object receiverObject : receivers) {
            String name = (String) receiverObject.getClass().getField("className").get(receiverObject);
            Class clazz=dexClassLoader.loadClass(name);
            List<? extends IntentFilter> filters = (List<? extends IntentFilter>) intentsField.get(receiverObject);
            for (IntentFilter filter : filters) {
                BroadcastReceiver broadcastReceiver = (BroadcastReceiver) clazz.newInstance();
                context.registerReceiver(broadcastReceiver, filter);
            }
        }
    }
}

package com.maniu.pmsmniu;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import androidx.annotation.Nullable;
//IBinder   强联系通信 方式 侯敏会讲的   防止
public class ServiceDavie extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

package com.maniu.pmsmniu;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Toast;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkPermission(this);


        startActivity(new Intent());
        IntentFilter filter =new IntentFilter();
        filter.addAction("com.maniu.receiver2");
        registerReceiver(new PersonPickerRecevier(), filter);
    }
    class PersonPickerRecevier extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "3: 宿主三次握手完成", Toast.LENGTH_SHORT).show();
        }
    }
    public static boolean checkPermission(
            Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            activity.requestPermissions(new String[]{
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            }, 1);

        }
        return false;
    }
    public void registBroaderCast(View view) {

        MyPackageParser myPackageParser = new MyPackageParser();
        try {
            myPackageParser.parserReceivers(this, new File(Environment.getExternalStorageDirectory(), "input.apk"));
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public void sendBroaderCast(View view) {
//Object
        Toast.makeText(this, "1: 宿主:  准备发送广播", Toast.LENGTH_SHORT).show();
        Intent intent =new Intent();
        intent.setAction("com.maniu.receiver1");
        sendBroadcast(intent);
    }
}

插件:

package com.maniu.receive;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class DavidReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, " 2----------,收到你的信息了", Toast.LENGTH_SHORT).show();
        Intent intent1 =new Intent();
        intent1.setAction("com.maniu.receiver2");
        context.sendBroadcast(intent1);
    }
}

安卓预面试总结_第5张图片
安卓预面试总结_第6张图片
安卓预面试总结_第7张图片
安卓预面试总结_第8张图片
安卓预面试总结_第9张图片
安卓预面试总结_第10张图片
安卓预面试总结_第11张图片

6、PMS服务启动原理详解,从开机到APP启动PMS服务处理机制与流程

周一 PMS服务启动原理详解,从开机到APP启动PMS服务处理机制与流程
1 Apk安装是怎么进行的,PMS如何分析APK压缩文件
2 开机时PMS做了什么,data/app目录下的扫描与分析
3 PakageParse类源码解读
4 AndroidManifest 为什么要按照google设计的写,PMS告诉你真相
5 AMS与PMS交互过程解析
6 项目应用(手写可下载的广播组件)

PMS作用:
快速定位到某个类,activity的入口,手机启动过程中70%时间都是在PMS

安卓预面试总结_第12张图片
启动引导服务,启动核心服务,启动其他服务,在引导服务中启动AMS,PMS

7、PMS实现apk解析

安装apk时,apk压缩包包含dex、resource、AndroidManifest文件,
dex:是加载过程中需要被翻译成机器码指令
odex机制:base.odex 1M -> 2.6M 磁盘容量
安卓预面试总结_第13张图片

package com.maniu.pmsmniu;

import android.content.Context;
import android.content.pm.PackageManager;

import java.io.File;
import java.lang.reflect.Method;

public class MyPackageParser {
    public void parserReceivers(Context context, File apkFile) throws Exception {

        /**
         *  PackageParser pp = new PackageParser();
         *   pr.pkg = parsePackage(pp, scanFile, parseFlags);
         */
        Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
        Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class);
        Object packageParser = packageParserClass.newInstance();

        //  pp.parsePackage(Fil);适配
        Object packageObj = parsePackageMethod.invoke(packageParser, apkFile, PackageManager.GET_RECEIVERS);
        packageObj.hashCode();
    }
}

调用:

package com.maniu.pmsmniu;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;

import java.io.File;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkPermission(this);
    }
    public static boolean checkPermission(
            Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            activity.requestPermissions(new String[]{
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            }, 1);

        }
        return false;
    }
    public void registBroaderCast(View view) {

        MyPackageParser myPackageParser = new MyPackageParser();
        try {
            myPackageParser.parserReceivers(this, new File(Environment.getExternalStorageDirectory(), "input.apk"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PMS总结:

PMS服务启动原理详解,从开机到APP启动PMS服务处理机制与流程
1 PMS全称PackageManagerService, 由SystemServer启动,PMS运行在单独的系统进程中
启动的时候通过ServiceManager.addService存入PMS对象,应用层通过ServiceManager.getService获取对象
由于PMS是单独进程,获取的对象是一个IBinder接口。

2 PMS的作用时期主要是集中在手机开机时期,会扫描主要/data/app 和/systema/app两个目录
扫描比较耗费时间,Android10.0 9.0 通过线程,缓存机制进行优化,9.0以下没有的
扫描所有的apk文件 只是读取每一个AndroidManifest.xml文件信息,通过dom解析,判断tagname,解析成对应四大组件
然后统一缓存在一个Package对象中

8、Binder机制详解(应用层), Proxy与Stub机制分析

1 应用层Binder源码分析
2 Android为什么开辟独一无二的Binder通信
3 详解AIDL生成的Java类的过程

周四 Binder面试系列,带你读懂binder进程通信机制
1.阿里三面Binder进程通信 Binder从应用层到原理层讲解
2 进程通信本质,内存拷贝详解
3 一次拷贝的实现方式
4 mmap函数实现内存与磁盘的映射关系

9、系统启动以及APP启动流程

安卓预面试总结_第14张图片
安卓预面试总结_第15张图片
安卓预面试总结_第16张图片
安卓预面试总结_第17张图片
安卓预面试总结_第18张图片

10、深度剖析WMS

印象笔记:
https://app.yinxiang.com/fx/7e223892-caf1-4db0-8467-f92709875db9

脑图(脑图太大导不出来,大家线上看吧):
https://www.processon.com/view/link/61a7ebe80e3e746f85f57285
密码:Wk3B

博客
https://www.jianshu.com/u/109ce62c77c8

UI具体绘制流程
https://www.jianshu.com/p/4e3e25092015

安卓预面试总结_第19张图片
安卓预面试总结_第20张图片
UI从数据加载到具体展现的过程

安卓预面试总结_第21张图片
Android APP运行时进程协作关系

安卓预面试总结_第22张图片









安卓预面试总结_第23张图片

1、数据加载:

activity从启动到view数据加载流程

2、图形绘制:

  1. View这些数据送到绘制层面之前如何管理?
  2. 如何绘制出一张我们看到的图形?

Choreographer来完成对于16.6ms时间管理以及跳帧处理
Choreographer定位就是去控制什么时候请求同步信号且推动绘制启动
Choreographer内部维护了一个Handler,刚进来时post一个消息,mFrameScheduled保证只有一帧数据在绘制,保证在主线程中进行绘制

SurfaceFlinger:
安卓预面试总结_第24张图片
所谓的垂直同步信号就是去下层底层驱动要一个上一帧绘制的时间

relayoutWindow->

  1. 保存信息到WMS
  2. 判定是否有需要重新计算相关坐标等数据可见性
  3. 去底层申请一个surface地址回来

图像生成
图像引擎生成图像数据bitmap,进行显示
canvas
unlockCanvasAndPost->主要核心目的是去进行对于绘制请求的发送

总结:

  1. 绘制流程
    数据加载->要有实例(activity,view)->绘制->编舞者->具体绘制->自己准备surface记录数据->下层准备一个surface记录数据->canvas记录数据->生成bitmap图像数据->surface在底层的存储是一个队列,采取生产消费模式,
    生产者(上层WMS)
    消费者(surfaceflinger)->拿到不同surface->合成一个bitmap->framebuffer中进行展示

WMS在这里扮演的角色:数据管理者,与surfaceFlinger的通信协调者
AMS是XML数据的管理者

11、全面解析事件处理及分发过程

全面解析事件处理及分发过程
技术点:
1.事件分发基本认知
2.android事件处理的三个流程
3.事件采集流程
4.内核到IMS过程
5.IMS如何推送数据给ViewRootImpl
6.WMS在事件采集中扮演的角色

预习资料-脑图笔记:
https://www.processon.com/view/link/61b1ff83f346fb6a6f1a2cae
密码:P74w

课堂笔记:
https://app.yinxiang.com/fx/8aab8fe8-08bd-4dc3-a714-a6e2a60f65c8
事件分发基本认知

事件中涉及到的四个触摸事件
安卓预面试总结_第25张图片
android事件处理的三个流程
安卓预面试总结_第26张图片


事件采集流程
安卓预面试总结_第27张图片
InputReaderThread采集过程
安卓预面试总结_第28张图片
InputDispatcherThread分发过程
安卓预面试总结_第29张图片
InputChannel通信
安卓预面试总结_第30张图片
事件的本质是什么?
他是以一个什么样的形式存在?
事件的本质就是一组数据,由硬件设备采集
硬件设备采集,采集到哪里?

/dev/input/所有设备,event0->修改了数据就会即使触发

adb shell
/dev/input/
adb shell input keyevent 4

如何动起来的?linux层面如何做到文件监听

linux中内核是一套应用程序,对外提供一组API
java IO -> io 操作系统,操作系统去完成文件操作
epoll->监听fd变化来进行操作
iNotify->监听文件变化,但不能回调->fd

/proc/1/fd/

1、用epoll_create、inotify_init两个函数创建了一个EventHub
/dev/input/下面有所改变,就会有个触发
getEvents->
//*epoll_wait 在这里挂起,文件没有改变时挂起,一旦变化就往下走了
2、对于所有设备的相关管理,全部封装到InputManager的管理对象,在上层的表现就是IMS

SystemServer 启动IMS,构造函数调用nativeInit
nativeInit->所有具体管理操作都依赖于INotify+epoll来完成,必须用c完成

3、系统进程启动时,构建了一个IMS服务,在native构建了一个IM对象,创建两个对象
inputReader->负责读取文件变化
inputDispatcher->负责将数据分发给app,同时开启两个native线程

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
	//*创建对象
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerCapture = false;
    }
    mInteractive = true;
	//*创建EventHub
    sp<EventHub> eventHub = new EventHub();
    //*通过EventHub,创建了InputManager
    mInputManager = new InputManager(eventHub, this, this);
}
InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
   ......
   t.traceBegin("StartInputManagerService");
   inputManager = new InputManagerService(context);
   t.traceEnd();

   t.traceBegin("StartWindowManagerService");
   // WMS needs sensor service ready
   ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
   mSensorServiceStart = null;
   //*WMS持有IMS
   wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
           new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
   ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
           DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
   ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
           /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
   t.traceEnd();
......
   t.traceBegin("StartInputManager");
        inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
        //*start
        inputManager.start();
        t.traceEnd();
......

InputManagerService.java

    public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);

    private static native void nativeStart(long ptr);

com_android_server_input_InputManagerService.cpp

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

InputManager.cpp,让两个native线程跑起来

status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }

    return OK;
}

1、InputReaderThread如何读取到相关数据?
2、InputDispatcherThread如何将数据推送app?

  1. 选择窗体
  2. 分发到窗体上

这个窗体是什么?
mChannel是啥?

要分发,但是window是谁?-> app
dispatcher是谁? -> system_server

这两怎么通信?->socketpair

3、systemserver与app进程如何通信?

InputReader.cpp

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock

	//*内部有一个epoll_wait()  挂起
	//*唤醒由linux驱动去更改dev/input下的文件造成  inotify+epoll
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
			//*处理事件信息
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    //* flush 就是InputListener的flush
    mQueuedListener->flush();
}
//* flush 就是InputListener的flush
mQueuedListener->flush();
    
void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        NotifyArgs* args = mArgsQueue[i];
        //*直接调用notify
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
//*文件内容变更
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            int32_t deviceId = rawEvent->deviceId;
            while (batchSize < count) {
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                        || rawEvent[batchSize].deviceId != deviceId) {
                    break;
                }
                batchSize += 1;
            }
#if DEBUG_RAW_EVENTS
            ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
        //*文件状态变更
            switch (rawEvent->type) {
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    if (deviceIndex < 0) {
        ALOGW("Discarding event for unknown deviceId %d.", deviceId);
        return;
    }

    InputDevice* device = mDevices.valueAt(deviceIndex);
    if (device->isIgnored()) {
        //ALOGD("Discarding event for ignored deviceId %d.", deviceId);
        return;
    }

    device->process(rawEvents, count);
}

InputListener.cpp

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
	//实际上就是在调用InputDispatcher.notifyMotion
    listener->notifyMotion(this);
}

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
    mArgsQueue.push(new NotifyMotionArgs(*args));
}

InputDispatcher.cpp

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
    ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
            "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
            args->eventTime, args->deviceId, args->source, args->policyFlags,
            args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
            args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
    for (uint32_t i = 0; i < args->pointerCount; i++) {
        ALOGD("  Pointer %d: id=%d, toolType=%d, "
                "x=%f, y=%f, pressure=%f, size=%f, "
                "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
                "orientation=%f",
                i, args->pointerProperties[i].id,
                args->pointerProperties[i].toolType,
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
                args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
    }
#endif
    if (!validateMotionEvent(args->action, args->actionButton,
                args->pointerCount, args->pointerProperties)) {
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;

    android::base::Timer t;
    mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
        ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms",
                std::to_string(t.duration().count()).c_str());
    }

    bool needWake;
    { // acquire lock
        mLock.lock();

        if (shouldSendMotionToInputFilterLocked(args)) {
            mLock.unlock();

            MotionEvent event;
            event.initialize(args->deviceId, args->source, args->action, args->actionButton,
                    args->flags, args->edgeFlags, args->metaState, args->buttonState,
                    0, 0, args->xPrecision, args->yPrecision,
                    args->downTime, args->eventTime,
                    args->pointerCount, args->pointerProperties, args->pointerCoords);

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }
        //*組裝成一個事件對象
        // Just enqueue a new motion event.
        MotionEntry* newEntry = new MotionEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, args->actionButton, args->flags,
                args->metaState, args->buttonState,
                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                args->displayId,
                args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);

        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock

    if (needWake) {
        mLooper->wake();
    }
}

InputDispatcher分发过程:
安卓预面试总结_第31张图片
InputDispatcher.cpp

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}
void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    } // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();

    // Reset the key repeat timer whenever normal dispatch is suspended while the
    // device is in a non-interactive state.  This is to ensure that we abort a key
    // repeat if the device is just coming out of sleep.
    if (!mDispatchEnabled) {
        resetKeyRepeatLocked();
    }

    // If dispatching is frozen, do not process timeouts or try to deliver any new events.
    if (mDispatchFrozen) {
#if DEBUG_FOCUS
        ALOGD("Dispatch frozen.  Waiting some more.");
#endif
        return;
    }

    // Optimize latency of app switches.
    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    // Ready to start a new event.
    // If we don't already have a pending event, go grab one.
    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            if (isAppSwitchDue) {
                // The inbound queue is empty so the app switch key we were waiting
                // for will never arrive.  Stop waiting for it.
                resetPendingAppSwitchLocked(false);
                isAppSwitchDue = false;
            }

            // Synthesize a key repeat if appropriate.
            if (mKeyRepeatState.lastKeyEntry) {
                if (currentTime >= mKeyRepeatState.nextRepeatTime) {
                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
                } else {
                    if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
                        *nextWakeupTime = mKeyRepeatState.nextRepeatTime;
                    }
                }
            }

            // Nothing to do if there is no pending event.
            if (!mPendingEvent) {
                return;
            }
        } else {
            // Inbound queue has at least one entry.
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }

        // Poke user activity for this event.
        if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            pokeUserActivityLocked(mPendingEvent);
        }

        // Get ready to dispatch the event.
        resetANRTimeoutsLocked();
    }

    // Now we have an event to dispatch.
    // All events are eventually dequeued and processed this way, even if we intend to drop them.
    ALOG_ASSERT(mPendingEvent != NULL);
    bool done = false;
    DropReason dropReason = DROP_REASON_NOT_DROPPED;
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
        dropReason = DROP_REASON_POLICY;
    } else if (!mDispatchEnabled) {
        dropReason = DROP_REASON_DISABLED;
    }

    if (mNextUnblockedEvent == mPendingEvent) {
        mNextUnblockedEvent = NULL;
    }

    switch (mPendingEvent->type) {
    case EventEntry::TYPE_CONFIGURATION_CHANGED: {
        ConfigurationChangedEntry* typedEntry =
                static_cast<ConfigurationChangedEntry*>(mPendingEvent);
        done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
        dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
        break;
    }

    case EventEntry::TYPE_DEVICE_RESET: {
        DeviceResetEntry* typedEntry =
                static_cast<DeviceResetEntry*>(mPendingEvent);
        done = dispatchDeviceResetLocked(currentTime, typedEntry);
        dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
        break;
    }

    case EventEntry::TYPE_KEY: {
        KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
        if (isAppSwitchDue) {
            if (isAppSwitchKeyEventLocked(typedEntry)) {
                resetPendingAppSwitchLocked(true);
                isAppSwitchDue = false;
            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
                dropReason = DROP_REASON_APP_SWITCH;
            }
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }
        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
        break;
    }

    case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            dropReason = DROP_REASON_APP_SWITCH;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }
        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }
        //*
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
    }

    default:
        ALOG_ASSERT(false);
        break;
    }

    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;

        releasePendingEventLocked();
        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
    }
}
bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // Preprocessing.
    if (! entry->dispatchInProgress) {
        entry->dispatchInProgress = true;

        logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
    }

    // Clean up if dropping the event.
    if (*dropReason != DROP_REASON_NOT_DROPPED) {
        setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
        return true;
    }

    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    // Identify targets.
    Vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    int32_t injectionResult;
    if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
        // Non touch event.  (eg. trackball)
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
    }
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }

    setInjectionResultLocked(entry, injectionResult);
    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
        if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
            CancelationOptions::Mode mode(isPointerEvent ?
                    CancelationOptions::CANCEL_POINTER_EVENTS :
                    CancelationOptions::CANCEL_NON_POINTER_EVENTS);
            CancelationOptions options(mode, "input event injection failed");
            synthesizeCancelationEventsForMonitorsLocked(options);
        }
        return true;
    }

    addMonitoringTargetsLocked(inputTargets);

    // Dispatch the motion.
    if (conflictingPointerActions) {
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                "conflicting pointer actions");
        synthesizeCancelationEventsForAllConnectionsLocked(options);
    }
    //分发事件
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("dispatchEventToCurrentInputTargets");
#endif

    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true

    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);

        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            //*prepareDispatchCycleLocked
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
#if DEBUG_FOCUS
            ALOGD("Dropping event delivery to target with channel '%s' because it "
                    "is no longer registered with the input dispatcher.",
                    inputTarget.inputChannel->getName().c_str());
#endif
        }
    }
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
            "xOffset=%f, yOffset=%f, scaleFactor=%f, "
            "pointerIds=0x%x",
            connection->getInputChannelName().c_str(), inputTarget->flags,
            inputTarget->xOffset, inputTarget->yOffset,
            inputTarget->scaleFactor, inputTarget->pointerIds.value);
#endif

    // Skip this event if the connection status is not normal.
    // We don't want to enqueue additional outbound events if the connection is broken.
    if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
        ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
                connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
        return;
    }

    // Split a motion event if needed.
    if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
        ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);

        MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
        if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
            MotionEntry* splitMotionEntry = splitMotionEvent(
                    originalMotionEntry, inputTarget->pointerIds);
            if (!splitMotionEntry) {
                return; // split event was dropped
            }
#if DEBUG_FOCUS
            ALOGD("channel '%s' ~ Split motion event.",
                    connection->getInputChannelName().c_str());
            logOutboundMotionDetailsLocked("  ", splitMotionEntry);
#endif
            enqueueDispatchEntriesLocked(currentTime, connection,
                    splitMotionEntry, inputTarget);
            splitMotionEntry->release();
            return;
        }
    }
	//*
    // Not splitting.  Enqueue dispatch entries for the event as is.
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
    bool wasEmpty = connection->outboundQueue.isEmpty();

    // Enqueue dispatch entries for the requested modes.
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_IS);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

    // If the outbound queue was previously empty, start the dispatch cycle going.
    if (wasEmpty && !connection->outboundQueue.isEmpty()) {
    	//*startDispatchCycleLocked
        startDispatchCycleLocked(currentTime, connection);
    }
}
void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) {
    int32_t inputTargetFlags = inputTarget->flags;
    if (!(inputTargetFlags & dispatchMode)) {
        return;
    }
    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;

    // This is a new event.
    // Enqueue a new dispatch entry onto the outbound queue for this connection.
    DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
            inputTarget->scaleFactor);

    // Apply target flags and update the connection's input state.
    switch (eventEntry->type) {
    case EventEntry::TYPE_KEY: {
        KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
        dispatchEntry->resolvedAction = keyEntry->action;
        dispatchEntry->resolvedFlags = keyEntry->flags;

        if (!connection->inputState.trackKey(keyEntry,
                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
                    connection->getInputChannelName().c_str());
#endif
            delete dispatchEntry;
            return; // skip the inconsistent event
        }
        break;
    }

    case EventEntry::TYPE_MOTION: {
        MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
        if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
        } else {
            dispatchEntry->resolvedAction = motionEntry->action;
        }
        if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
                && !connection->inputState.isHovering(
                        motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
#if DEBUG_DISPATCH_CYCLE
        ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
                connection->getInputChannelName().c_str());
#endif
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
        }

        dispatchEntry->resolvedFlags = motionEntry->flags;
        if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
            dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
        }
        if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
            dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
        }

        if (!connection->inputState.trackMotion(motionEntry,
                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
                    connection->getInputChannelName().c_str());
#endif
            delete dispatchEntry;
            return; // skip the inconsistent event
        }
        break;
    }
    }

    // Remember that we are waiting for this dispatch to complete.
    if (dispatchEntry->hasForegroundTarget()) {
        incrementPendingForegroundDispatchesLocked(eventEntry);
    }

    // Enqueue the dispatch entry.
    connection->outboundQueue.enqueueAtTail(dispatchEntry);
    traceOutboundQueueLengthLocked(connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ startDispatchCycle",
            connection->getInputChannelName().c_str());
#endif

    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime;

        // Publish the event.
        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

            // Publish the key event.
            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                    keyEntry->deviceId, keyEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);
            break;
        }

        case EventEntry::TYPE_MOTION: {
            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);

            PointerCoords scaledCoords[MAX_POINTERS];
            const PointerCoords* usingCoords = motionEntry->pointerCoords;

            // Set the X and Y offset depending on the input source.
            float xOffset, yOffset;
            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                float scaleFactor = dispatchEntry->scaleFactor;
                xOffset = dispatchEntry->xOffset * scaleFactor;
                yOffset = dispatchEntry->yOffset * scaleFactor;
                if (scaleFactor != 1.0f) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i] = motionEntry->pointerCoords[i];
                        scaledCoords[i].scale(scaleFactor);
                    }
                    usingCoords = scaledCoords;
                }
            } else {
                xOffset = 0.0f;
                yOffset = 0.0f;

                // We don't want the dispatch target to know.
                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i].clear();
                    }
                    usingCoords = scaledCoords;
                }
            }
			//*inputPublisher.publishMotionEvent
            // Publish the motion event.
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
                    dispatchEntry->resolvedAction, motionEntry->actionButton,
                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                    motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords);
            break;
        }

        default:
            ALOG_ASSERT(false);
            return;
        }

        // Check the result.
        if (status) {
            if (status == WOULD_BLOCK) {
                if (connection->waitQueue.isEmpty()) {
                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
                            "This is unexpected because the wait queue is empty, so the pipe "
                            "should be empty and we shouldn't have any problems writing an "
                            "event to it, status=%d", connection->getInputChannelName().c_str(),
                            status);
                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
                } else {
                    // Pipe is full and we are waiting for the app to finish process some events
                    // before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
                    ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
                            "waiting for the application to catch up",
                            connection->getInputChannelName().c_str());
#endif
                    connection->inputPublisherBlocked = true;
                }
            } else {
                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
                        "status=%d", connection->getInputChannelName().c_str(), status);
                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
            }
            return;
        }

        // Re-enqueue the event on the wait queue.
        connection->outboundQueue.dequeue(dispatchEntry);
        traceOutboundQueueLengthLocked(connection);
        connection->waitQueue.enqueueAtTail(dispatchEntry);
        traceWaitQueueLengthLocked(connection);
    }
}

InputTransport.cpp

status_t InputPublisher::publishMotionEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t displayId,
        int32_t action,
        int32_t actionButton,
        int32_t flags,
        int32_t edgeFlags,
        int32_t metaState,
        int32_t buttonState,
        float xOffset,
        float yOffset,
        float xPrecision,
        float yPrecision,
        nsecs_t downTime,
        nsecs_t eventTime,
        uint32_t pointerCount,
        const PointerProperties* pointerProperties,
        const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
    ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
            "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
            "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
            "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
            "pointerCount=%" PRIu32,
            mChannel->getName().c_str(), seq,
            deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif

    if (!seq) {
        ALOGE("Attempted to publish a motion event with sequence number 0.");
        return BAD_VALUE;
    }

    if (pointerCount > MAX_POINTERS || pointerCount < 1) {
        ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",
                mChannel->getName().c_str(), pointerCount);
        return BAD_VALUE;
    }

    InputMessage msg;
    msg.header.type = InputMessage::TYPE_MOTION;
    msg.body.motion.seq = seq;
    msg.body.motion.deviceId = deviceId;
    msg.body.motion.source = source;
    msg.body.motion.displayId = displayId;
    msg.body.motion.action = action;
    msg.body.motion.actionButton = actionButton;
    msg.body.motion.flags = flags;
    msg.body.motion.edgeFlags = edgeFlags;
    msg.body.motion.metaState = metaState;
    msg.body.motion.buttonState = buttonState;
    msg.body.motion.xOffset = xOffset;
    msg.body.motion.yOffset = yOffset;
    msg.body.motion.xPrecision = xPrecision;
    msg.body.motion.yPrecision = yPrecision;
    msg.body.motion.downTime = downTime;
    msg.body.motion.eventTime = eventTime;
    msg.body.motion.pointerCount = pointerCount;
    for (uint32_t i = 0; i < pointerCount; i++) {
        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
    }
    return mChannel->sendMessage(&msg);
}

在ViewRootImpl建立了一个java层的InputChannel对象,将这个位置的具体数据推给WMS,WMS通过native层面构建socketpair

ViewRootImpl.java setView->new InputChannel

   requestLayout();
   InputChannel inputChannel = null;
   if ((mWindowAttributes.inputFeatures
           & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
       inputChannel = new InputChannel();
   }

WindowManagerService.java,addWindow->openInputChannel 打开通道

   if  (openInputChannels) {
       win.openInputChannel(outInputChannel);
   }

WindowState.java

    void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        //*WMS通过native层面构建socketpair
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);

InputChannel.java

public static InputChannel[] openInputChannelPair(String name) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        if (DEBUG) {
            Slog.d(TAG, "Opening input channel pair '" + name + "'");
        }
        return nativeOpenInputChannelPair(name);
    }

private static native InputChannel[] nativeOpenInputChannelPair(String name);

android_view_InputChannel.cpp

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    std::string name = nameChars;
    env->ReleaseStringUTFChars(nameObj, nameChars);

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    if (result) {
        String8 message;
        message.appendFormat("Could not open input channel pair.  status=%d", result);
        jniThrowRuntimeException(env, message.string());
        return NULL;
    }

    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

InputTrasport.cpp

status_t InputChannel::openInputChannelPair(const std::string& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                name.c_str(), errno);
        outServerChannel.clear();
        outClientChannel.clear();
        return result;
    }

    int bufferSize = SOCKET_BUFFER_SIZE;
    //构建2组socket
    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

    std::string serverChannelName = name;
    serverChannelName += " (server)";
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    std::string clientChannelName = name;
    clientChannelName += " (client)";
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

WindowState.java

void openInputChannel(InputChannel outInputChannel) {
        if (mInputChannel != null) {
            throw new IllegalStateException("Window already has an input channel.");
        }
        String name = getName();
        InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
        //*创建了两个inputChannels后
        mInputChannel = inputChannels[0];
        mClientChannel = inputChannels[1];
        //*相当于之前的regist channel
        mWmService.mInputManager.registerInputChannel(mInputChannel);
        mInputWindowHandle.token = mInputChannel.getToken();
        if (outInputChannel != null) {
        	将客户端的socket放入outInputChannel,最终返回给客户端进程
            mClientChannel.transferTo(outInputChannel);
            mClientChannel.dispose();
            mClientChannel = null;
        } else {
            // If the window died visible, we setup a dummy input channel, so that taps
            // can still detected by input monitor channel, and we can relaunch the app.
            // Create dummy event receiver that simply reports all events as handled.
            mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
        }
        mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
    }

InputManagerService.java

public void registerInputChannel(InputChannel inputChannel) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null.");
        }

        nativeRegisterInputChannel(mPtr, inputChannel);
    }

    private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel);

com_android_server_input_InputManagerService.cpp

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }

    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
    if (status) {
        std::string message;
        message += StringPrintf("Failed to register input channel.  status=%d", status);
        jniThrowRuntimeException(env, message.c_str());
        return;
    }

    if (! monitor) {
        android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                handleInputChannelDisposed, im);
    }
}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}

你可能感兴趣的:(面试,面试,1024程序员节)