Android Application与SurfaceFlinger连接过程分析

2023-12-19 20:48

本文主要是介绍Android Application与SurfaceFlinger连接过程分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

     看了罗老师的的博客很久了,特别羡慕,写的非常认真而且详细,所以呢,也经常向大家推荐,各位卓友如果有时间,请多看一下,对自己从整体上掌握Android Framework架构非常有益。自己的学习在同时,也跟着源码分析,得出自己的结论,只是单纯的看罗老师的博客,看完还是一头雾水,只有自己完整完整走一遍,才会有一定的掌握。

     Android当中的GUI绘图应该算是最重要的一块了,因为所有的应用都最直接和用户接触,当然这块也是特别复杂的。自己看了好久,才有一点脉络,记下来,怕以后忘掉了。

     从罗老师的博客当中,可以了解到,Application都会与SurfaceFlinger连接,并得到一个匿名的binder对象,以便能够绘制自己的UI,并在绘制完成后,请求SurfaceFlinger对自己的UI数据进行渲染。一个Application在SurfaceFlinger端对应有一个Client的对象,对应的代码如下:

spSurfaceFlinger::createConnection()
{
spbclient;
spclient(new Client(this));
status_t err = client->initCheck();
if (err == NO_ERROR) {
bclient = client;
}
return bclient;
}

     到这里,Application就取得与SurfaceFlinger的正常连接了,好了,那我们的目标现在就非常清晰了,Application是怎么执行到这里的呢?我们还是从ViewRootImpl类来看起,Application中的每个界面对应一个Activity,而每个Activity都对应一个Window、一个ViewRootImpl、一个WindowState、一个Surface,这些如果有疑问的,可以去看罗老师的博客。ViewRootImpl的创建是在WindowManagerGlobal当中的,代码如下:

public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
// Start watching for system property changes.
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();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
// Don't wait for MSG_DIE to make it's way through root's queue.
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
// The previous removeView() had not completed executing. Now it has.
}
// If this is a panel window, then find the window it is being
// attached to for future reference.
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);
}
}
}
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
synchronized (mLock) {
final int index = findViewLocked(view, false);
if (index >= 0) {
removeViewLocked(index, true);
}
}
throw e;
}
}
     这里创建了ViewRootImpl对象,在ViewRootImpl的构造方法当中,对类成员变量进行初始化,代码如下:

public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mDisplayAdjustments = display.getDisplayAdjustments();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
// [+LEUI-9331]
mPreBlurParams = new BlurParams();
// [-LEUI-9331]
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityInteractionConnectionManager =
new AccessibilityInteractionConnectionManager();
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
/**
* M: increase instance count and check log property to determine
* whether to enable/disable log system. @{
*/
mIdent = sIdent++;
checkViewRootImplLogProperty();
if (LOCAL_LOGV) {
enableLog(true, "a");
}
if (DEBUG_LIFECYCLE) {
Log.v(TAG, "ViewRootImpl construct: context = " + context + ", mThread = " + mThread
+ ", mChoreographer = " + mChoreographer + ", mTraversalRunnable = "
+ mTraversalRunnable + ", this = " + this);
}
}
     其中的第二行mWindowSession非常重要,它是通过WindowManagerGlobal.getWindowSession()赋值的,这里是一个binder调用,最终的实现是在WindowManagerService中的openSession()方法当中,这里新创建了一个Session对象,并通过binder进程间调用返回给了Application。
    public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
}
return sWindowSession;
}
}
     继续往下看,当ViewRootImpl对象创建完成,Activity需要绘制自己的UI数据时,通过各种调用,最终都会调用到ViewRootImpl类的performTraversals()方法当中,这个也就是我们通常说的View绘制的标准流程(Measure、Layout、Draw)三步,这个方法代码特别长,这里就不贴出来了,我们主要看一下if (mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params != null) 这个分支,就是在绘制时,如果是第一次、窗口大小发生变化、状态栏变化、可见性变化、绘图参数不为空这几种情况时,会调用relayoutWindow(params, viewVisibility, insetsPending)方法,在relayoutWindow方法中,会调用最开始创建好的mWindowSession.relayout()方法,mWindowSession我们在前面已经说过了,是在WindowManagerService的openSession()方法当中创建的对象,它对应的类是Session,它的relayoutWindow就是转调到mService.relayoutWindow()方法当中了,而mService当然就是WindowManagerService了。
    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
