Android Surface 是如何跨进程传递的?

news2024/11/25 19:32:09

Android Surface 跨进程传递原理?

  • Surface
  • Activity 的 Surface 是怎么跨进程传递的
  • 问题

Surface

public class Surface implements Parcelable {
	// ....
 	long mNativeObject;
    private final Canvas mCanvas = new CompatibleCanvas();
    // ....
}
	首先,Surface 实现了 Parcelable,所以它是可以跨进程传递的。
	Parcelable 关键的函数就是 readFromParcel(Parcel source) 和 writeToParcel(Parcel dest, int flags) 
  • writeToParcel()
    @Override
    public void writeToParcel(Parcel dest, int flags) {
		// ...
        synchronized (mLock) {
        	// 写了个 mName
            dest.writeString(mName);
            dest.writeInt(mIsSingleBuffered ? 1 : 0);
            // 调用了 native 方法 nativeWriteToParcel 写入了一个 mNativeObject 对象
            nativeWriteToParcel(mNativeObject, dest);
        }
    }

writeToParcel 方法写入了一个 mName 变量,然后调用 nativeWriteToParcel 函数写入了 mNativeObject 对象。long mNativeObject; 是一个 native对象的指针。

	private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
  • readFromParcel 函数
    public void readFromParcel(Parcel source) {
        synchronized (mLock) {
            mName = source.readString();
            mIsSingleBuffered = source.readInt() != 0;
            setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
        }
    }
	private static native long nativeReadFromParcel(long nativeObject, Parcel source);

readFromParcel 和 writeToParcel 相比,他是反过来读取一个 mName 值,然后通过 mNativeObject 传入nativeReadFromParcel 中,在调用 setNativeObjectLocked() 函数。设置了一些属性。

  • setNativeObjectLocked()
    private void setNativeObjectLocked(long ptr) {
        if (mNativeObject != ptr) {
            // 。。。
            mNativeObject = ptr;
        }
    }

setNativeObjectLocked 函数把传入的 long 类型的地址赋值给了 mNativeObject 。

  • 目前java层来看的话就是操作了一个 long 类型的mNativeObject 变量和一个 mName 属性。接下来看一下 native 层的实现

      frameworks/base/core/jni/android_view_Surface.cpp
    
  • 先看一下 nativeWriteToParcel() 函数

static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject parcelObj) {
        // 通过 parcelForJavaObject 函数获得了一个 native 层的 Parcel 对象
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    // nativeObject 就是 surface 在 native 层的指针
    // 所以通过该指针获得 surface 的对象
    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
    android::view::Surface surfaceShim;
    if (self != nullptr) {
    	// 获取一个 GraphicBuffer
        surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
    }
    // 将 GraphicBuffer 对象写到 parcel
    surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
}
  • parcelForJavaObject()
Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj) {
    // 通过 jni ,从Java层的 Parcel 对象获得了一个 native 层的 Parcel 对象。
        Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr);
        if (p != NULL) {
            return p;
        }
    }
    return NULL;
}

上面方法通过 jni ,从Java层的 Parcel 对象获得了一个 native 层的 Parcel 对象。因为Java层对象中保存了一个 native 层对象的指针。

  • nativeReadFromParcel
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject parcelObj) {
        // 先 parcel 对象拿到 native 的 Parcel 对象
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    // 定义 surfaceShim 指定是 android view surface
    android::view::Surface surfaceShim;
    surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);

    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));

	// 只有当底层的IGraphicBufferProducer发生变化时才更新Surface。
    if (self != nullptr
            && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
                    IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
        // same IGraphicBufferProducer, return ourselves
        return jlong(self.get());
    }

    sp<Surface> sur;
    if (surfaceShim.graphicBufferProducer != nullptr) {
        // 创建一个 surface 对象,传入 IGraphicBufferProducer
        sur = new Surface(surfaceShim.graphicBufferProducer, true);
        // and keep a reference before passing to java
        sur->incStrong(&sRefBaseOwner);
    }

    if (self != NULL) {
        // and loose the java reference to ourselves
        self->decStrong(&sRefBaseOwner);
    }
	// 返回新创建的 surface 对象给 Java 层
    return jlong(sur.get());
}
  • Java层的surface 在于 native 层的 surface,而 native 层的 surface 在于 graphicBufferProducer 对象,它是可以申请 buffer 的存在。

Activity 的 Surface 是怎么跨进程传递的

performTraversals() 是准备绘制的时候,当第一次绘制的时候代码如下

private void performTraversals() {
	if(mFirst){
    	int relayoutResult = 0;
		relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
	}
}
  • relayoutWindow()
    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
        int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
                mPendingMergedConfiguration, mSurface);
        return relayoutResult;
    }

mWindowSession binder 对象会给 wms 申请 relayout 调用,这里面会申请surface。传入的 mSurface 只是一个空壳。
relayout() 是一个 aidl 接口源码中是这样描述它的,总之就是调用这个方法,可以返回一个 surface 对象,你可以用它展示内容。mWindowSession 实际上就是 Java 层和 wms 交流的桥梁

     * Change the parameters of a window.  You supply the
     * new parameters, it returns the new frame of the window on screen (the
     * position should be ignored) and surface of the window.  The surface
     * will be invalid if the window is currently hidden, else you can use it
     * to draw the window's contents.

