WindowManagerService (WMS )和 AMS 一样,都是 Android 应用开发需要掌握的知 识点。 WMS 也很复杂并且功能繁多,需要花很多篇幅来进行讲解。如果直接讲解 WMS 很难理解,为了更好地理解 WMS ,需要先了解 WindowManager 的相关知识,这是因为从 应用开发角度来看, WindowManager 是与 WMS 关联最紧密的类。
一.Window、WindowManager、WMS
1.简介 Window:在Android视图体系中Window就是一个窗口的概念。Android中所有的视图都是依赖于Window显示的(在activity中他的实现类是PhoneWindow),可以这样理解Window是View的一个容器,而View是Window的具体表现。 WindowManager:WindowManager 个接口类,继承自接口 ViewManager ,从名称就知道它是 用来管理 Window 的,它的实现类为 WindowManager Imp对Window的管理,包括新增、更新和删除等。 WMS:窗口的最终管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进行管理。 2.常见的Window 3.窗口的次序 当一个进程向 WMS 申请一个窗口时, WMS 会为窗口确定显示次序。为了方便窗口显示次序的管理,手机屏幕可以虚拟地用 轴来表示,其中 轴垂直于屏幕,从屏幕内指向屏幕外,这样确定窗口显示次序也就是确定窗口在 轴上的次序,这个次序称为Z -Oder。Type 值是 -Oder 排序的依据,我们知道应用程序窗口的 Type 值范围为0- 99,子窗口 1000-1999 ,系统窗口 2000-2999 ,在 般情况下, Type 值越大则 Z-Oder 排序越靠前,就越靠近用户。当然窗口显示次序的逻辑不会这么简单,情况会 较多,举个常见 的情况 当多个窗口的 Type 值都是 TYPE_APPLICATION ,这时 WMS 会结合各种情况给出最终的 Z-Oder。Z-Oder大的窗口会覆盖在Z-Oder比较小的窗口之上。
如下图所示,第一个图片是一个选择注册的界面,第二张图片是一个注册界面,第三张图片是一个注册成功的界面,加入我通过点击同选择注册界面,到注册界面,再到注册成功的界面(假设跳转的时候没有finish),那么在注册成功的界面的窗口排列次序如最右边的图所示。
4.Window分类 Application Window:Activity就是一个典型的应用程序窗口。 Sub Window:子窗口,顾名思义,它不能独立存在,需要附着在其他窗口才可以,PopupWindow就属于子窗口。 System Window:输入法窗口、系统音量条窗口、系统错误窗口都属于系统窗口。 type = ApplicationWindow时的 Z-Oder
public static final int FIRST_APPLICATION_WINDOW = 1; // 这种类型 Z-Oder的下界
public static final int TYPE_BASE_APPLICATION = 1;
public static final int TYPE_APPLICATION = 2;
public static final int TYPE_APPLICATION_STARTING = 3; // 临时窗口(比如启动app时的过渡白屏)
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99; // 这种类型 Z-Oder的上界
type = Sub Window时的 Z-Oder
public static final int FIRST_SUB_WINDOW = 1000; // 这种类型 Z-Oder的下界 public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW; public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1; public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2; public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3; public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4; public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5; public static final int LAST_SUB_WINDOW = 1999; // 这种类型 Z-Oder的上界
type =System Window时的 Z-Oder
public static final int FIRST_SYSTEM_WINDOW = 2000; // 这种类型 Z-Oder的下界
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
..
public static final int LAST_SYSTEM_WINDOW = 2999; // 这种类型 Z-Oder的上界
5.窗口的次序 系统窗口位于最上面,子窗口次之,应用程序窗口位于最下面, 7.WindowManager WindowManager是一个接口,在Android中他的实现类是WindowManagerImpl。我们新增窗口,更新窗口。删除窗口的能力来自于WindowManager,最终这些操作都会交给WindowManagerGloble进行处理。 8.添加Window Activity#attach()方法之内PhoneWindow被创建,并同时创建一WindowManagerImpl负责维护PhoneWindow内的内容。 在Activity#onCreate()中调用setContentView()方法,这个方法内部创建一个DecorView实例作为PhoneWindow的内容。 WindowManagerImpl决定管理DecorView,并创建一个ViewRootImpl实例,将ViewRootImpl与View树进行关联,这样ViewRootImpl就可以指挥View树的具体工作。
如下代码所示,在ActivityThread的performLaunchActivity通过反射的方式创建出activity,然后在后面调用了该activity的attach方法。
ActivityThread.java '
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),
appContext.getAttributionSource());
if (r.state != null) {
r.state.setClassLoader(cl);
}
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken, r.shareableActivityToken);
如下代码,在activity的attach函数中,创建出了PhoneWindow的一个对象,然后在之后创建出了一个WindowManager对象,然后使得WindowManager和我们创建出的PhoneWindow产生关联。
Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
IBinder shareableActivityToken) {
attachBaseContext(context);
mFragments.attachHost(null );
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
之后在activity的onCreate中的setContentView方法中创建了DecorView, Window,PhoneWindow,WindowManager,WindowManagerImpl在这里运用了桥接的设计模式。
activity与 PhoneWindow与DecorView关系
DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图
如下代码: activity与 PhoneWindow与DecorView与WindowMnager建立了关系
ActivityThread.java
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
...
if (!performResumeActivity(r, finalStateRequest, reason)) {
return;
}
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
上面的代码可以看得出,最后把调用了WindowManager的addView,WindowManager是一个接口,他的实现类是WindowManagerImpl,如下代码:
WindowManagerImpl.java
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
如上的代码,可以看出最后调用了WindowManagerGlobal的addView。WindowManagerGlobal可以认为是一个全局的Window管理者。作为管理者WindowManagerGlobal会管理View(DecorView),布局参数和ViewRootImpl,说道ViewRootImpl,先来简单了解一下ViewRootImpl。
ViewRootImpl
-
View树的树根并管理View树 -
触发View的测量、布局和绘制 -
输入响应的中转站 -
负责与WMS进行进程间通信
ViewRootImpl的类注释是这样描述的: 视图层次结构的顶部,在视图之间实现所需的协议还有WindowManager。这在很大程度上是一个内部实现细节。 ViewRootImpl非常重要,WindowManager通过ViewRootImpl与DecorView起联系。并且,View的绘制流程都是由ViewRootImpl发起的。
ViewRootImpl是View中的最高层级,属于所有View的根(但ViewRootImpl不是View,只是实现了ViewParent接口),实现了View和WindowManager之间的通信协议,实现的具体细节在WindowManagerGlobal这个类当中。 回到代码:如下,通过 mViews.add(view);mRoots.add(root);mParams.add(wparams);添加一个Window的流程算是走完了。
WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
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 {
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) {
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)) {
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
}
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);
try {
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
9.绘制流程 绘制流程我之前分析过,这里简单提一下,具体见View的绘制流程
当收到了一个同步信号,就开始进行测量布局和绘制。
10.更新Window
当窗口发生变化的时候(比如横竖屏切换,弹出一个Dialog…),这些变化会让WindowManagerImpl调用updateViewLayout。
WindowManagerImpl.java
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.updateViewLayout(view, params);
}
如上的代码,WindowManagerImpl中调用了WindowManagerGloble的updateViewLayout
WindowManagerGloble.java
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (mLock) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
mParams.remove(index);
mParams.add(index, wparams);
root.setLayoutParams(wparams, false);
}
}
如上代码,接下来会调用该Window对应的ViewRootImpl 的setLayoutParams方法。
ViewRootImpl.java
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
scheduleTraversals();
如上代码,最终会产生一个重绘,这个重绘会调用到WindowManagerImpl的performTraversales。窗口更新的时候会引起一个重绘。
9.刷新流程 *UI刷新:*以电影为例,动画至少要达到24FPS,才能保证画面的流畅性,低于这个值,肉眼会感觉到卡顿。在手机上,这个值被调整到60FPS,增加丝滑度,这也是为什么有个(1000/60)16ms的指标,一般而言目前的Android系统FPS也就是60,它是通过了一个VSYNC来保证每16ms最多绘制一帧。简而言之:UI必须至少等待16ms的间隔才会绘制下一帧,所以连续两次setTextView只会触发一次重绘。
接下来,将以TextView.setText()为例来说明Window刷新的流程:
等到VSYNC到来后,会移除同步栅栏,并率先开始执行当前帧的处理,调用逻辑如下
代码分析:
TextView.java
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
....
checkForRelayout();
....
}
在TextView的setText方法中会调用 checkForRelayout方法,这个方法的作用是检查全新文本是需要新的视图布局还是仅需要新的文本布局。
private void checkForRelayout() {
if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT
|| (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))
&& (mHint == null || mHintLayout != null)
&& (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {
int oldht = mLayout.getHeight();
int want = mLayout.getWidth();
int hintWant = mHintLayout == null ? 0 : mHintLayout.getWidth();
makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,
mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),
false);
if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {
if (mLayoutParams.height != LayoutParams.WRAP_CONTENT
&& mLayoutParams.height != LayoutParams.MATCH_PARENT) {
autoSizeText();
invalidate();
return;
}
if (mLayout.getHeight() == oldht
&& (mHintLayout == null || mHintLayout.getHeight() == oldht)) {
autoSizeText();
invalidate();
return;
}
}
requestLayout();
invalidate();
} else {
nullLayouts();
requestLayout();
invalidate();
}
}
在requestLayout方法中,首先先判断当前View树是否正在布局流程,接着为当前子View设置标记位,该标记位的作用就是标记了当前的View是需要进行重新布局的,接着调用mParent.requestLayout方法,这个十分重要,因为这里是向父容器请求布局,即调用父容器的requestLayout方法,为父容器添加PFLAG_FORCE_LAYOUT标记位,而父容器又会调用它的父容器的requestLayout方法,即requestLayout事件层层向上传递,直到DecorView,即根View,而根View又会传递给ViewRootImpl,也即是说子View的requestLayout事件,最终会被ViewRootImpl接收并得到处理。纵观这个向上传递的流程,其实是采用了责任链模式,即不断向上传递该事件,直到找到能处理该事件的上级,在这里,只有ViewRootImpl能够处理requestLayout事件。关于requestLayout和invalidate详细的分析见Android View 深度分析requestLayout、invalidate与postInvalidate
invalidate一路向上 标志脏区,然后会执行到ViewRootImpl的scheduleTraversals方法。如下
ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
可以看到,上面的代码中,调用mChoreographer.postCallback()函数时候,post的是一个mTraversalRunnable,我们来看下这个mTraversalRunnable是什么。
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
TraversalRunnable类定义在ViewRootImpl中,如下:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
该类实现了Runnable接口,在run()方法中,执行了doTraversal()函数,我们接着看下doTraversal()函数。
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
综上分析,我们可以得出结论,在我们调用ViewRootImpl的scheduleTraversals()方法后,并不是立即就开始执行performTraversals()的,而是需要等到使用Choreographer类的postCallback()方法post出去的Runnable回调执行run()方法的时候,才开始真正的绘制流程,即调用performTraversals()方法。
再看看上面的代码:
ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
Choreographer的postCallback()分析:(这里的分析借鉴了Android中老生常谈的ViewRootImpl的scheduleTraversals…)
Choreographer.java
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
通过源码可以发现,第一个参数在Choreographer类中有五个不同的值
Choreographer.java
public static final int CALLBACK_INPUT = 0;
@TestApi
public static final int CALLBACK_ANIMATION = 1;
public static final int CALLBACK_INSETS_ANIMATION = 2;
public static final int CALLBACK_TRAVERSAL = 3;
public static final int CALLBACK_COMMIT = 4;
事件值 解释说明 CALLBACK_INPUT: 输入事件,第一个执行 CALLBACK_ANIMATION: 动画,在CALLBACK_INSETS_ANIMATION前执行 CALLBACK_INSETS_ANIMATION: 输入和动画之后,TRAVERSAL之前 CALLBACK_TRAVERSAL: 处理布局和绘制,运行在其他异步消息之后 CALLBACK_COMMIT 提交,最后执行
第二个参数需要的是一个Runnable
第三个参数为Object token
我们在ViewRootImpl中调用scheduleTraversals()方法中
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
第一个参数传入的是CALLBACK_TRAVERSAL(布局和绘制)。 第二个参数传入的是mTraversalRunnable,上面已经说过,就是一个实现了Runnable接口的TraversalRunnable类。 第三个参数传入的是null。
如下代码,在mChoreographer.postCallback中有调用了 postCallbackDelayed
Choreographer.java
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
如下代码,在经过一些检查后又调用了postCallbackDelayedInternal
Choreographer.java
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
如下代码中,mCallbackQueues是Choreographer类中的一个数组,初始化是在Choreographer类的构造方法中
Choreographer.java
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
如上的代码中的 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);就是根据Callback的类型,把Callback添加到对应的CallbackQueue 得链表当中。 mCallbackQueues 的初始化,可以见得,mCallbackQueues 的长度为5(这里的5就对应前面的物种类型),mCallbackQueues 数组里面填充的是CallbackQueue。
Choreographer.java
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
CallbackQueue是一个内部类
Choreographer.java
private final class CallbackQueue {
private CallbackRecord mHead;
public boolean hasDueCallbacksLocked(long now) {
return mHead != null && mHead.dueTime <= now;
}
public CallbackRecord extractDueCallbacksLocked(long now) {
......
}
@UnsupportedAppUsage
public void addCallbackLocked(long dueTime, Object action, Object token) {
......
}
public void removeCallbacksLocked(Object action, Object token) {
......
}
}
可以看到,在CallbackQueue中存储的是CallbackRecord,看下CallbackRecord类: CallbackRecord类中有一个成员变量是next,指向的是下一个CallbackRecord,因此在CallbackQueue中存储的是一个链式结构的CallbackRecord。注意这里的run()方法,下面会用到。
Choreographer.java
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action;
public Object token;
@UnsupportedAppUsage
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
接着上文的postCallbackDelayedInternal继续分析:
Choreographer.java
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
if (isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
如上代码 在检查了是否在Looper thread之后调用了scheduleVsyncLocked。
Choreographer.java
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
如上,在scheduleVsyncLocked中调用了mDisplayEventReceiver.scheduleVsync();,mDisplayEventReceiver类型是FrameDisplayEventReceiver。FrameDisplayEventReceiver继承自DisplayEventReceiver,并实现了Runnable接口。实现了两个方法,onVsync()和run(),其中onVsync方法来自DisplayEventReceiver,run()方法来自Runnable接口。
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
}
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
如上:mDisplayEventReceiver中没有scheduleVsync(),这是因为scheduleVsync是DisplayEventReceiver父类DisplayEventReceiver的方法。如下
DisplayEventReceiver.java
public void scheduleVsync() {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
+ "receiver has already been disposed.");
} else {
nativeScheduleVsync(mReceiverPtr);
}
}
因此如果mReceiverPtr不是0,会调用nativeScheduleVsync(mReceiverPtr)。该方法也是一个native方法,这里这个类指的是底层NativeDisplayEventReceiver这个类nativeScheduleVsync底层会调用到requestNextVsync()去请求下一个Vsync,具体不跟踪了,native层代码更长,还涉及到各种描述符监听以及跨进程数据传输,当我们请求后的Vsync收到后,我们只需要知道VSYNC信号的接收回调是onVsync()方法,所以下一步的分析是回到上文中FrameDisplayEventReceiver 的onVsync()
class FrameDisplayEventReceiver extends DisplayEventReceiver
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
long now = System.nanoTime();
if (timestampNanos > now) {
Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)
+ " ms in the future! Check that graphics HAL is generating vsync "
+ "timestamps using the correct timebase.");
timestampNanos = now;
}
if (mHavePendingVsync) {
Log.w(TAG, "Already have a pending vsync event. There should only be "
+ "one at a time.");
} else {
mHavePendingVsync = true;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
上面的直接省略,我们看下通过mHandler发送消息,可以看到,这里创建Message消息的时候,传入的是this,因为FrameDisplayEventReceiver实现了Runnable接口,因此在handler处理消息的时候回调run方法,在run方法中,调用了doFramen方法。另外,这里调用了msg.setAsynchronous(true),通过handler发送到MessageQueue中的是一个异步消息,我们前面已经post了一个同步屏障,因此该异步消息会被调用。因为FrameDisplayEventReceiver实现了Runnable接口,同时把自己作为参数交给了handler去处理,所以回到用到这里的 run()方法,可以看到,在 run()中调用了doFrame方法。
Choreographer.java
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
......
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
......
}
可以看出,在doFrame中依次执行了doCallbacks方法,传入的类型是我们上面提到的Choreographer类中定义好的五种类型。看下doCallbacks方法:
Choreographer.java
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
if (callbacks == null) {
return;
}
......
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
可以看到,首先根据指定的任务类型,从mCallbackQueues中查找需要执行的CallbackRecord,如果是null,直接return了。紧接着,遍历执行CallbackRecord中的所有任务(链表结构),回调CallbackRecord的run 方法。
CallbackRecord.java
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
因为我们在上面往CallbackRecord中add任务的时候,传入的token是null,所以这里直接走到了action.run()方法,而action是前面提到的TraversalRunnable,所以直接调用了TraversalRunnable类的run方法,然后调用了doTraversal(),在doTraversal()方法中,开始真正的绘制流程。看下doTraversal方法:
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
在调用performTraversals之前,调用了mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier),在这里就把之前我们添加的同步屏障从MessageQueue中移除,从而使MesssageQueue中next()方法可以正常取到同步消息。
使用一张图来梳理一下在整个Choreographer中的流程: 总结一下: android一般60FPS,是VSYNC及决定的,每16ms最多一帧
VSYNC要客户端主动申请,才会有有VSYNC到来才会刷新
UI没更改,不会请求VSYNC也就不会刷新
UI局部重绘其实只会去重绘带刷新的View
11.SurfaceFlinger
SF是整个Android系统渲染的核心进程。所有应用的渲染逻辑最终都会来到SF中进行处理,最终会把处理后的图像数据交给CPU或者GPU进行绘制。 SurfaceFlinger服务是在System进程中启动的,并且负责统一管理设备的帧缓冲区。SurfaceFlinger服务在启动的过程中,会创建两个线程,其中一个线程用来监控控制台事件,而另外一个线程用来渲染系统的UI。在本文中,我们就将详细分析SurfaceFlinger服务的启动过程。
如上图所描述的DecorView surface layer 图层 图像数据 之间的关系:一个DecorVeiw对应一个surface,一个surface 又对应一个layer图层,在SurfaceFlinger会将这些图层合成成一层 然后交给CPU/GPU进行处理
在每一个应用中都以Surface作为一个图元传递单元,向SF这个服务端传递图元数据
SF是以生产者以及消费者为核心设计思想,把每一个应用进程作为生产者生产图元保存到SF的图元队列中,SF则作为消费者依照一定的规则把生产者存放到SF中的队列一一处理。
|