float appScale = mAttachInfo.mApplicationScale;
boolean restore = false;
if (params != null && mTranslator != null) {
restore = true;
params.backup();
mTranslator.translateWindowLayout(params);
}
if (params != null) {
if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
}
mPendingConfiguration.seq = 0;
if (DEBUG_LAYOUT) {
Log.d(TAG, ">>>>>> CALLING relayoutW+ " + mWindow + ", params = " + params
+ ",viewVisibility = " + viewVisibility + ", insetsPending = " + insetsPending
+ ", appScale = " + appScale + ", mWinFrame = " + mWinFrame + ", mSeq = "
+ mSeq + ", mPendingOverscanInsets = " + mPendingOverscanInsets
+ ", mPendingContentInsets = " + mPendingContentInsets
+ ", mPendingVisibleInsets = " + mPendingVisibleInsets
+ ", mPendingStableInsets = " + mPendingStableInsets
+ ", mPendingOutsets = " + mPendingOutsets
+ ", mPendingConfiguration = " + mPendingConfiguration + ", mSurface = "
+ mSurface + ",valid = " + mSurface.isValid() + ", mOrigWindowType = "
+ mOrigWindowType + ",this = " + this);
}
if (params != null && mOrigWindowType != params.type) {
// For compatibility with old apps, don't crash here.
if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
Slog.w(TAG, "Window type can not be changed after "
+ "the window is added; ignoring change of " + mView);
params.type = mOrigWindowType;
}
}
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,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
if (DEBUG_LAYOUT) {
Log.d(TAG, "<<<<<< BACK FROM relayoutW- : res = " + relayoutResult + ", mWinFrame = "
+ mWinFrame + ", mPendingOverscanInsets = " + mPendingOverscanInsets
+ ", mPendingContentInsets = " + mPendingContentInsets
+ ", mPendingVisibleInsets = " + mPendingVisibleInsets
+ ", mPendingStableInsets = " + mPendingStableInsets
+ ", mPendingOutsets = " + mPendingOutsets
+ ", mPendingConfiguration = " + mPendingConfiguration + ", mSurface = "
+ mSurface + ",valid = " + mSurface.isValid() + ",params = " + params
+ ", this = " + this);
}
if (restore) {
params.restore();
}
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
}
return relayoutResult;
}
     好,我们进入WindowManagerService.relayoutWindow()方法当中,这里请一定注意,relayoutWindow方法没有带重写的标志,说明不是从其他类继续的,而是直接调用的。因代码较长,这里也就不贴出来了,其中最关键的一句就是SurfaceControl surfaceControl = winAnimator.createSurfaceLocked(),这里创建好一个SurfaceControl对象,然后就将其拷贝到outSurface当中了。这里就有点疑问了,如果执行到这步,那Surface对象就已经生成好了,那么与SurfaceFlinger的连接到底是什么建立的呢?不对了,肯定是中间露掉什么了,回头看一下。
     从添加窗口重新来,ViewRootImpl调用setView方法,间接调用了mWindowSession.addToDisplay()方法,转而调用WindowManagerService.addWindow()方法,每个Activity对应的WindowState对象也是在这里构建的,创建完成后,调用win.attach(),代码如下:
    void attach() {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
}
其中的mSession对象就是WindowManagerService为每个ViewRootImpl构建的Session,在Session类的windowAddedLocked方法当中又构建了一个SurfaceSession,好像模糊的看到目标了,跟Surface有关系了,我们继续往下看,SurfaceSession的构造方法直接调用jni的nativeCreate,实现在android_view_SurfaceSession.cpp类中:
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
return reinterpret_cast(client);
}
看到这里就很明显了,直接在native层创建了一个SurfaceComposerClient指针,而SurfaceComposerClient创建后,在首次调用时,会执行onFirstRef的方法,就会与SurfaceFlinger取得连接,然后调用到最开始我们看的new Client当中,这样Application就与SurfaceFlinger取得连接了。
中间写的思路开始不清晰,走错了,后面回头再看一次,更加深了印象,写的不好的地方,请大家见谅,谢谢!



这篇关于Android Application与SurfaceFlinger连接过程分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/513653

相关文章

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

【Altium】查找PCB上未连接的网络

【更多软件使用问题请点击亿道电子官方网站】 1、文档目标: PCB设计后期检查中找出没有连接的网络 应用场景:PCB设计后期,需要检查是否所有网络都已连接布线。虽然未连接的网络会有飞线显示,但是由于布线后期整板布线密度较高,虚连,断连的网络用肉眼难以轻易发现。用DRC检查也可以找出未连接的网络,如果PCB中DRC问题较多,查找起来就不是很方便。使用PCB Filter面板来达成目的相比DRC

Java面试题:通过实例说明内连接、左外连接和右外连接的区别

在 SQL 中,连接(JOIN)用于在多个表之间组合行。最常用的连接类型是内连接(INNER JOIN)、左外连接(LEFT OUTER JOIN)和右外连接(RIGHT OUTER JOIN)。它们的主要区别在于它们如何处理表之间的匹配和不匹配行。下面是每种连接的详细说明和示例。 表示例 假设有两个表:Customers 和 Orders。 Customers CustomerIDCus

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st

Android多线程下载见解

通过for循环开启N个线程,这是多线程,但每次循环都new一个线程肯定很耗内存的。那可以改用线程池来。 就以我个人对多线程下载的理解是开启一个线程后: 1.通过HttpUrlConnection对象获取要下载文件的总长度 2.通过RandomAccessFile流对象在本地创建一个跟远程文件长度一样大小的空文件。 3.通过文件总长度/线程个数=得到每个线程大概要下载的量(线程块大小)。