Activity-Window加載顯示流程概述: Android系統中圖形系統是至關複雜的,包括WindowManager,SurfaceFlinger,Open GL,GPU等模塊。 其中SurfaceFlinger做爲負責繪製應用UI的核心,從名字能夠看出其功能是將全部Surface合成工做。 不論使用什麼渲染API, 全部的東西最終都是渲染到」surface」. surface表明BufferQueue的生產者端, 而且 由SurfaceFlinger所消費, 這即是基本的生產者-消費者模式. Android平臺所建立的Window都由surface所支持, 全部可見的surface渲染到顯示設備都是經過SurfaceFlinger來完成的. 本文詳細分析Android Window加載顯示流程,並經過SurfaceFlinger渲染合成輸出到屏幕的過程。java
啓動流程:android
點擊桌面App圖標,Launcher進程採用Binder IPC向system_server進程發起startActivity請求;算法
system_server進程接收到請求後,向zygote進程發送建立進程的請求;canvas
Zygote進程fork出新的子進程,即App進程;windows
App進程,經過Binder IPC向sytem_server進程發起attachApplication請求;數組
system_server進程在收到請求後,進行一系列準備工做後,再經過binder IPC向App進程發送scheduleLaunchActivity請求;bash
App進程的binder線程(ApplicationThread)在收到請求後,經過handler向主線程發送LAUNCH_ACTIVITY消息;session
主線程在收到Message後,經過發射機制建立目標Activity,並回調Activity.onCreate()等方法。app
App正式啓動後,開始進入Activity生命週期,執行完onCreate/onStart/onResume方法,UI渲染結束後即可以看到App的主界面, 接下來分析UI渲染流程。composer
2.一、ActivityThread.handleLaunchActivity()
接着從ActivityThread的handleLaunchActivity方法:[->ActivityThread.java]
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason){
......
// Initialize before creating the activity
WindowManagerGlobal.initialize();
//建立Activity
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
......
//啓動Activity
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
......
}
}
複製代碼
應用程序進程經過performLaunchActivity函數將即將要啓動的Activity加載到當前進程空間來,同時爲啓動Activity作準備。 [ActivityThread.java #performLaunchActivity()]
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//經過Activity所在的應用程序信息及該Activity對應的CompatibilityInfo信息從PMS服務中查詢當前Activity的包信息
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
//獲取當前Activity的組件信息
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
//packageName爲啓動Activity的包名,targetActivity爲Activity的類名
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
//經過類反射方式加載即將啓動的Activity
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} ......
try {
//經過單例模式爲應用程序進程建立Application對象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
......
if (activity != null) {
//爲當前Activity建立上下文對象ContextImpl
Context appContext = createBaseContextForActivity(r, activity);
......
//將當前啓動的Activity和上下文ContextImpl、Application綁定
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);
......
//將Activity保存到ActivityClientRecord中,ActivityClientRecord爲Activity在應用程序進程中的描述符
r.activity = activity;
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
......
//生命週期onStart、onresume
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
//ActivityThread的成員變量mActivities保存了當前應用程序進程中的全部Activity的描述符
mActivities.put(r.token, r);
......
return activity;
}
複製代碼
在該函數中,首先經過PMS服務查找到即將啓動的Activity的包名信息,而後經過類反射方式建立一個該Activity實例,同時爲應用程序啓動的每個Activity建立一個LoadedApk實例對象(ActivityInfo.packageInfo),應用程序進程中建立的全部LoadedApk對象保存在ActivityThread的成員變量mPackages中。接着經過LoadedApk對象的makeApplication函數,使用單例模式建立Application對象,所以在android應用程序進程中有且只有一個Application實例。而後爲當前啓動的Activity建立一個ContextImpl上下文對象,並初始化該上下文,到此咱們能夠知道,啓動一個Activity須要如下對象:
Activity對象,須要啓動的Activity;
LoadedApk對象,每一個啓動的Activity都擁有屬於自身的LoadedApk對象;
ContextImpl對象,每一個啓動的Activity都擁有屬於自身的ContextImpl對象;
Application對象,應用程序進程中有且只有一個實例,和Activity是一對多的關係;
2.二、Activity對象Attach過程
Activity所須要的對象都建立好了,就須要將Activity和Application對象、ContextImpl對象綁定在一塊兒。
參數: context:Activity的上下文對象,就是前面建立的ContextImpl對象;
aThread:Activity運行所在的主線程描述符ActivityThread;
instr:用於監控Activity運行狀態的Instrumentation對象;
token:用於和AMS服務通訊的IApplicationToken.Proxy代理對象;
application:Activity運行所在進程的Application對象;
parent:啓動當前Activity的Activity;
[->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) {
//將上下文對象ContextImpl保存到Activity的成員變量中
attachBaseContext(context);
......
mWindow = new PhoneWindow(this, window);
......
//記錄應用程序的UI線程
mUiThread = Thread.currentThread();
//記錄應用程序的ActivityThread對象
mMainThread = aThread;
......
//爲Activity所在的窗口建立窗口管理器
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
複製代碼
在該attach函數中主要作了如下幾件事:
根據參數初始化Activity的成員變量;
爲Activity建立窗口Window對象;
爲Window建立窗口管理器;
2.三、Activity視圖對象的建立過程-Activity.setContentView()
ActivityThread.performLaunchActivity()
–> Instrumentation.callActivityOnCreate()
——>Activity.performCreate()
——>Activity.onCreate()
–>Activity.performStart()
——>Instrumentation.callActivityOnStart()
——>Activity.onStart()
複製代碼
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
複製代碼
getWindow()函數獲得前面建立的窗口對象PhoneWindow,經過PhoneWindow來設置Activity的視圖。 [->PhoneWindow.java]
public void setContentView(View view, ViewGroup.LayoutParams params) {
......
//若是窗口頂級視圖對象爲空,則建立窗口視圖對象
if (mContentParent == null) {
installDecor();
}
......
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
......
} else {//加載佈局文件,並將佈局文件中的全部視圖對象添加到mContentParent容器中,PhoneWindow的成員變量mContentParent的類型爲ViewGroup,是窗口內容存放的地方
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
複製代碼
Activity.onCreate()會調用setContentView(),整個過程主要是Activity的佈局文件或View添加至窗口裏。
建立一個DecorView的對象mDecor,該mDecor對象將做爲整個應用窗口的根視圖。
依據Feature等style theme建立不一樣的窗口修飾佈局文件,而且經過findViewById獲取Activity佈局文件該存放的地方(窗口修飾佈局文件中id爲content的FrameLayout)。
將Activity的佈局文件添加至id爲content的FrameLayout內。
當setContentView設置顯示OK之後會回調Activity的onContentChanged方法。Activity的各類View的findViewById()方法等均可以放到該方法中,系統會幫忙回調。
複製代碼
2.四、ActivityThread.handleResumeActivity() 回到咱們剛剛的handleLaunchActivity()方法,在調用完performLaunchActivity()方法以後,其有掉用了handleResumeActivity()法。
performLaunchActivity()方法完成了兩件事:
Activity窗口對象的建立,經過attach函數來完成;
Activity視圖對象的建立,經過setContentView函數來完成;
這些準備工做完成後,就能夠顯示該Activity了,應用程序進程經過調用handleResumeActivity函數來啓動Activity的顯示過程。
[->ActivityThread.java]
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
......
//
r = performResumeActivity(token, clearHide, reason);
......
if (r.window == null && !a.mFinished && willBeVisible) {
//得到爲當前Activity建立的窗口PhoneWindow對象
r.window = r.activity.getWindow();
//獲取爲窗口建立的視圖DecorView對象
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//在attach函數中就爲當前Activity建立了WindowManager對象
ViewManager wm = a.getWindowManager();
//獲得該視圖對象的佈局參數
WindowManager.LayoutParams l = r.window.getAttributes();
//將視圖對象保存到Activity的成員變量mDecor中
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
......
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
//將建立的視圖對象DecorView添加到Activity的窗口管理器中
wm.addView(decor, l);
}
......
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
if (!r.onlyLocalRequest) {
//onStop()......
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);
}
}
......
}
}
複製代碼
咱們知道,在前面的performLaunchActivity函數中完成Activity的建立後,會將當前當前建立的Activity在應用程序進程端的描述符ActivityClientRecord以鍵值對的形式保存到ActivityThread的成員變量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份證,便是IApplicationToken.Proxy代理對象,也用於與AMS通訊。上面的函數首先經過performResumeActivity從mActivities變量中取出Activity的應用程序端描述符ActivityClientRecord,而後取出前面爲Activity建立的視圖對象DecorView和窗口管理器WindowManager,最後將視圖對象添加到窗口管理器中。
ViewManager.addView()真正實現的的地方在WindowManagerImpl.java中。
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
複製代碼
[->WindowManagerImpl.java]
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
......
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
複製代碼
[->WindowManagerGlobal.java]
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
......
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
try {
root.setView(view, wparams, panelParentView);
}
......
}
複製代碼
2.五、ViewRootImpl()構造過程:
[ViewRootImpl.java # ViewRootImpl()]
final W mWindow;
final Surface mSurface = new Surface();
final ViewRootHandler mHandler = new ViewRootHandler();
......
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();//IWindowSession的代理對象,該對象用於和WMS通訊。
mDisplay = display;
......
mWindow = new W(this);//建立了一個W本地Binder對象,用於WMS通知應用程序進程
......
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
......
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();//Choreographer對象
......
}
複製代碼
在ViewRootImpl的構造函數中初始化了一些成員變量,ViewRootImpl建立了如下幾個主要對象:
(1) 經過WindowManagerGlobal.getWindowSession()獲得IWindowSession的代理對象,該對象用於和WMS通訊。
(2) 建立了一個W本地Binder對象,用於WMS通知應用程序進程。
(3) 採用單例模式建立了一個Choreographer對象,用於統一調度窗口繪圖。
(4) 建立ViewRootHandler對象,用於處理當前視圖消息。
(5) 構造一個AttachInfo對象;
(6) 建立Surface對象,用於繪製當前視圖,固然該Surface對象的真正建立是由WMS來完成的,只不過是WMS傳遞給應用程序進程的。
2.六、IWindowSession代理獲取過程
[->WindowManagerGlobal.java]
private static IWindowSession sWindowSession;
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
//獲取輸入法管理器
InputMethodManager imm = InputMethodManager.getInstance();
//獲取窗口管理器
IWindowManager windowManager = getWindowManagerService();
//獲得IWindowSession代理對象
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
複製代碼
以上函數經過WMS的openSession函數建立應用程序與WMS之間的鏈接通道,即獲取IWindowSession代理對象,並將該代理對象保存到ViewRootImpl的靜態成員變量sWindowSession中,所以在應用程序進程中有且只有一個IWindowSession代理對象。 [->WindowManagerService.java]
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
}
複製代碼
在WMS服務端構造了一個Session實例對象。ViewRootImpl 是一很重要的類,相似 ActivityThread 負責跟AmS通訊同樣,ViewRootImpl 的一個重要職責就是跟 WmS 通訊,它通靜態變量 sWindowSession(IWindowSession實例)與 WmS 進行通訊。每一個應用進程,僅有一個 sWindowSession 對象,它對應了 WmS 中的 Session 子類,WmS 爲每個應用進程分配一個 Session 對象。WindowState 類有一個 IWindow mClient 參數,是在構造方法中賦值的,是由 Session 調用 addWindow 傳遞過來了,對應了 ViewRootImpl 中的 W 類的實例。
2.七、AttachInfo構造過程
AttachInfo(IWindowSession session, IWindow window, Display display,
ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
mSession = session;//IWindowSession代理對象,用於與WMS通訊
mWindow = window;//W對象
mWindowToken = window.asBinder();//W本地Binder對象
mDisplay = display;
mViewRootImpl = viewRootImpl;//ViewRootImpl實例
mHandler = handler;//ViewRootHandler對象
mRootCallbacks = effectPlayer;
}
複製代碼
2.八、建立Choreographer對象
[->Choreographer.java]
// Thread local storage for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Choreographer(looper);
}
};
public static Choreographer getInstance() {
return sThreadInstance.get();
}
複製代碼
爲調用線程建立一個Choreographer實例,調用線程必須具有消息循環功能,由於ViewRootImpl對象的構造是在應用程序進程的UI主線程中執行的,所以建立的Choreographer對象將使用UI線程消息隊列。 [->Choreographer.java]
private Choreographer(Looper looper) {
mLooper = looper;
//建立消息處理Handler
mHandler = new FrameHandler(looper);
//若是系統使用了Vsync機制,則註冊一個FrameDisplayEventReceiver接收器
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
//屏幕刷新週期
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
//建立回調數組
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
//初始化數組
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
複製代碼
2.九、視圖View添加過程
窗口管理器WindowManagerImpl爲當前添加的窗口建立好各類對象後,調用ViewRootImpl的setView函數向WMS服務添加一個窗口對象。 [->ViewRootImpl.java]
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
////將DecorView保存到ViewRootImpl的成員變量mView中
mView = view;
......
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
//同時將DecorView保存到mAttachInfo中
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator != null;
mAttachInfo.mApplicationScale =
mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
mAdded = true;
int res; /* = WindowManagerImpl.ADD_OKAY; */
//1)在添加窗口前進行UI佈局
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//2)將窗口添加到WMS服務中,mWindow爲W本地Binder對象,經過Binder傳輸到WMS服務端後,變爲IWindow代理對象
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
} ......
//3)創建窗口消息通道
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
......
}
}
}
複製代碼
經過前面的分析能夠知道,用戶自定義的UI做爲一個子View被添加到DecorView中,而後將頂級視圖DecorView添加到應用程序進程的窗口管理器中,窗口管理器首先爲當前添加的View建立一個ViewRootImpl對象、一個佈局參數對象ViewGroup.LayoutParams,而後將這三個對象分別保存到當前應用程序進程的窗口管理器WindowManagerImpl中,最後經過ViewRootImpl對象將當前視圖對象註冊到WMS服務中。
ViewRootImpl的setView函數向WMS服務添加一個窗口對象過程:
(1) requestLayout()在應用程序進程中進行窗口UI佈局;
(2) WindowSession.addToDisplay()向WMS服務註冊一個窗口對象;
(3) 註冊應用程序進程端的消息接收通道;
(1)、requestLayout()在應用程序進程中進行窗口UI佈局;
2.十、窗口UI佈局過程
requestLayout函數調用裏面使用了Hanlder的一個小手段,那就是利用postSyncBarrier添加了一個Barrier(擋板),這個擋板的做用是阻塞普通的同步消息的執行,在擋板被撤銷以前,只會執行異步消息,而requestLayout先添加了一個擋板Barrier,以後本身插入了一個異步任務mTraversalRunnable,其主要做用就是保證mTraversalRunnable在全部同步Message以前被執行,保證View繪製的最高優先級。具體實現以下:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
複製代碼
2.10.一、添加回調過程
[->Choreographer.java]
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
......
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
......
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//將要執行的回調封裝成CallbackRecord對象,保存到mCallbackQueues數組中
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);
}
}
}
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_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);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
複製代碼
消息處理:
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
}
}
}
void doScheduleVsync() {
synchronized (mLock) {
if (mFrameScheduled) {
scheduleVsyncLocked();
}
}
}
private void scheduleVsyncLocked() {
//申請Vsync信號
mDisplayEventReceiver.scheduleVsync();
}
複製代碼
在該函數中考慮了兩種狀況,一種是系統沒有使用Vsync機制,在這種狀況下,首先根據屏幕刷新頻率計算下一次刷新時間,經過異步消息方式延時執行doFrame()函數實現屏幕刷新。若是系統使用了Vsync機制,而且當前線程具有消息循環,則直接請求Vsync信號,不然就經過主線程來請求Vsync信號。
2.10.二、Vsync請求過程
咱們知道在Choreographer構造函數中,構造了一個FrameDisplayEventReceiver對象,用於請求並接收Vsync信號,Vsync信號請求過程以下:
private void scheduleVsyncLocked() {
//申請Vsync信號
mDisplayEventReceiver.scheduleVsync();
}
複製代碼
[->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);
}
}
複製代碼
[->android_view_DisplayEventReceiver.cpp ]
static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
sp<NativeDisplayEventReceiver> receiver =
reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
status_t status = receiver->scheduleVsync();
if (status) {
String8 message;
message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status);
jniThrowRuntimeException(env, message.string());
}
}
複製代碼
VSync請求過程又轉交給了DisplayEventReceiver: [->DisplayEventReceiver.cpp]
status_t DisplayEventReceiver::requestNextVsync() {
if (mEventConnection != NULL) {
mEventConnection->requestNextVsync();
return NO_ERROR;
}
return NO_INIT;
}
複製代碼
這裏又經過IDisplayEventConnection接口來請求Vsync信號,IDisplayEventConnection實現了Binder通訊框架,能夠跨進程調用,由於Vsync信號請求進程和Vsync產生進程有可能不在同一個進程空間,所以這裏就藉助IDisplayEventConnection接口來實現。下面經過圖來梳理Vsync請求的調用流程:
須要說明的是/Vsync/之間的代碼此時其實還未執行,call requestNextVsync()來告訴系統我要在下一個VSYNC須要被trigger.
繼續ViewRootImpl的setView函數中的WindowSession.addToDisplay()。
(2) 、mWindowSession.addToDisplay()向WMS服務註冊一個窗口對象; [Session.java]
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}
複製代碼
[WindowManagerService.java]
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
......
boolean reportNewConfig = false;
WindowState attachedWindow = null;
long origId;
final int callingUid = Binder.getCallingUid();
final int type = attrs.type;
synchronized(mWindowMap) {
......
final DisplayContent displayContent = getDisplayContentLocked(displayId);
......
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
AppWindowToken atoken = null;
boolean addToastWindowRequiresToken = false;
......
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
return WindowManagerGlobal.ADD_APP_EXITING;
}
......
mPolicy.adjustWindowParamsLw(win.mAttrs);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
......
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
......
if (addToken) {
mTokenMap.put(attrs.token, token);
}
win.attach();
mWindowMap.put(client.asBinder(), win);
......
}
boolean imMayMove = true;
if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.add(win);
addWindowToListInOrderLocked(win, true);
moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
if (type == TYPE_WALLPAPER) {
mWallpaperControllerLocked.clearLastWallpaperTimeoutTime();
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (mWallpaperControllerLocked.isBelowWallpaperTarget(win)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
......
mInputMonitor.setUpdateInputWindowsNeededLw();
boolean focusChanged = false;
if (win.canReceiveKeys()) {
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
if (focusChanged) {
imMayMove = false;
}
}
......
mLayersController.assignLayersLocked(displayContent.getWindowList());
// Don't do layout here, the window must call // relayout to be displayed, so we'll do it there.
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
......
}
if (reportNewConfig) {
sendNewConfiguration();
}
return res;
}
複製代碼
咱們知道當應用程序進程添加一個DecorView到窗口管理器時,會爲當前添加的窗口建立ViewRootImpl對象,同時構造了一個W本地Binder對象,不管是窗口視圖對象DecorView仍是ViewRootImpl對象,都只是存在於應用程序進程中,在添加窗口過程當中僅僅將該窗口的W對象傳遞給WMS服務,通過Binder傳輸後,到達WMS服務端進程後變爲IWindow.Proxy代理對象,所以該函數的參數client的類型爲IWindow.Proxy。參數attrs的類型爲WindowManager.LayoutParams,在應用程序進程啓動Activity時,handleResumeActivity()函數經過WindowManager.LayoutParams l = r.window.getAttributes();來獲得應用程序窗口布局參數,因爲WindowManager.LayoutParams實現了Parcelable接口,所以WindowManager.LayoutParams對象能夠跨進程傳輸,WMS服務的addWindow函數中的attrs參數就是應用程序進程發送過來的窗口布局參數。在WindowManagerImpl的addView函數中爲窗口布局參數設置了相應的token,若是是應用程序窗口,則佈局參數的token設爲W本地Binder對象。若是不是應用程序窗口,同時當前窗口沒有父窗口,則設置token爲當前窗口的IApplicationToken.Proxy代理對象,不然設置爲父窗口的IApplicationToken.Proxy代理對象,因爲應用程序和WMS分屬於兩個不一樣的進程空間,所以通過Binder傳輸後,佈局參數的令牌attrs.token就轉變爲IWindow.Proxy或者Token。以上函數首先根據佈局參數的token等信息構造一個WindowToken對象,而後在構造一個WindowState對象,並將添加的窗口信息記錄到mTokenMap和mWindowMap哈希表中。
在WMS服務端建立了所需對象後,接着調用了WindowState的attach()來進一步完成窗口添加。 [WindowState.java]
void attach() {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
}
複製代碼
[Session.java]
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (WindowManagerService.localLOGV) Slog.v(
TAG_WM, "First window added to " + this + ", creating SurfaceSession");
mSurfaceSession = new SurfaceSession();
if (SHOW_TRANSACTIONS) Slog.i(
TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession);
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
複製代碼
SurfaceSession創建過程
SurfaceSession對象承擔了應用程序與SurfaceFlinger之間的通訊過程,每個須要與SurfaceFlinger進程交互的應用程序端都須要建立一個SurfaceSession對象。
客戶端請求 [SurfaceSession.java]
public SurfaceSession() {
mNativeClient = nativeCreate();
}
複製代碼
Java層的SurfaceSession對象構造過程會經過JNI在native層建立一個SurfaceComposerClient對象。
[android_view_SurfaceSession.cpp]
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(client);
}
複製代碼
Java層的SurfaceSession對象與C++層的SurfaceComposerClient對象之間是一對一關係。 [SurfaceComposerClient.cpp]
SurfaceComposerClient::SurfaceComposerClient()
: mStatus(NO_INIT), mComposer(Composer::getInstance()){}
void SurfaceComposerClient::onFirstRef() {
//獲得SurfaceFlinger的代理對象BpSurfaceComposer
sp<ISurfaceComposer> sm(ComposerService::getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}
複製代碼
SurfaceComposerClient繼承於RefBase類,當第一次被強引用時,onFirstRef函數被回調,在該函數中SurfaceComposerClient會請求SurfaceFlinger爲當前應用程序建立一個Client對象,專門接收該應用程序的請求,在SurfaceFlinger端建立好Client本地Binder對象後,將該Binder代理對象返回給應用程序端,並保存在SurfaceComposerClient的成員變量mClient中。
服務端處理 在SurfaceFlinger服務端爲應用程序建立交互的Client對象 [SurfaceFlinger.cpp]
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
sp<ISurfaceComposerClient> bclient;
sp<Client> client(new Client(this));
status_t err = client->initCheck();
if (err == NO_ERROR) {
bclient = client;
}
return bclient;
}
複製代碼
Vsync信號處理
以上是請求過程,FrameDisplayEventReceiver對象用於請求並接收Vsync信號,當Vsync信號到來時,系統會自動調用其onVsync()函數,後面會回調到FrameDisplayEventReceiver.run方法,再回調函數中執行doFrame()實現屏幕刷新。 當VSYNC信號到達時,Choreographer doFrame()函數被調用
[->Choreographer.java]
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
......
long intendedFrameTimeNanos = frameTimeNanos;
//保存起始時間
startNanos = System.nanoTime();
//因爲Vsync事件處理採用的是異步方式,所以這裏計算消息發送與函數調用開始之間所花費的時間
final long jitterNanos = startNanos - frameTimeNanos;
//計算函數調用期間所錯過的幀數
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG, "Skipped " + skippedFrames + " frames! "
+ "The application may be doing too much work on its main thread.");
}
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
frameTimeNanos = startNanos - lastFrameOffset;
}
//若是frameTimeNanos小於一個屏幕刷新週期,則從新請求VSync信號
if (frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
//分別回調CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT事件
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
}
}
複製代碼
Choreographer類中分別定義了CallbackRecord、CallbackQueue內部類,CallbackQueue是一個按時間前後順序保存CallbackRecord的單向循環鏈表。
在Choreographer中定義了三個CallbackQueue隊列,用數組mCallbackQueues表示,用於分別保存CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL這三種類型的Callback,當調用Choreographer類的postCallback()函數時,就是往指定類型的CallbackQueue隊列中經過addCallbackLocked()函數添加一個CallbackRecord項:首先構造一個CallbackRecord對象,而後按時間前後順序插入到CallbackQueue鏈表中。從代碼註釋中,咱們能夠知道CALLBACK_INPUT是指輸入回調,該回調優先級最高,首先獲得執行,而CALLBACK_TRAVERSAL是指處理佈局和繪圖的回調,只有在全部異步消息都執行完後才獲得執行,CALLBACK_ANIMATION是指動畫回調,比CALLBACK_TRAVERSAL優先執行,從doFrame()函數中的doCallbacks調用就能印證這點。 當Vsync事件到來時,順序執行CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL 和CALLBACK_COMMIT 對應CallbackQueue隊列中註冊的回調。 [->Choreographer.java]
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
//從指定類型的CallbackQueue隊列中查找執行時間到的CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
now / TimeUtils.NANOS_PER_MS);
......
if (callbackType == Choreographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
if (jitterNanos >= 2 * mFrameIntervalNanos) {
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
+ mFrameIntervalNanos;
mDebugPrintNextFrameTimeDelta = true;
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
}
}
}
try {
for (CallbackRecord c = callbacks; c != null; c = c.next) {
//因爲CallbackQueues是按時間前後順序排序的,所以遍歷執行全部時間到的CallbackRecord
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
複製代碼
咱們知道Choreographer對外提供了兩個接口函數用於註冊指定的Callback,postCallback()用於註冊Runnable對象,而postFrameCallback()函數用於註冊FrameCallback對象,不管註冊的是Runnable對象仍是FrameCallback對象,在CallbackRecord對象中統一裝箱爲Object類型。在執行其回調函數時,就須要區別這兩種對象類型,若是註冊的是Runnable對象,則調用其run()函數,若是註冊的是FrameCallback對象,則調用它的doFrame()函數。
2.十一、視圖View添加過程
關於Choreographer的postCallback()用法在前面進行了詳細的介紹,當Vsync事件到來時,mTraversalRunnable對象的run()函數將被調用。
mTraversalRunnable對象的類型爲TraversalRunnable,該類實現了Runnable接口,在其run()函數中調用了doTraversal()函數來完成窗口布局。 [->ViewRootImpl.java]
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
複製代碼
performTraversals函數至關複雜,其主要實現如下幾個重要步驟:
1.執行窗口測量;
2.執行窗口註冊;
3.執行窗口布局;
4.執行窗口繪圖;
[->ViewRootImpl.java]
private void performTraversals() {
......
final View host = mView;
mIsInTraversal = true;
mWillDrawSoon = true;
boolean windowSizeMayChange = false;
boolean newSurface = false;
boolean surfaceChanged = false;
WindowManager.LayoutParams lp = mWindowAttributes;
int desiredWindowWidth;
int desiredWindowHeight;
final int viewVisibility = getHostVisibility();
final boolean viewVisibilityChanged = !mFirst
&& (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
final boolean viewUserVisibilityChanged = !mFirst &&
((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
surfaceChanged = true;
params = lp;
}
......
/****************執行窗口測量******************/
boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
if (layoutRequested) {
windowSizeMayChange |= measureHierarchy(host, lp, res,
desiredWindowWidth, desiredWindowHeight);
}
......
/****************向WMS服務添加窗口******************/
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
......
try {
......
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
......
} catch (RemoteException e) {
}
......
if (!mStopped || mReportNextDraw) {
......
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
......
}
}
} else {
......
}
/****************執行窗口布局******************/
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
performLayout(lp, mWidth, mHeight);
......
}
/****************查找窗口焦點******************/
if (mFirst) {
......
if (mView != null) {
if (!mView.hasFocus()) {
mView.requestFocus(View.FOCUS_FORWARD);
} else {}
}
}
final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
final boolean regainedFocus = hasWindowFocus && mLostWindowFocus;
if (regainedFocus) {
mLostWindowFocus = false;
} else if (!hasWindowFocus && mHadWindowFocus) {
mLostWindowFocus = true;
}
if (changedVisibility || regainedFocus) {
// Toasts are presented as notifications - don't present them as windows as well boolean isToast = (mWindowAttributes == null) ? false : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST); if (!isToast) { host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } } mFirst = false; mWillDrawSoon = false; mNewSurfaceNeeded = false; mActivityRelaunched = false; mViewVisibility = viewVisibility; mHadWindowFocus = hasWindowFocus; if (hasWindowFocus && !isInLocalFocusMode()) { final boolean imTarget = WindowManager.LayoutParams .mayUseInputMethod(mWindowAttributes.flags); if (imTarget != mLastWasImTarget) { mLastWasImTarget = imTarget; InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null && imTarget) { imm.onPreWindowFocus(mView, hasWindowFocus); imm.onPostWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, !mHasHadWindowFocus, mWindowAttributes.flags); } } } // Remember if we must report the next draw. if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { mReportNextDraw = true; } /****************執行窗口繪製******************/ boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; if (!cancelDraw && !newSurface) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).startChangingAnimations(); } mPendingTransitions.clear(); } performDraw(); } else { if (isViewVisible) { // Try again scheduleTraversals(); } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).endChangingAnimations(); } mPendingTransitions.clear(); } } mIsInTraversal = false; } 複製代碼
一、執行窗口測量performMeasure()
[->ViewRootImpl.java]
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
複製代碼
二、執行窗口註冊relayoutWindow;
[->ViewRootImpl.java]
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,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
mSurface);
......
return relayoutResult;
}
複製代碼
這裏經過前面獲取的IWindowSession代理對象請求WMS服務執行窗口布局,mSurface是ViewRootImpl的成員變量 [->ViewRootImpl.java]
final Surface mSurface = new Surface();
複製代碼
[->Surface.java]
/**
* Create an empty surface, which will later be filled in by readFromParcel().
* @hide
*/
public Surface() {
}
複製代碼
該Surface構造函數僅僅建立了一個空Surface對象,並無對該Surface進程native層的初始化,到此咱們知道應用程序進程爲每一個窗口對象都建立了一個Surface對象。而且將該Surface經過跨進程方式傳輸給WMS服務進程,咱們知道,在Android系統中,若是一個對象須要在不一樣進程間傳輸,必須實現Parcelable接口,Surface類正好實現了Parcelable接口。ViewRootImpl經過IWindowSession接口請求WMS的完整過程以下:
[->IWindowSession.java$ Proxy]
/*
* This file is auto-generated. DO NOT MODIFY
* * Original file: frameworks/base/core/java/android/view/IWindowSession.aidl
*/
@Override
public int relayout(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, android.graphics.Rect outFrame, android.graphics.Rect outOverscanInsets, android.graphics.Rect outContentInsets, android.graphics.Rect outVisibleInsets, android.graphics.Rect outStableInsets, android.graphics.Rect outOutsets, android.graphics.Rect outBackdropFrame, android.content.res.Configuration outConfig, android.view.Surface outSurface) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
......
mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);
......
if ((0 != _reply.readInt())) {
outSurface.readFromParcel(_reply);
}
} finally {
......
}
return _result;
}
複製代碼
從該函數的實現能夠看出,應用程序進程中建立的Surface對象並無傳遞到WMS服務進程,只是讀取WMS服務進程返回來的Surface。那麼WMS服務進程是如何響應應用程序進程佈局請求的呢?
[->IWindowSession.java$ Stub]
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case TRANSACTION_relayout:
{
......
android.view.Surface _arg15;
_arg15 = new android.view.Surface();
int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14, _arg15);
reply.writeNoException();
reply.writeInt(_result);
......
if ((_arg15!=null)) {
reply.writeInt(1);
_arg15.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
return true;
}
}
複製代碼
該函數能夠看出,WMS服務在響應應用程序進程請求添加窗口時,首先在當前進程空間建立一個Surface對象,而後調用Session的relayout()函數進一步完成窗口添加過程,最後將WMS服務中建立的Surface返回給應用程序進程。
到目前爲止,在應用程序進程和WMS服務進程分別建立了一個Surface對象,可是他們調用的都是Surface的無參構造函數,在該構造函數中並未真正初始化native層的Surface,那native層的Surface是在那裏建立的呢?
[->Session.java]
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
Configuration outConfig, Surface outSurface) {
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
return res;
}
複製代碼
[->WindowManagerService.java]
ublic int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
Configuration outConfig, Surface outSurface) {
int result = 0;
......
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || !win.mAppToken.clientHidden)) {
result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges,
oldVisibility);
try {
result = createSurfaceControl(outSurface, result, win, winAnimator);
} catch (Exception e) {
......
return 0;
}
......
} else {
......
}
......
return result;
}
複製代碼
[->WindowManagerService.java]
private int createSurfaceControl(Surface outSurface, int result, WindowState win,
WindowStateAnimator winAnimator) {
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
}
WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
if (surfaceController != null) {
surfaceController.getSurface(outSurface);
} else {
outSurface.release();
}
return result;
}
複製代碼
[->WindowSurfaceController.java]
void getSurface(Surface outSurface) {
outSurface.copyFrom(mSurfaceControl);
}
複製代碼
[->WindowStateAnimator.java]
WindowSurfaceController createSurfaceLocked() {
......
try {
......
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags, this);
w.setHasSurface(true);
}
......
return mSurfaceController;
}
複製代碼
[->WindowSurfaceController.java]
public WindowSurfaceController(SurfaceSession s,
String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
mAnimator = animator;
mSurfaceW = w;
mSurfaceH = h;
......
if (animator.mWin.isChildWindow() &&
animator.mWin.mSubLayer < 0 &&
animator.mWin.mAppToken != null) {
......
} else {
mSurfaceControl = new SurfaceControl(
s, name, w, h, format, flags);
}
}
複製代碼
2.十二、Surface建立過程
[->SurfaceControl.java]
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
......
mNativeObject = nativeCreate(session, name, w, h, format, flags);
......
}
複製代碼
[->android_view_SurfaceControl.cpp]
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
sp<SurfaceControl> surface = client->createSurface(
String8(name.c_str()), w, h, format, flags);
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return 0;
}
surface->incStrong((void *)nativeCreate);
return reinterpret_cast<jlong>(surface.get());
}
複製代碼
該函數首先獲得前面建立好的SurfaceComposerClient對象,經過該對象向SurfaceFlinger端的Client對象發送建立Surface的請求,最後獲得一個SurfaceControl對象。 [->SurfaceComposerClient.cpp]
sp<SurfaceControl> SurfaceComposerClient::createSurface(
const String8& name,
uint32_t w,
uint32_t h,
PixelFormat format,
uint32_t flags)
{
sp<SurfaceControl> sur;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IGraphicBufferProducer> gbp;
status_t err = mClient->createSurface(name, w, h, format, flags,
&handle, &gbp);
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
sur = new SurfaceControl(this, handle, gbp);
}
}
return sur;
}
複製代碼
SurfaceComposerClient將Surface建立請求轉交給保存在其成員變量中的Bp SurfaceComposerClient對象來完成,在SurfaceFlinger端的Client本地對象會返回一個ISurface代理對象給應用程序,經過該代理對象爲應用程序當前建立的Surface建立一個SurfaceControl對象。 [ISurfaceComposerClient.cpp]
virtual status_t createSurface(const String8& name, uint32_t width,
uint32_t height, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp) {
Parcel data, reply;
......
remote()->transact(CREATE_SURFACE, data, &reply);
*handle = reply.readStrongBinder();
*gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
return reply.readInt32();
}
複製代碼
[Client.cpp] MessageCreateSurface消息是專門爲應用程序請求建立Surface而定義的一種消息類型:
status_t Client::createSurface(
const String8& name,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp){
/*
* createSurface must be called from the GL thread so that it can
* have access to the GL context.
*/
class MessageCreateLayer : public MessageBase {
SurfaceFlinger* flinger;
Client* client;
sp<IBinder>* handle;
sp<IGraphicBufferProducer>* gbp;
status_t result;
const String8& name;
uint32_t w, h;
PixelFormat format;
uint32_t flags;
public:
MessageCreateLayer(SurfaceFlinger* flinger,
const String8& name, Client* client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp)
: flinger(flinger), client(client),
handle(handle), gbp(gbp), result(NO_ERROR),
name(name), w(w), h(h), format(format), flags(flags) {
}
status_t getResult() const { return result; }
virtual bool handler() {
result = flinger->createLayer(name, client, w, h, format, flags,
handle, gbp);
return true;
}
};
sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
name, this, w, h, format, flags, handle, gbp);
mFlinger->postMessageSync(msg);
return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}
Client將應用程序建立Surface的請求轉換爲異步消息投遞到SurfaceFlinger的消息隊列中,將建立Surface的任務轉交給SurfaceFlinger。
[->SurfaceFlinger.cpp]
status_t SurfaceFlinger::createLayer(
const String8& name,
const sp<Client>& client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp){
//ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
......
status_t result = NO_ERROR;
sp<Layer> layer;
////根據flags建立不一樣類型的layer
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
result = createNormalLayer(client,
name, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceDim:
result = createDimLayer(client,
name, w, h, flags,
handle, gbp, &layer);
break;
default:
result = BAD_VALUE;
break;
}
if (result != NO_ERROR) {
return result;
}
//將建立好的Layer對象保存在Client中
result = addClientLayer(client, *handle, *gbp, layer);
if (result != NO_ERROR) {
return result;
}
setTransactionFlags(eTransactionNeeded);
return result;
}
複製代碼
SurfaceFlinger根據標誌位建立對應類型的Surface,當前系統定義了2種類型的Layer: [->ISurfaceComposerClient.h]
eFXSurfaceNormal = 0x00000000,
eFXSurfaceDim = 0x00020000,
複製代碼
[->SurfaceFlinger.cpp]
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer){
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
format = PIXEL_FORMAT_RGBX_8888;
break;
}
//在SurfaceFlinger端爲應用程序的Surface建立對應的Layer對象
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getProducer();
}
ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
return err;
}
複製代碼
在SurfaceFlinger服務端爲應用程序建立的Surface建立對應的Layer對象。應用程序請求建立Surface過程以下:
第一次強引用Layer對象時,onFirstRef()函數被回調 [Layer.cpp]
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
//建立BufferQueue對象
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,
this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
#else
mProducer->setMaxDequeuedBufferCount(2);
#endif
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
updateTransformHint(hw);
}
複製代碼
根據buffer可用監聽器的註冊過程,咱們知道,當生產者也就是應用程序填充好圖形buffer數據後,經過回調方式通知消費者的
BufferQueue構造過程
[->BufferQueue.cpp]
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {
......
sp<BufferQueueCore> core(new BufferQueueCore(allocator));
sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
*outProducer = producer;
*outConsumer = consumer;
}
複製代碼
[->BufferQueueCore.cpp] 因此核心都是這個BufferQueueCore,他是管理圖形緩衝區的中樞。這裏舉一個SurfaceTexture的例子,來看看他們之間的關係:
BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
mAllocator(allocator),
......
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mAllocator = composer->createGraphicBufferAlloc();
if (mAllocator == NULL) {
BQ_LOGE("createGraphicBufferAlloc failed");
}
}
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
}
for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
s++) {
mUnusedSlots.push_front(s);
}
}
複製代碼
BufferQueueCore類中定義了一個64項的數據mSlots,是一個容量大小爲64的數組,所以BufferQueueCore能夠管理最多64塊的GraphicBuffer。
[->ISurfaceComposer.cpp]
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
}
複製代碼
[->SurfaceFlinger.cpp]
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
{
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
return gba;
}
複製代碼
GraphicBufferAlloc構造過程
[->GraphicBufferAlloc.cpp]
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t usage,
std::string requestorName, status_t* error) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
width, height, format, usage, std::move(requestorName)));
status_t err = graphicBuffer->initCheck();
......
return graphicBuffer;
}
複製代碼
圖形緩衝區建立過程
[->GraphicBuffer.cpp]
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
{
width =
height =
stride =
format =
usage = 0;
handle = NULL;
mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,
std::move(requestorName));
}
複製代碼
根據圖形buffer的寬高、格式等信息爲圖形緩衝區分配存儲空間。
使用GraphicBufferAllocator對象來爲圖形緩衝區分配內存空間,GraphicBufferAllocator是對Gralloc模塊中的gpu設備的封裝類。圖形緩衝區分配完成後,還會映射到SurfaceFlinger服務進程的虛擬地址空間。
Android圖形緩衝區分配過程源碼分析
[->Layer.cpp]
Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags)
: contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
mTextureName(-1U),
mPremultipliedAlpha(true),
mName("unnamed"),
mFormat(PIXEL_FORMAT_NONE),
......{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
......
}
複製代碼
到此纔算真正建立了一個可用於繪圖的Surface (Layer),從上面的分析咱們能夠看出,在WMS服務進程端,其實建立了兩個Java層的Surface對象,第一個Surface使用了無參構造函數,僅僅構造一個Surface對象而已,而第二個Surface卻使用了有參構造函數,參數指定了圖象寬高等信息,這個Java層Surface對象還會在native層請求SurfaceFlinger建立一個真正能用於繪製圖象的native層Surface。最後經過淺拷貝的方式將第二個Surface複製到第一個Surface中,最後經過writeToParcel方式寫回到應用程序進程。
public void copyFrom(SurfaceControl other) {
......
long surfaceControlPtr = other.mNativeObject;
......
long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
setNativeObjectLocked(newNativeObject);
}
}
複製代碼
[android_view_Surface.cpp]
static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
jlong surfaceControlNativeObj) {
/*
* This is used by the WindowManagerService just after constructing
* a Surface and is necessary for returning the Surface reference to
* the caller. At this point, we should only have a SurfaceControl.
*/
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
sp<Surface> surface(ctrl->getSurface());
if (surface != NULL) {
surface->incStrong(&sRefBaseOwner);
}
return reinterpret_cast<jlong>(surface.get());
}
複製代碼
2號Surface引用到了3號Surface的SurfaceControl對象後,經過writeToParcel()函數寫會到應用程序進程。 [Surface.java]
@Override
public void writeToParcel(Parcel dest, int flags) {
if (dest == null) {
throw new IllegalArgumentException("dest must not be null");
}
synchronized (mLock) {
// NOTE: This must be kept synchronized with the native parceling code
// in frameworks/native/libs/Surface.cpp
dest.writeString(mName);
dest.writeInt(mIsSingleBuffered ? 1 : 0);
nativeWriteToParcel(mNativeObject, dest);
}
if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
release();
}
}
複製代碼
[android_view_Surface.cpp]
static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel == NULL) {
doThrowNPE(env);
return;
}
sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
android::view::Surface surfaceShim;
if (self != nullptr) {
surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
}
// Calling code in Surface.java has already written the name of the Surface
// to the Parcel
surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
}
複製代碼
應用程序進程中的1號Surface按相反順序讀取WMS服務端返回過來的Binder對象等數據,並構造一個native層的Surface對象。
public void readFromParcel(Parcel source) {
if (source == null) {
throw new IllegalArgumentException("source must not be null");
}
synchronized (mLock) {
// nativeReadFromParcel() will either return mNativeObject, or
// create a new native Surface and return it after reducing
// the reference count on mNativeObject. Either way, it is
// not necessary to call nativeRelease() here.
// NOTE: This must be kept synchronized with the native parceling code
// in frameworks/native/libs/Surface.cpp
mName = source.readString();
mIsSingleBuffered = source.readInt() != 0;
setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
}
}
複製代碼
應用程序進程中的1號Surface按相反順序讀取WMS服務端返回過來的Binder對象等數據,並構造一個native層的Surface對象。
static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
jlong surfaceControlNativeObj) {
/*
* This is used by the WindowManagerService just after constructing
* a Surface and is necessary for returning the Surface reference to
* the caller. At this point, we should only have a SurfaceControl.
*/
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
sp<Surface> surface(ctrl->getSurface());
if (surface != NULL) {
surface->incStrong(&sRefBaseOwner);
}
return reinterpret_cast<jlong>(surface.get());
}
複製代碼
每一個Activity能夠有一個或多個Surface,默認狀況下一個Activity只有一個Surface,當Activity中使用SurfaceView時,就存在多個Surface。Activity默認surface是在relayoutWindow過程當中由WMS服務建立的,而後回傳給應用程序進程,咱們知道一個Surface其實就是應用程序端的本地窗口,關於Surface的初始化過程這裏就不在介紹。
應用程序本地窗口Surface建立過程
從前面分析可知,SurfaceFlinger在處理應用程序請求建立Surface中,在SurfaceFlinger服務端僅僅建立了Layer對象,那麼應用程序本地窗口Surface在何時、什麼地方建立呢?
爲應用程序建立好了Layer對象並返回ISurface的代理對象給應用程序,應用程序經過該代理對象建立了一個SurfaceControl對象,Java層Surface須要經過android_view_Surface.cpp中的JNI函數來操做native層的Surface,在操做native層Surface前,首先須要獲取到native的Surface,應用程序本地窗口Surface就是在這個時候建立的。 [->SurfaceControl.cpp]
sp<Surface> SurfaceControl::getSurface() const
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false. mSurfaceData = new Surface(mGraphicBufferProducer, false); } return mSurfaceData; } 複製代碼
[Surface.cpp]
Surface::Surface(
const sp<IGraphicBufferProducer>& bufferProducer,
bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
mGenerationNumber(0),
mSharedBufferMode(false),
mAutoRefresh(false),
mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
mSharedBufferHasBeenQueued(false),
mNextFrameNumber(1)
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
mReqWidth = 0;
mReqHeight = 0;
mReqFormat = 0;
mReqUsage = 0;
mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
mDataSpace = HAL_DATASPACE_UNKNOWN;
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
mStickyTransform = 0;
mDefaultWidth = 0;
mDefaultHeight = 0;
mUserWidth = 0;
mUserHeight = 0;
mTransformHint = 0;
mConsumerRunningBehind = false;
mConnectedToCpu = false;
mProducerControlledByApp = controlledByApp;
mSwapIntervalZero = false;
}
複製代碼
在建立完應用程序本地窗口Surface後,想要在該Surface上繪圖,首先須要爲該Surface分配圖形buffer。咱們前面介紹了Android應用程序圖形緩衝區的分配都是由SurfaceFlinger服務進程來完成,在請求建立Surface時,在服務端建立了一個BufferQueue本地Binder對象,該對象負責管理應用程序一個本地窗口Surface的圖形緩衝區。
三、執行窗口布局performLayout()
[->ViewRootImpl.java]
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
mLayoutRequested = false;
mScrollMayChange = true;
mInLayout = true;
final View host = mView;
try {
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
mInLayout = false;
int numViewsRequestingLayout = mLayoutRequesters.size();
if (numViewsRequestingLayout > 0) {
// requestLayout() was called during layout.
// If no layout-request flags are set on the requesting views, there is no problem.
// If some requests are still pending, then we need to clear those flags and do
// a full request/measure/layout pass to handle this situation.
ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
false);
if (validLayoutRequesters != null) {
// Set this flag to indicate that any further requests are happening during
// the second pass, which may result in posting those requests to the next
// frame instead
mHandlingLayoutInLayoutRequest = true;
// Process fresh layout requests, then measure and layout
int numValidRequests = validLayoutRequesters.size();
for (int i = 0; i < numValidRequests; ++i) {
final View view = validLayoutRequesters.get(i);
Log.w("View", "requestLayout() improperly called by " + view +
" during layout: running second layout pass");
view.requestLayout();
}
measureHierarchy(host, lp, mView.getContext().getResources(),
desiredWindowWidth, desiredWindowHeight);
mInLayout = true;
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
mHandlingLayoutInLayoutRequest = false;
// Check the valid requests again, this time without checking/clearing the
// layout flags, since requests happening during the second pass get noop'd validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); if (validLayoutRequesters != null) { final ArrayList<View> finalRequesters = validLayoutRequesters; // Post second-pass requests to the next frame getRunQueue().post(new Runnable() { @Override public void run() { int numValidRequests = finalRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = finalRequesters.get(i); view.requestLayout(); } } });} } } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } mInLayout = false; } 複製代碼
4.執行窗口繪製performDraw()
[->ViewRootImpl.java]
private void performDraw() {
......
try {
draw(fullRedrawNeeded);
} finally {
mIsDrawing = false;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
......
}
}
複製代碼
Android是怎樣將View畫出來的? [->ViewRootImpl.java]
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
......
mAttachInfo.mTreeObserver.dispatchOnDraw();
int xOffset = -mCanvasOffsetX;
int yOffset = -mCanvasOffsetY + curScrollY;
final WindowManager.LayoutParams params = mWindowAttributes;
final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
if (surfaceInsets != null) {
xOffset -= surfaceInsets.left;
yOffset -= surfaceInsets.top;
// Offset dirty rect for surface insets.
dirty.offset(surfaceInsets.left, surfaceInsets.right);
}
boolean accessibilityFocusDirty = false;
final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
if (drawable != null) {
final Rect bounds = mAttachInfo.mTmpInvalRect;
final boolean hasFocus = getAccessibilityFocusedRect(bounds);
if (!hasFocus) {
bounds.setEmpty();
}
if (!bounds.equals(drawable.getBounds())) {
accessibilityFocusDirty = true;
}
}
mAttachInfo.mDrawingTime =
mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
// If accessibility focus moved, always invalidate the root.
boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
mInvalidateRootRequested = false;
// Draw with hardware renderer.
mIsAnimating = false;
if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
mHardwareYOffset = yOffset;
mHardwareXOffset = xOffset;
invalidateRoot = true;
}
if (invalidateRoot) {
mAttachInfo.mHardwareRenderer.invalidateRoot();
}
......
if (updated) {
requestDrawWindow();
}
mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
} else {
if (mAttachInfo.mHardwareRenderer != null &&
!mAttachInfo.mHardwareRenderer.isEnabled() &&
mAttachInfo.mHardwareRenderer.isRequested()) {
try {
mAttachInfo.mHardwareRenderer.initializeIfNeeded(
mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
return;
}
mFullRedrawNeeded = true;
scheduleTraversals();
return;
}
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
}
}
if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
}
複製代碼
這裏咱們由於要分析Surface機制,因此只分析ViewRootImpl的draw流程。(若是開啓了硬件加速功能,則會使用hwui硬件繪製功能,這裏咱們忽略這個,使用默認的軟件繪製流程drawSoftware)。 [->ViewRootImpl.java]
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
// Draw with software renderer.
final Canvas canvas;
try {
......
canvas = mSurface.lockCanvas(dirty);
......
} ......
try {
canvas.translate(-xoff, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
attachInfo.mSetIgnoreDirtyState = false;
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
}......
} finally {
try {
surface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
......
return false;
}
}
return true;
}
複製代碼
先看看Surface的lockCanvas方法: [->Surface.java]
//mCanvas 變量直接賦值
private final Canvas mCanvas = new CompatibleCanvas();
public Canvas lockCanvas(Rect inOutDirty)
throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
checkNotReleasedLocked();
......
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
}
}
複製代碼
[->android_view_Surface.cpp]
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
//獲取java層的Surface保存的long型句柄
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if (!isSurfaceValid(surface)) {
doThrowIAE(env);
return 0;
}
Rect dirtyRect(Rect::EMPTY_RECT);
Rect* dirtyRectPtr = NULL;
//獲取java層dirty Rect的位置大小信息
if (dirtyRectObj) {
dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
dirtyRectPtr = &dirtyRect;
}
ANativeWindow_Buffer outBuffer;
//調用Surface的lock方法,將申請的圖形緩衝區賦給outBuffer
status_t err = surface->lock(&outBuffer, dirtyRectPtr);
......
SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
convertPixelFormat(outBuffer.format),
outBuffer.format == PIXEL_FORMAT_RGBX_8888 ?
kOpaque_SkAlphaType : kPremul_SkAlphaType);
SkBitmap bitmap;
//建立一個SkBitmap
//圖形緩衝區每一行像素大小
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
bitmap.setInfo(info, bpr);
if (outBuffer.width > 0 && outBuffer.height > 0) {
bitmap.setPixels(outBuffer.bits);
} else {
// be safe with an empty bitmap.
bitmap.setPixels(NULL);
}
Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
nativeCanvas->setBitmap(bitmap);
if (dirtyRectPtr) {
nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom);
}
if (dirtyRectObj) {
env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left);
env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top);
env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right);
env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
}
......
sp<Surface> lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
return (jlong) lockedSurface.get();
}
複製代碼
這段代碼邏輯主要以下:
1)獲取java層dirty 的Rect大小和位置信息;
2)調用Surface的lock方法,將申請的圖形緩衝區賦給outBuffer;
3)建立一個Skbitmap,填充它用來保存申請的圖形緩衝區,並賦值給Java層的Canvas對象;
4)將剪裁位置大小信息賦給java層Canvas對象。
複製代碼
unlockCanvasAndPost() Surface繪製完畢後,unlockCanvasAndPost操做。
[->android_view_Surface.cpp]
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if (!isSurfaceValid(surface)) {
return;
}
// detach the canvas from the surface
Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
nativeCanvas->setBitmap(SkBitmap());
// unlock surface
status_t err = surface->unlockAndPost();
if (err < 0) {
doThrowIAE(env);
}
}
複製代碼
Surface管理圖形緩衝區 咱們上邊分析到了申請圖形緩衝區,用到了Surface的lock函數,咱們繼續查看。 [->Surface.cpp]
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
......
ANativeWindowBuffer* out;
int fenceFd = -1;
//調用dequeueBuffer函數,申請圖形緩衝區
status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
//獲取圖形緩衝區區域大小,賦給後備緩衝區變量backBuffer
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
const Rect bounds(backBuffer->width, backBuffer->height);
Region newDirtyRegion;
if (inOutDirtyBounds) {
//若是上層指定樂刷新髒矩形區域,則用這個區域和緩衝區區域求交集,
//而後將交集的結果設給須要去刷新的新區域
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
newDirtyRegion.andSelf(bounds);
} else {
/若是上層沒有指定髒矩形區域,因此刷新整個圖形緩衝區
newDirtyRegion.set(bounds);
}
// figure out if we can copy the frontbuffer back
//上一次繪製的信息保存在mPostedBuffer中,而這個mPostedBuffer則要在unLockAndPost函數中設置
int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
Mutex::Autolock lock(mMutex);
Region oldDirtyRegion;
if(mSlots[backBufferSlot].dirtyRegion.isEmpty()) {
oldDirtyRegion.set(bounds);
} else {
for(int i = 0 ; i < NUM_BUFFER_SLOTS; i++ ) {
if(i != backBufferSlot && !mSlots[i].dirtyRegion.isEmpty())
oldDirtyRegion.orSelf(mSlots[i].dirtyRegion);
}
}
const Region copyback(oldDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
//這裏把mPostedBuffer中的舊數據拷貝到BackBuffer中。
//後續的繪畫只要更新髒區域就能夠了,這會節約很多資源
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
//若是兩次圖形緩衝區大小不一致,咱們就要修改用戶指定的dirty區域大小爲整個緩衝區大小,
//而後去更新整個緩衝區
newDirtyRegion.set(bounds);
Mutex::Autolock lock(mMutex);
for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
mSlots[i].dirtyRegion.clear();
}
}
{ // scope for the lock
Mutex::Autolock lock(mMutex);
//將新的dirty賦給這個bufferslot
mSlots[backBufferSlot].dirtyRegion = newDirtyRegion;
}
if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds();
}
void* vaddr;
//lock和unlock分別用來鎖定和解鎖一個指定的圖形緩衝區,在訪問一塊圖形緩衝區的時候,
//例如,向一塊圖形緩衝寫入內容的時候,須要將該圖形緩衝區鎖定,用來避免訪問衝突,
//鎖定以後,就能夠得到由參數參數l、t、w和h所圈定的一塊緩衝區的起始地址,保存在輸出參數vaddr中
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd);
......
}
return err;
}
複製代碼
Surface的lock函數用來申請圖形緩衝區和一些操做,方法不長,大概工做有: 1)調用connect函數完成一些初始化; 2)調用dequeueBuffer函數,申請圖形緩衝區; 3)計算須要繪製的新的dirty區域,舊的區域原樣copy數據。 [->BufferQueueProducer.cpp]
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
uint32_t reqWidth;
uint32_t reqHeight;
PixelFormat reqFormat;
uint32_t reqUsage;
{
......
//申請圖形緩衝區
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
reqWidth, reqHeight, reqFormat, reqUsage);
......
//根據index獲取緩衝區
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
......
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
//因爲申請的內存是在surfaceflinger進程中,
//BufferQueue中的圖形緩衝區也是經過匿名共享內存和binder傳遞描述符映射過去的,
//Surface經過調用requestBuffer將圖形緩衝區映射到Surface所在進程
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
......
}
......
//獲取這個這個buffer對象的指針內容
*buffer = gbuf.get();
......
return OK;
}
複製代碼
[->BufferQueueProducer.cpp]
status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ATRACE_CALL();
Mutex::Autolock lock(mCore->mMutex);
......
mSlots[slot].mRequestBufferCalled = true;
*buf = mSlots[slot].mGraphicBuffer;
return NO_ERROR;
}
複製代碼
這個比較簡單,仍是很好理解的額,就是根據指定index取出mSlots中的slot中的buffer。
圖形緩衝區入隊
咱們前面講了,省略了第二步繪製流程,所以咱們這裏分析第三部,繪製完畢後再queueBuffer。 一樣,調用了Surface的unlockCanvasAndPost函數,咱們查看它的實現: [->Surface.cpp]
status_t Surface::unlockAndPost()
{
......
int fd = -1;
//解鎖圖形緩衝區,和前面的lockAsync成對出現
status_t err = mLockedBuffer->unlockAsync(&fd);
//queueBuffer去歸還圖形緩衝區
err = queueBuffer(mLockedBuffer.get(), fd);
mPostedBuffer = mLockedBuffer;
mLockedBuffer = 0;
return err;
}
複製代碼
這裏也比較簡單,核心也是分兩步: 1)解鎖圖形緩衝區,和前面的lockAsync成對出現; 2)queueBuffer去歸還圖形緩衝區; 因此咱們仍是重點分析第二步,查看queueBuffer的實現: [->Surface.cpp]
int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
......
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
mLastQueueDuration = systemTime() - now;
......
return err;
}
複製代碼
調用BufferQueueProducer的queueBuffer歸還緩衝區,將繪製後的圖形緩衝區queue回去。 [->BufferQueueProducer.cpp]
status_t BufferQueueProducer::queueBuffer(int slot,
const QueueBufferInput &input, QueueBufferOutput *output) {
......
{ // scope for the lock
Mutex::Autolock lock(mCallbackMutex);
while (callbackTicket != mCurrentCallbackTicket) {
mCallbackCondition.wait(mCallbackMutex);
}
if (frameAvailableListener != NULL) {
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != NULL) {
frameReplacedListener->onFrameReplaced(item);
}
......
}
......
return NO_ERROR;
}
複製代碼
總結: 1)從傳入的QueueBufferInput ,解析填充一些變量; 2)改變入隊Slot的狀態爲QUEUED,每次推動來,mFrameCounter都加1。這裏的slot,上一篇講分配緩衝區返回最老的FREE狀態buffer,就是用這個mFrameCounter最小值判斷,就是上一篇LRU算法的判斷; 3)建立一個BufferItem來描述GraphicBuffer,用mSlots[slot]中的slot填充BufferItem; 4)將BufferItem塞進mCore的mQueue隊列,依照指定規則; 5)而後通知SurfaceFlinger去消費。
上述lockCanvas和unlockCanvasAndPost能夠用下圖來總結一下:
通知SF消費合成
當繪製完畢的GraphicBuffer入隊以後,會通知SurfaceFlinger去消費,就是BufferQueueProducer的queueBuffer函數的最後幾行,listener->onFrameAvailable()。 listener最終經過回調,會回到Layer當中,因此最終調用Layer的onFrameAvailable接口,咱們看看它的實現: [Layer.cpp]
void Layer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
......
mQueueItems.push_back(item);
android_atomic_inc(&mQueuedFrames);
// Wake up any pending callbacks
mLastFrameNumberReceived = item.mFrameNumber;
mQueueItemCondition.broadcast();
}
mFlinger->signalLayerUpdate();
}
複製代碼
這裏又調用SurfaceFlinger的signalLayerUpdate函數,繼續查看: [SurfaceFlinger.cpp]
void SurfaceFlinger::signalLayerUpdate() {
mEventQueue.invalidate();
}
複製代碼
這裏又調用MessageQueue的invalidate函數: [MessageQueue.cpp]
void MessageQueue::invalidate() {
mEvents->requestNextVsync();
}
複製代碼
貼一下SurfaceFlinger的初始化請求vsync信號流程圖:
最終結果會走到SurfaceFlinger的vsync信號接收邏輯,即SurfaceFlinger的onMessageReceived函數: [SurfaceFlinger.cpp]
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
mPreviousPresentFence->getSignalTime() == INT64_MAX;
ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
if (mPropagateBackpressure && frameMissed) {
signalLayerUpdate();
break;
}
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}
case MessageQueue::REFRESH: {
handleMessageRefresh();
break;
}
}
}
複製代碼
SurfaceFlinger收到了VSync信號後,調用了handleMessageRefresh函數 [SurfaceFlinger.cpp]
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
preComposition();
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition();
postComposition(refreshStartTime);
mPreviousPresentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
mHadClientComposition = false;
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
mHadClientComposition = mHadClientComposition ||
mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
}
// Release any buffers which were replaced this frame
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer();
}
mLayersWithQueuedFrames.clear();
}
複製代碼
咱們主要看下下面幾個函數。 [SurfaceFlinger.cpp]
preComposition();
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition();
postComposition(refreshStartTime);
複製代碼
1、preComposition()函數
咱們先來看第一個函數preComposition() [SurfaceFlinger.cpp]
void SurfaceFlinger::preComposition()
{
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
if (layers[i]->onPreComposition()) {
needExtraInvalidate = true;
}
}
if (needExtraInvalidate) {
signalLayerUpdate();
}
}
複製代碼
上面函數先是調用了mDrawingState的layersSortedByZ來獲得上次繪圖的Layer層列表。並非全部的Layer都會參與屏幕圖像的繪製,所以SurfaceFlinger用state對象來記錄參與繪製的Layer對象。 記得咱們以前分析過createLayer函數來建立Layer,建立以後會調用addClientLayer函數。 [SurfaceFlinger.cpp]
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc)
{
// add this layer to the current state list
{
Mutex::Autolock _l(mStateLock);
if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
return NO_MEMORY;
}
mCurrentState.layersSortedByZ.add(lbc);
mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
}
// attach this layer to the client
client->attachLayer(handle, lbc);
return NO_ERROR;
}
複製代碼
咱們來看下addClientLayer函數,這裏會把Layer對象放在mCurrentState的layersSortedByZ對象中。而mDrawingState和mCurrentState什麼關係呢?在後面咱們會介紹,mDrawingState表明上一次繪圖時的狀態,處理完以後會把mCurrentState賦給mDrawingState。 回到preComposition函數,遍歷全部的Layer對象,調用其onPreComposition函數來檢測Layer層中的圖像是否有變化。
1.一、每一個Layer的onFrameAvailable函數
onPreComposition函數來根據mQueuedFrames來判斷圖像是否發生了變化,或者是mSidebandStreamChanged、mAutoRefresh。 [Layer.cpp]
bool Layer::onPreComposition() {
mRefreshPending = false;
return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
}
複製代碼
當Layer所對應的Surface更新圖像後,它所對應的Layer對象的onFrameAvailable函數會被調用來通知這種變化。 在SurfaceFlinger的preComposition函數中當有Layer的圖像改變了,最後也會調用SurfaceFlinger的signalLayerUpdate函數。 SurfaceFlinger::signalLayerUpdate是調用了MessageQueue的invalidate函數 最後處理仍是調用了SurfaceFlinger的onMessageReceived函數。看看SurfaceFlinger的onMessageReceived函數對NVALIDATE的處理 handleMessageInvalidate函數中調用了handlePageFlip函數,這個函數將會處理Layer中的緩衝區,把更新過的圖像緩衝區切換到前臺,等待VSync信號更新到FrameBuffer。
1.二、繪製流程
具體完整的繪製流程如圖。
2、handleTransaction handPageFlip更新Layer對象
在上一節中的繪圖的流程中,咱們看到了handleTransaction和handPageFlip這兩個函數一般是在用戶進程更新Surface圖像時會調用,來更新Layer對象。這節就主要講解這兩個函數。
2.一、handleTransaction函數
handleTransaction函數的參數是transactionFlags,不過函數中沒有使用這個參數,而是經過getTransactionFlags(eTransactionMask)來從新對transactionFlags賦值,而後使用它做爲參數來調用函數 handleTransactionLocked。 [SurfaceFlinger.cpp]
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
}
複製代碼
getTransactionFlags函數的參數是eTransactionMask只是屏蔽其餘位。 handleTransactionLocked函數會調用每一個Layer類的doTransaction函數,在分析handleTransactionLocked函數以前,咱們先看看Layer類 的doTransaction函數。
2.二、Layer的doTransaction函數
下面是Layer的doTransaction函數代碼 [Layer.cpp]
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
pushPendingState();//上次繪製的State對象
Layer::State c = getCurrentState();//當前使用的State對象
const Layer::State& s(getDrawingState());
const bool sizeChanged = (c.requested.w != s.requested.w) ||
(c.requested.h != s.requested.h);
if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
//若是Layer的尺寸發生變化,就要改變Surface的緩衝區的尺寸
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size. mSurfaceFlingerConsumer->setDefaultBufferSize( c.requested.w, c.requested.h); } const bool resizePending = (c.requested.w != c.active.w) || (c.requested.h != c.active.h); if (!isFixedSize()) { if (resizePending && mSidebandStream == NULL) { //若是Layer不是固定尺寸的類型,比較它的實際大小和要求的改變大小 flags |= eDontUpdateGeometryState; } } //若是沒有eDontUpdateGeometryState標誌,更新active的值爲request if (flags & eDontUpdateGeometryState) { } else { Layer::State& editCurrentState(getCurrentState()); if (mFreezePositionUpdates) { float tx = c.active.transform.tx(); float ty = c.active.transform.ty(); c.active = c.requested; c.active.transform.set(tx, ty); editCurrentState.active = c.active; } else { editCurrentState.active = editCurrentState.requested; c.active = c.requested; } } // 若是當前state的active和之前的State的active不等,設置更新標誌 if (s.active != c.active) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; } //若是當前state的sequence和之前state的sequence不等,設置更新標誌 if (c.sequence != s.sequence) { // invalidate and recompute the visible regions if needed flags |= eVisibleRegion; this->contentDirty = true; // we may use linear filtering, if the matrix scales us const uint8_t type = c.active.transform.getType(); mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE)); } // If the layer is hidden, signal and clear out all local sync points so // that transactions for layers depending on this layer's frames becoming
// visible are not blocked
if (c.flags & layer_state_t::eLayerHidden) {
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
point->setFrameAvailable();
}
mLocalSyncPoints.clear();
}
// Commit the transaction
commitTransaction(c);
return flags;
}
複製代碼
Layer類中的兩個類型爲Layer::State的成員變量mDrawingState、mCurrentState,這裏爲何要兩個對象呢?Layer對象在繪製圖形時,使用的是mDrawingState變量,用戶調用接口設置Layer對象屬性是,設置的值保存在mCurrentState對象中,這樣就不會由於用戶的操做而干擾Layer對象的繪製了。 Layer的doTransaction函數據你是比較這兩個變量,若是有不一樣的地方,說明在上次繪製之後,用戶改變的Layer的設置,要把這種變化經過flags返回。 State的結構中有兩個Geometry字段,active和requested。他們表示layer的尺寸,其中requested保存是用戶設置的尺寸,而active保存的值經過計算後的實際尺寸。 State中的z字段的值就是Layer在顯示軸的位置,值越小位置越靠下。 layerStack字段是用戶指定的一個值,用戶能夠給DisplayDevice也指定一個layerStack值,只有Layer對象和DisplayDevice對象的layerStack相等,這個Layer才能在這個顯示設備上輸出,這樣的好處是可讓顯示設備只顯示某個Surface的內容。例如,可讓HDMI顯示設備只顯示手機上播放視頻的Surface窗口,但不顯示Activity窗口。 sequence字段是個序列值,每當用戶調用了Layer的接口,例如setAlpha、setSize或者setLayer等改變Layer對象屬性的哈數,這個值都會加1。所以在doTransaction函數中能經過比較sequence值來判斷Layer的屬性值有沒有變化。 doTransaction函數最後會調用commitTransaction函數,就是把mCurrentState賦值給mDrawingState [Layer.cpp]
void Layer::commitTransaction(const State& stateToCommit) {
mDrawingState = stateToCommit;
}
複製代碼
2.三、handleTransactionLocked函數
下面咱們來分析handleTransactionLocked函數,這個函數比較長,咱們分段分析
2.3.1 處理Layer的事務 [SurfaceFlinger.cpp]
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
// Notify all layers of available frames
for (size_t i = 0; i < count; ++i) {
currentLayers[i]->notifyAvailableFrames();
}
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
const uint32_t flags = layer->doTransaction(0);
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
}
複製代碼
在SurfaceFlinger中也有兩個類型爲State的變量mCurrentState和mDrawingState,可是和Layer中的不要混起來。它的名字相同而已
struct State {
LayerVector layersSortedByZ;
DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
};
複製代碼
結構layersSortedByZ字段保存全部參與繪製的Layer對象,而字段displays保存的是全部輸出設備的DisplayDeviceState對象 這裏用兩個變量的目的是和Layer中使用兩個變量是同樣的。 上面代碼根據eTraversalNeeded標誌來決定是否要檢查全部的Layer對象。若是某個Layer對象中有eTransactionNeeded標誌,將調用它的doTransaction函數。Layer的doTransaction函數返回的flags若是有eVisibleRegion,說明這個Layer須要更新,就把mVisibleRegionsDirty設置爲true
2.3.二、處理顯示設備的變化
if (transactionFlags & eDisplayTransactionNeeded) {
// here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when // know that the lists are identical const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; const size_t cc = curr.size(); size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) for (size_t i=0 ; i<dc ; i++) { const ssize_t j = curr.indexOfKey(draw.keyAt(i)); if (j < 0) { // in drawing state but not in current state if (!draw[i].isMainDisplay()) { // Call makeCurrent() on the primary display so we can // be sure that nothing associated with this display // is current. const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice()); defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) mEventThread->onHotplugReceived(draw[i].type, false); mDisplays.removeItem(draw.keyAt(i)); } else { ALOGW("trying to remove the main display"); } } else { // this display is in both lists. see if something changed. const DisplayDeviceState& state(curr[j]); const wp<IBinder>& display(curr.keyAt(j)); const sp<IBinder> state_binder = IInterface::asBinder(state.surface); const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface); if (state_binder != draw_binder) { // changing the surface is like destroying and // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added // below. sp<DisplayDevice> hw(getDisplayDevice(display)); if (hw != NULL) hw->disconnect(getHwComposer()); mDisplays.removeItem(display); mDrawingState.displays.removeItemsAt(i); dc--; i--; // at this point we must loop to the next item continue; } const sp<DisplayDevice> disp(getDisplayDevice(display)); if (disp != NULL) { if (state.layerStack != draw[i].layerStack) { disp->setLayerStack(state.layerStack); } if ((state.orientation != draw[i].orientation) || (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) { disp->setProjection(state.orientation, state.viewport, state.frame); } if (state.width != draw[i].width || state.height != draw[i].height) { disp->setDisplaySize(state.width, state.height); } } } } // find displays that were added // (ie: in current state but not in drawing state) for (size_t i=0 ; i<cc ; i++) { if (draw.indexOfKey(curr.keyAt(i)) < 0) { const DisplayDeviceState& state(curr[i]); sp<DisplaySurface> dispSurface; sp<IGraphicBufferProducer> producer; sp<IGraphicBufferProducer> bqProducer; sp<IGraphicBufferConsumer> bqConsumer; BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, new GraphicBufferAlloc()); int32_t hwcDisplayId = -1; if (state.isVirtualDisplay()) { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { int width = 0; DisplayUtils* displayUtils = DisplayUtils::getInstance(); int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); int height = 0; status = state.surface->query( NATIVE_WINDOW_HEIGHT, &height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 || (width <= MAX_VIRTUAL_DISPLAY_DIMENSION && height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) { int usage = 0; status = state.surface->query( NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); ALOGW_IF(status != NO_ERROR, "Unable to query usage (%d)", status); if ( (status == NO_ERROR) && displayUtils->canAllocateHwcDisplayIdForVDS(usage)) { hwcDisplayId = allocateHwcDisplayId(state.type); } } displayUtils->initVDSInstance(mHwc, hwcDisplayId, state.surface, dispSurface, producer, bqProducer, bqConsumer, state.displayName, state.isSecure, state.type); } } else { ALOGE_IF(state.surface!=NULL, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); hwcDisplayId = allocateHwcDisplayId(state.type); // for supported (by hwc) displays we provide our // own rendering surface dispSurface = new FramebufferSurface(*mHwc, state.type, bqConsumer); producer = bqProducer; } const wp<IBinder>& display(curr.keyAt(i)); if (dispSurface != NULL && producer != NULL) { sp<DisplayDevice> hw = new DisplayDevice(this, state.type, hwcDisplayId, mHwc->getFormat(hwcDisplayId), state.isSecure, display, dispSurface, producer, mRenderEngine->getEGLConfig()); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); // When a new display device is added update the active // config by querying HWC otherwise the default config // (config 0) will be used. if (hwcDisplayId >= DisplayDevice::DISPLAY_PRIMARY && hwcDisplayId < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { int activeConfig = mHwc->getActiveConfig(hwcDisplayId); if (activeConfig >= 0) { hw->setActiveConfig(activeConfig); } } mDisplays.add(display, hw); if (state.isVirtualDisplay()) { if (hwcDisplayId >= 0) { mHwc->setVirtualDisplayProperties(hwcDisplayId, hw->getWidth(), hw->getHeight(), hw->getFormat()); } } else { mEventThread->onHotplugReceived(state.type, true); } } } } } } 複製代碼
這段代碼的做用是處理顯示設備的變化,分紅3種狀況: 1.顯示設備減小了,須要把顯示設備對應的DisplayDevice移除 2.顯示設備發生了變化,例如用戶設置了Surface、從新設置了layerStack、旋轉了屏幕等,這就須要從新設置顯示對象的屬性 3.顯示設備增長了,建立新的DisplayDevice加入系統中。
2.3.三、設置TransfromHit
if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
......
sp<const DisplayDevice> disp;
uint32_t currentlayerStack = 0;
for (size_t i=0; i<count; i++) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list // of displays for every layer). const sp<Layer>& layer(currentLayers[i]); uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored // (more than one display) if so, pick the default display, // if not, pick the only display it's on.
disp.clear();
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
if (hw->getLayerStack() == currentlayerStack) {
if (disp == NULL) {
disp = hw;
} else {
disp = NULL;
break;
}
}
}
}
if (disp == NULL) {
// NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
// redraw after transform hint changes. See bug 8508397.
// could be null when this layer is using a layerStack
// that is not visible on any display. Also can occur at
// screen off/on times.
disp = getDefaultDisplayDevice();
}
layer->updateTransformHint(disp);
}
}
複製代碼
這段代碼的做用是根據每種顯示設備的不一樣,設置和顯示設備關聯在一塊兒的Layer(主要看Layer的layerStack是否和DisplayDevice的layerStack)的TransformHint(主要指設備的顯示方向orientation)。
2.3.四、處理Layer增長狀況
/*
* Perform our own transaction if needed
*/
const LayerVector& layers(mDrawingState.layersSortedByZ);
if (currentLayers.size() > layers.size()) {
// layers have been added
mVisibleRegionsDirty = true;
}
// some layers might have been removed, so
// we need to update the regions they're exposing. if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.active.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); } } } 複製代碼
這段代碼處理Layer的增長狀況,若是Layer增長了,須要從新計算設備的更新區域,所以把mVisibleRegionsDirty設爲true,若是Layer刪除了,須要把Layer的可見區域加入到系統須要更新的區域中。
2.3.五、設置mDrawingState
commitTransaction();
updateCursorAsync();
}
複製代碼
調用commitTransaction和updateCursorAsync函數 commitTransaction函數做用是把mDrawingState的值設置成mCurrentState的值。而updateCursorAsync函數會更新全部顯示設備中光標的位置。
2.3.6 小結 handleTransaction函數的做用的就是處理系統在兩次刷新期間的各類變化。SurfaceFlinger模塊中無論是SurfaceFlinger類仍是Layer類,都採用了雙緩衝的方式來保存他們的屬性,這樣的好處是剛改變SurfaceFlinger對象或者Layer類對象的屬性是,不須要上鎖,大大的提升了系統效率。只有在最後的圖像輸出是,才進行一次上鎖,並進行內存的屬性變化處理。正所以,應用進程必須收到VSync信號纔開始改變Surface的內容。
2.四、handlePageFlip函數
handlePageFlip函數代碼以下: [SurfaceFlinger.cpp]
bool SurfaceFlinger::handlePageFlip()
{
Region dirtyRegion;
bool visibleRegions = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
bool frameQueued = false;
// Store the set of layers that need updates. This set must not change as
// buffers are being latched, as this could result in a deadlock.
// Example: Two producers share the same command stream and:
// 1.) Layer 0 is latched
// 2.) Layer 0 gets a new frame
// 2.) Layer 1 gets a new frame
// 3.) Layer 1 is latched.
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display. Vector<Layer*> layersWithQueuedFrames; for (size_t i = 0, count = layers.size(); i<count ; i++) { const sp<Layer>& layer(layers[i]); if (layer->hasQueuedFrame()) { frameQueued = true; if (layer->shouldPresentNow(mPrimaryDispSync)) { layersWithQueuedFrames.push_back(layer.get()); } else { layer->useEmptyDamage(); } } else { layer->useEmptyDamage(); } } for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) { Layer* layer = layersWithQueuedFrames[i]; const Region dirty(layer->latchBuffer(visibleRegions)); layer->useSurfaceDamage(); const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); } mVisibleRegionsDirty |= visibleRegions; // If we will need to wake up at some time in the future to deal with a // queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
if (frameQueued && layersWithQueuedFrames.empty()) {
signalLayerUpdate();
}
// Only continue with the refresh if there is actually new work to do
return !layersWithQueuedFrames.empty();
}
複製代碼
handlePageFlip函數先調用每一個Layer對象的hasQueuedFrame函數,肯定這個Layer對象是否有須要更新的圖層,而後把須要更新的Layer對象放到layersWithQueuedFrames中。 咱們先來看Layer的hasQueuedFrame方法就是看其mQueuedFrames是否大於0 和mSidebandStreamChanged。前面小節分析只要Surface有數據寫入,就會調用Layer的onFrameAvailable函數,而後mQueuedFrames值加1. 繼續看handlePageFlip函數,接着調用須要更新的Layer對象的latchBuffer函數,而後根據返回的更新區域調用invalidateLayerStack函數來設置更新設備對象的更新區域。 下面咱們看看latchBuffer函數
LatchBuffer函數調用updateTextImage來獲得須要的圖像。這裏參數r是Reject對象,其做用是判斷在緩衝區的尺寸是否符合要求。調用updateTextImage函數若是獲得的結果是PRESENT_LATER,表示推遲處理,而後調用signalLayerUpdate函數來發送invalidate消息,此次繪製過程就不處理這個Surface的圖像了。 若是不須要推遲處理,把mQueuedFrames的值減1. 最後LatchBuffer函數調用mSurfaceFlingerConsumer的getCurrentBuffer來取回當前的圖像緩衝區指針,保存在mActiveBuffer中。
2.5 小結
這樣通過handleTransaction handlePageFlip兩個函數處理,SurfaceFlinger中不管是Layer屬性的變化仍是圖像的變化都處理好了,只等VSync信號到來就能夠輸出了。
3、rebuildLayerStacks函數
前面介紹,VSync信號到來後,先是調用了rebuildLayerStacks函數
void SurfaceFlinger::rebuildLayerStacks() {
updateExtendedMode();
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_CALL();
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
//計算每一個顯示設備上可見的Layer
const LayerVector& layers(mDrawingState.layersSortedByZ);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
Region opaqueRegion;
Region dirtyRegion;
Vector< sp<Layer> > layersSortedByZ;
const sp<DisplayDevice>& hw(mDisplays[dpy]);
const Transform& tr(hw->getTransform());
const Rect bounds(hw->getBounds());
if (hw->isDisplayOn()) {
//計算每一個layer的可見區域,肯定設備須要從新繪製的區域
computeVisibleRegions(hw->getHwcDisplayId(), layers,
hw->getLayerStack(), dirtyRegion, opaqueRegion);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Layer>& layer(layers[i]);
{
//只須要和顯示設備的LayerStack相同的layer
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
//若是Layer的顯示區域和顯示設備的窗口有交集
//把Layer加入列表中
layersSortedByZ.add(layer);
}
}
}
}
//設置顯示設備的可見Layer列表
hw->setVisibleLayersSortedByZ(layersSortedByZ);
hw->undefinedRegion.set(bounds);
hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
hw->dirtyRegion.orSelf(dirtyRegion);
}
}
}
複製代碼
rebuildLayerStacks函數的做用是重建每一個顯示設備的可見layer對象列表。對於按顯示軸(Z軸)排列的Layer對象,排在最前面的固然會優先顯示,可是Layer圖像可能有透明域,也可能有尺寸沒有覆蓋整個屏幕,所以下面的layer也有顯示的機會。rebuildLayerStacks函數對每一個顯示設備,先計算和顯示設備具備相同layerStack值的Layer對象在該顯示設備上的可見區域。而後將可見區域和顯示設備的窗口區域有交集的layer組成一個新的列表,最後把這個列表設置到顯示設備對象中。 computeVisibleRegions函數首先計算每一個Layer在設備上的可見區域visibleRegion。計算方法就是用整個Layer的區域減去上層全部不透明區域aboveOpaqueLayers。而上層全部不透明區域值是一個逐層累計的過程,每層都須要把本身的不透明區域累加到aboveOpaqueLayers中。 而每層的不透明區域的計算方法:若是Layer的alpha的值爲255,而且layer的isOpaque函數爲true,則本層的不透明區域等於Layer所在區域,不然爲0.這樣一層層算下來,就很容易獲得每層的可見區域大小了。 其次,計算整個顯示設備須要更新的區域outDirtyRegion。outDirtyRegion的值也是累計全部層的須要重回的區域獲得的。若是Layer中的顯示內容發生了變化,則整個可見區域visibleRegion都須要更新,同時還要包括上一次的可見區域,而後在去掉被上層覆蓋後的區域獲得的就是Layer須要更新的區域。若是Layer顯示的內容沒有變化,可是考慮到窗口大小的變化或者上層窗口的變化,所以Layer中仍是有區域能夠須要重繪的地方。這種狀況下最簡單的算法是用Layer計算出可見區域減去之前的可見區域就能夠了。可是在computeVisibleRegions函數還引入了被覆蓋區域,一般被覆蓋區域和可見區域並不重複,所以函數中計算暴露區域是用可見區域減去被覆蓋區域的。
4、setUpHWComposer函數
setUpHWComposer函數的做用是更新HWComposer對象中圖層對象列表以及圖層屬性。 [SurfaceFlinger.cpp]
void SurfaceFlinger::setUpHWComposer() {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
......
bool mustRecompose = dirty && !(empty && wasEmpty);
......
mDisplays[dpy]->beginFrame(mustRecompose);
if (mustRecompose) {
mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
}
}
//獲得系統HWComposer對象
HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
// build the h/w work list
if (CC_UNLIKELY(mHwWorkListDirty)) {
mHwWorkListDirty = false;
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
//根據Layer數量在HWComposer中建立hwc_layer_list_t列表
if (hwc.createWorkList(id, count) == NO_ERROR) {
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<Layer>& layer(currentLayers[i]);
layer->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
cur->setSkip(true);
}
}
}
}
}
}
// set the per-frame data
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
bool freezeSurfacePresent = false;
isfreezeSurfacePresent(freezeSurfacePresent, hw, id);
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
/*
* update the per-frame h/w composer data for each layer
* and build the transparent region of the FB
*/
const sp<Layer>& layer(currentLayers[i]);
//將Layer的mActiveBuffer設置到HWComposer中
layer->setPerFrameData(hw, *cur);
setOrientationEventControl(freezeSurfacePresent,id);
}
}
}
// If possible, attempt to use the cursor overlay on each display.
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<Layer>& layer(currentLayers[i]);
if (layer->isPotentialCursor()) {
cur->setIsCursorLayerHint();
break;
}
}
}
}
dumpDrawCycle(true);
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
hw->prepareFrame(hwc);
}
}
}
複製代碼
HWComposer中有一個類型爲DisplayData結構的數組mDisplayData,它維護着每一個顯示設備的信息。DisplayData結構中有一個類型爲hwc_display_contents_l字段list,這個字段又有一個hwc_layer_l類型的數組hwLayers,記錄該顯示設備全部須要輸出的Layer信息。 setUpHWComposer函數調用HWComposer的createWorkList函數就是根據每種顯示設備的Layer數量,建立和初始化hwc_display_contents_l對象和hwc_layer_l數組 建立完HWComposer中的列表後,接下來是對每一個Layer對象調用它的setPerFrameData函數,參數是HWComposer和HWCLayerInterface。setPerFrameData函數將Layer對象的當前圖像緩衝區mActiveBuffer設置到HWCLayerInterface對象對應的hwc_layer_l對象中。 HWComposer類中除了前面介紹的Gralloc還管理着Composer模塊,這個模塊實現了硬件的圖像合成功能。setUpHWComposer函數接下來調用HWComposer類的prepare函數,而prepare函數會調用Composer模塊的prepare接口。最後到各個廠家的實現hwc_prepare函數將每種HWComposer中的全部圖層的類型都設置爲HWC_FRAMEBUFFER就結束了。
5、合成全部層的圖像 (doComposition()函數)
doComposition函數是合成全部層的圖像,代碼以下: [SurfaceFlinger.cpp]
void SurfaceFlinger::doComposition() {
ATRACE_CALL();
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->isDisplayOn()) {
// transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); // repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion); hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); } // inform the h/w that we're done compositing
hw->compositionComplete();
}
postFramebuffer();
}
複製代碼
doComposition函數針對每種顯示設備調用doDisplayComposition函數來合成,合成後調用postFramebuffer函數,咱們先來看看doDisplayComposition函數
void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
const Region& inDirtyRegion)
{
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty) bool isHwcDisplay = hw->getHwcDisplayId() >= 0; if (!isHwcDisplay && inDirtyRegion.isEmpty()) { ALOGV("Skipping display composition"); return; } ALOGV("doDisplayComposition"); Region dirtyRegion(inDirtyRegion); // compute the invalid region //swapRegion設置爲須要更新的區域 hw->swapRegion.orSelf(dirtyRegion); uint32_t flags = hw->getFlags();//得到顯示設備支持的更新方式標誌 if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only
// takes a rectangle, we must make sure to update that whole
// rectangle in that case
dirtyRegion.set(hw->swapRegion.bounds());
} else {
if (flags & DisplayDevice::PARTIAL_UPDATES) {//支持部分更新
// We need to redraw the rectangle that will be updated
// (pushed to the framebuffer).
// This is needed because PARTIAL_UPDATES only takes one
// rectangle instead of a region (see DisplayDevice::flip())
//將更新區域調整爲整個窗口大小
dirtyRegion.set(hw->swapRegion.bounds());
} else {
// we need to redraw everything (the whole screen)
dirtyRegion.set(hw->bounds());
hw->swapRegion = dirtyRegion;
}
}
//合成
if (!doComposeSurfaces(hw, dirtyRegion)) return;
// update the swap region and clear the dirty region
hw->swapRegion.orSelf(dirtyRegion);
//沒有硬件composer的狀況,輸出圖像
// swap buffers (presentation)
hw->swapBuffers(getHwComposer());
}
複製代碼
doDisplayComposition函數根據顯示設備支持的更新方式,從新設置須要更新區域的大小。 真正的合成工做是在doComposerSurfaces函數中完成,這個函數在layer的類型爲HWC_FRAMEBUFFER,或者不支持硬件的composer的狀況下,調用layer的draw函數來一層一層低合成最後的圖像。 合成完後,doDisplayComposition函數調用了hw的swapBuffers函數,這個函數前面介紹過了,它將在系統不支持硬件的composer狀況下調用eglSwapBuffers來輸出圖像到顯示設備。
6、postFramebuffer函數
上一節的doComposition函數最後調用了postFramebuffer函數,代碼以下: [SurfaceFlinger.cpp]
void SurfaceFlinger::postFramebuffer()
{
ATRACE_CALL();
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
if (!hwc.supportsFramebufferTarget()) {
// EGL spec says:
// "surface must be bound to the calling thread's current context, // for the current rendering API."
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
}
hwc.commit();
}
// make the default display current because the VirtualDisplayDevice code cannot
// deal with dequeueBuffer() being called outside of the composition loop; however
// the code below can call glFlush() which is allowed (and does in some case) call
// dequeueBuffer().
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
hw->onSwapBuffersCompleted(hwc);
const size_t count = currentLayers.size();
int32_t id = hw->getHwcDisplayId();
if (id >=0 && hwc.initCheck() == NO_ERROR) {
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
currentLayers[i]->onLayerDisplayed(hw, &*cur);
}
} else {
for (size_t i = 0; i < count; i++) {
currentLayers[i]->onLayerDisplayed(hw, NULL);
}
}
}
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
logFrameStats();
}
}
複製代碼
postFramebuffer先判斷系統是否支持composer,若是不支持,咱們知道圖像已經在doComposition函數時調用hw->swapBuffers輸出了,就返回了。若是支持硬件composer,postFramebuffer函數將調用HWComposer的commit函數繼續執行。 [HWComposer.cpp]
status_t HWComposer::commit() {
int err = NO_ERROR;
if (mHwc) {
if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// On version 1.0, the OpenGL ES target surface is communicated
// by the (dpy, sur) fields and we are guaranteed to have only
// a single display.
mLists[0]->dpy = eglGetCurrentDisplay();
mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
}
for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {
DisplayData& disp(mDisplayData[i]);
if (disp.outbufHandle) {
mLists[i]->outbuf = disp.outbufHandle;
mLists[i]->outbufAcquireFenceFd =
disp.outbufAcquireFence->dup();
}
}
err = mHwc->set(mHwc, mNumDisplays, mLists);
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
disp.lastDisplayFence = disp.lastRetireFence;
disp.lastRetireFence = Fence::NO_FENCE;
if (disp.list) {
if (disp.list->retireFenceFd != -1) {
disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
disp.list->retireFenceFd = -1;
}
disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
}
}
}
return (status_t)err;
}
複製代碼