调用该这个 aidl 方法执行 framework 中 Session.java
在这里插入图片描述

    @Override
    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
            Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
            Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
            Surface outSurface) {
        int res = mService.relayoutWindow(this, window, seq, attrs,
                requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                outStableInsets, outsets, outBackdropFrame, cutout,
                mergedConfiguration, outSurface);
        return res;
    }
  • mService.relayoutWindow()

public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attr...{
	// 调用了 createSurfaceControl() 方法中有下面代码
	WindowSurfaceController surfaceController;
	surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
	// getSurface 里面调用了 outSurface.copyFrom(mSurfaceControl);
	surfaceController.getSurface(outSurface);
}

  • surface 从 surfaceController 中 copy 了一些东西
    public void copyFrom(SurfaceControl other) {
		// SurfaceControl 也保存了 native 层的对象
        long surfaceControlPtr = other.mNativeObject;
        // 根据 native 层的SurfaceControl对象创建一个native层的 surface 对象
        long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
        synchronized (mLock) {
            if (mNativeObject != 0) {
                nativeRelease(mNativeObject);
            }
            // 然后将 native层的 surface 对象 和 java层的 surface 对象绑定到一起
            setNativeObjectLocked(newNativeObject);
        }
    }

上面方法创建了 native 层的 surface 对象 并且和Java层的surface 层对象绑定一起,在创建对象的时候,
long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr); 创建了一个 Surface对象,并且传入了 mGraphicBufferProducer 。也就是 SurfaceControl 中有一个 mGraphicBufferProducer 然后根据 mGraphicBufferProducer 创建了一个native 层 Surface 对象,然后将 native 层的 Surface 对象的指针,保存到 Java 层 Surface 对象中。

问题

  1. 怎么理解 surface 它是一块 buffer 么?

     	所以 surface 实际上有作用的是 GraphicBufferProducer 对象,它可以生成 buffer 。
    
  2. 如果是 buffer ,surface 如何跨进程携带它的?

     所以它不是 buffer 它携带的是 GraphicBufferProducer ,GraphicBufferProducer 是一个 binder 对象。
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/13750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

思科模拟器的远程连接交换机的实现

这里写目录标题思科模拟器的远程连接交换机的实现方式一 :反转线1.使用蓝色的线2.在pc0 上面找到超级终端 这时候就可以看到一些终端数 就说明连接进去了方式二:交换机配置终端 进行终端tennet连接1.设置命令终端的进入密码2.配置终端的连接密码3.给交换机添加ip3.方式3: web连…

Spring Boot

Spring Boot (https://baike.baidu.com/item/Spring%20Boot?fromModulelemma_search-box) 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。 人们把 Spring Boot 称为搭建程序的脚手架。其最主要作用就是帮我们快速的…

IPWorks Delphi版自定义服务器解决方案

IPWorks Delphi版自定义服务器解决方案 IPWorks是一个用于Internet开发的综合框架&#xff0c;它消除了Internet开发的复杂性&#xff0c;提供了可编程的、支持SSL的组件&#xff0c;以便于执行诸如确保安全、发送电子邮件、传输文件、管理网络、浏览Web、使用Web服务等任务。 …

pybind11使用总结(依赖python3.7版本)

先安装python3.7的源码&#xff1b;test_py.py调用test_cpp中导出函数add()及python三方库&#xff1a; import os import pandas as pd import numpy as np import libtest as coredef test(a):print(pd.__version__)print(np.__version__)print(core.add(1,2))test_cpp.cpp导…

Study Git - Data Model

前言 本文章主要记录学习git底层原理时的一些知识点 文章参考 MIT missing classHow to explain git in simple words?The anatomy of a Git commitPro Git Git的数据模型 blob: 压缩并保存所有文件内容的数据结构 blob array<byte>tree: 存储目录的结构&#xff0c…

Cholesterol艾美捷胆固醇基参方案

艾美捷Cholesterol胆固醇以固体形式提供。可以通过将胆固醇溶解在所选择的溶剂中来制备储备溶液&#xff0c;该溶剂应使用惰性气体吹扫。胆固醇以约30mg/ml的浓度溶于有机溶剂氯-仿中。 艾美捷Cholesterol胆固醇基本参数&#xff1a; Formal Name (3β)-cholest-5-en-3-ol C…

Element Tiptap Editor - 免费开源的 Vue 富文本编辑器,专门为搭配 Element UI 使用优化,使用很简单

一款很容易上手配置的富文本编辑器&#xff0c;和 Element plus 一起使用效果非常好&#xff0c;还能自定义功能。 关于 Element Tiptap Editor Element Tiptap Editor 是一个在 web 开发领域“所见即所得”的富文本编辑器&#xff0c;基于 tiptap 编辑器和 element-ui 开发&…

Android程序设计之音乐播放器实现

Android毕设音乐播放器实现 基于MediaPlayer技术实现在线音乐播放器&#xff0c;播放在线音乐&#xff0c;后端使用SpringBoot将音乐存放在Tomcat服务器。app通过网络请求获取音乐&#xff0c;从而实现在线音乐播放。该项目分为用户端和管理员端 一、核心技术Service组件介绍 …

远程教育:低代码重塑教育技术

新冠肺炎大流行对世界各地的行业产生了影响&#xff0c;其中一些行业的影响远远超过其他行业。食品、零售、供应链、娱乐和航空业是受影响最大的行业&#xff0c;为确保不间断运营&#xff0c;这引发了一场数字革命。相信&#xff0c;这种数字化的采用将长期保持下去&#xff0…

​电脑上的回收站怎么隐藏 ,怎么隐藏桌面回收站图标

回收站是电脑上不可分割的一部分&#xff0c;往往被放在电脑的桌面上&#xff0c;我们是不能够删除桌面上的回收站的&#xff0c;但是如果想要一个很干净的桌面&#xff0c;不想让回收站出现在电脑桌面上&#xff0c;​电脑上的回收站怎么隐藏&#xff1f; 通过本文&#xff0c…

List接口

集合框架图 list接口的常用实现类 list接口的常用方法 ■void add(int index, E element);向指定位置上添加元素&#xff0c;原始数据后移■E remove(int index);删除指定位置上的元素&#xff0c;并返回被删除的元素&#xff0c;原始位置上的元素前移■E get(int index);按照索…

Maven 【ERROR】 不再支持源选项 5。请使用 7或更高版本解决方案:修改Maven默认JDK(含完整代码及详细教程)

文章目录一、前言二、项目场景三、问题描述四、原因分析五、解决方案1. 查看本机安装的jdk版本2. 找到settings.xml文件3. 编辑settings.xml文件4.找到pom.xml文件5.修改pom.xml文件六、验证七、结语一、前言 博主在遇到这个问题时&#xff0c;找遍了百度的方法也没办法解决&a…

[附源码]Python计算机毕业设计java视频点播系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

AI+教育的结合

1、AI 目前有哪些应用方向 我们所说的 AI 到底是什么&#xff1f;先定义清楚&#xff0c;我们先不要被这个被过度包装的概念迷惑说 AI 能代替人类&#xff0c;无所不能。 实际上&#xff0c;人工智能&#xff0c;是属于计算机科学的一个分支&#xff0c;我们常听到的 机器学习…

java读取局域网共享文件夹中文件并保存到本地文件夹

在磁盘新建一个文件夹&#xff0c;右击文件夹属性&#xff0c;点击共享 点击网络和共享中心 设置文件夹可访问权限 到此就可以用本地ip加文件夹名称访问了&#xff0c;同局域网也可以通过改地址访问 文件夹的名称来自这张图的 网络路径 如果需要通过java的jcifs包访问请继…

负载均衡-动静分离

文章目录一.Nginx负载均衡实现原理1、反向代理原理2、反向代理的概念3、反向代理的优势4、Nginx四层反向代理和七层反向代理二、Nginx动静分离实现原理1、动静分离的概念2、动静分离的原理3、Nginx 静态处理优势三、Nginx负载均衡调度算法&#xff08;6种&#xff09;1、轮询&a…

Sentinel源码剖析之执行流程

1、说明 Sentinel主要用来流控&#xff0c;熔断降级保护目标资源用的&#xff0c;常用集成SCG&#xff0c;SpringBoot&#xff0c;SprinMVC这些&#xff0c;但底层本质没变&#xff0c;但是体现形式上会有差别。例如SCG底层是Netty 和 SpringWebFlux 采用Reactor Stream处理&a…

策略验证_买入口诀_三杆通底反弹在即

写在前面&#xff1a; 1. 本文中提到的“股票策略校验工具”的具体使用操作请查看该博文&#xff1b; 2. 文中知识内容来自书籍《同花顺炒股软件从入门到精通》 3. 本系列文章是用来学习技法&#xff0c;文中所得内容都仅仅只是作为演示功能使用 目录 解说 策略代码 结果 解…

【POJ No. 1988】 方块栈 Cube Stacking

【POJ No. 1988】 方块栈 Cube Stacking POJ 题目地址 【题意】 贝西正在玩方块游戏&#xff0c;方块编号为1&#xff5e;N&#xff08;1≤N ≤30,000&#xff09;&#xff0c;开始时每个方块都相当于一个栈。 贝西执行P 个&#xff08;1≤P ≤100,000&#xff09;操作&…

深圳市数字经济指数发布:数字经济蓬勃发展,数字用户深度渗透

2022年1月&#xff0c;国务院印发了《“十四五”数字经济发展规划》。规划提出&#xff0c;到2025年&#xff0c;数字经济核心产业增加值占国内生产总值比重达到10%&#xff0c;数据要素市场体系初步建立&#xff0c;产业数字化转型迈上新台阶&#xff0c;数字产业化水平显著提…