Android 8.0 graphics engine and form management service (WMS)

Keywords: Java Android Session

In the above four articles, Android's graphics engine is viewed from the hardware abstraction layer, data drive, rendering, output and other aspects of the graphics engine. From the perspective of engine input, the data input end of the engine mainly includes UI, Camera, Media and so on. Today, from the perspective of UI, we take setContentView of Activity as the starting point, running through phonewindow, viewrootimpl, WindowManager and WindowManager Rservice up to the engine entry SufaceComposerClient and Surface.

1. Create rootview

frameworks\base\core\java\android\app\Activity.java
Calling the setContentView method in the onCreate() lifecycle function of Activity

   public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID); //Setting up layout
        initWindowDecorActionBar();
    }

frameworks\base\core\java\com\android\internal\policy\PhoneWindow.java
PhoneWindow inherits from the Window class and overloads the setContentView method of the parent class

 @Override
    public void setContentView(int layoutResID) {
        ......
        if (mContentParent == null) {
            installDecor(); // DecorView associated with Window
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent); // Analytical layout
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

frameworks\base\core\java\com\android\internal\policy\PhoneWindow.java
Create a DecorView, add it to the PhoneWindow, analyze the layout, and add it to the DecorView

 private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1); // Generate DecorView
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this); //Associate PhoneWindow with DecorView
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor); //Generate content area

            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
            mDecor.makeOptionalFitsSystemWindows();

            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                    R.id.decor_content_parent);
        }
    }

frameworks\base\core\java\android\app\ActivityThread.java
When the onResume function of Activity wakes up, the parsed View will be added to the PhoneWindow

 final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ActivityClientRecord r = mActivities.get(token);
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l); //Call the addView method of ViewManager
                    } else {
                        // The activity will get a callback for this {@link LayoutParams} change
                        // earlier. However, at that time the decor will not be set (this is set
                        // in this method), so no action will be taken. This call ensures the
                        // callback occurs with the decor set.
                        a.onWindowAttributesChanged(l);
                    }
                }
            }
        }
    }

frameworks\base\core\java\android\view\WindowManagerImpl.java
WindowManagerImpl inherits from WindowManager and indirectly from ViewManager

 @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        // mGlobal is an instance of WindowManagerGlobal
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

frameworks\base\core\java\android\view\WindowManagerGlobal.java
WindowManagerGlobal

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); //Newly build

            view.setLayoutParams(wparams);

            mViews.add(view); //Manage all views
            mRoots.add(root); //Manage all root ViewRootImpl
            mParams.add(wparams); //Manage layout parameters

            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView); // Set current root layout parameters
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

frameworks\base\core\java\android\view\ViewRootImpl.java

 public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession(); //Get Session of WMS
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();
        mThread = Thread.currentThread();
        mLocation = new WindowLeaked(null);
        mLocation.fillInStackTrace();
        mWindow = new W(this); //Draw IWindow and receive commands from WMS
        ......
}

2. Connect to WindowManagerService

frameworks\base\core\java\android\view\WindowManagerGlobal.java
Connect WMS, get the connection sWindowSession

  public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
   }
    
 public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    if (sWindowManagerService != null) {
                        ValueAnimator.setDurationScale(
                                sWindowManagerService.getCurrentAnimatorScale());
                    }
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
Return a Session token to the ViewRootImpl class

 @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;
    }

3. Drawing of view

frameworks\base\core\java\android\view\ViewRootImpl.java

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ......
				requestLayout(); //Request layout
                ......
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    // mWindow is a subclass W instance of IWinbdow
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                   ......
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
            }
        }
    }

frameworks\base\core\java\android\view\ViewRootImpl.java

  @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals(); //Scheduling rendering
        }
    }
  void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true; //Turn on the draw switch
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
  final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
  final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal(); //implement
        }
    }
 void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals(); // Famous performTraversals

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

frameworks\base\core\java\android\view\ViewRootImpl.java — performTraversals()
The performTraversals method is too long. Let's segment analysis

if (!cancelDraw && !newSurface) {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }

            performDraw(); //Draw
        } else {
            if (isViewVisible) {
                // Try again
                scheduleTraversals(); //retry
            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                }
                mPendingTransitions.clear();
            }
        }

        mIsInTraversal = false;

frameworks\base\core\java\android\view\ViewRootImpl.java

 private void performDraw() {
        .....
        final boolean fullRedrawNeeded = mFullRedrawNeeded;
        mFullRedrawNeeded = false;

        mIsDrawing = true;
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
        try {
            draw(fullRedrawNeeded);
        } finally {
            mIsDrawing = false;
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        .....
    }

frameworks\base\core\java\android\view\ViewRootImpl.java

  /**
     * @return true if drawing was successful, false if an error occurred
     */
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty) {

        // Draw with software renderer.
        final Canvas canvas;
        try {
            final int left = dirty.left;
            final int top = dirty.top;
            final int right = dirty.right;
            final int bottom = dirty.bottom;

            canvas = mSurface.lockCanvas(dirty); //Lock canvas
            ......
        } catch (Surface.OutOfResourcesException e) {
            handleOutOfResourcesException(e);
            return false;
        } catch (IllegalArgumentException e) {
            Log.e(mTag, "Could not lock surface", e);
            // Don't assume this is due to out of memory, it could be
            // something else, and if it is something else then we could
            // kill stuff (or ourself) for no reason.
            mLayoutRequested = true;    // ask wm for a new surface next time.
            return false;
        }

        try {
           ......
        } finally {
            try {
                surface.unlockCanvasAndPost(canvas); //Unlocking and submitting data
            } catch (IllegalArgumentException e) {
                Log.e(mTag, "Could not unlock surface", e);
                mLayoutRequested = true;    // ask wm for a new surface next time.
                //noinspection ReturnInsideFinallyBlock
                return false;
            }

            if (LOCAL_LOGV) {
                Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
            }
        }
        return true;
    }

frameworks\base\core\java\android\view\Surface.java

private void unlockSwCanvasAndPost(Canvas canvas) {
        if (canvas != mCanvas) {
            throw new IllegalArgumentException("canvas object must be the same instance that "
                    + "was previously returned by lockCanvas");
        }
        if (mNativeObject != mLockedObject) {
            Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
                    Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
                    Long.toHexString(mLockedObject) +")");
        }
        if (mLockedObject == 0) {
            throw new IllegalStateException("Surface was not locked");
        }
        try {
            nativeUnlockCanvasAndPost(mLockedObject, canvas);
        } finally {
            nativeRelease(mLockedObject);
            mLockedObject = 0;
        }
    }

frameworks\base\core\jni\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(); // finally, if you remember the function we analyzed last time
    if (err < 0) {
        doThrowIAE(env);
    }
}

4. Connect to the graphic engine SurfaceFlinger

frameworks\base\core\java\android\view\ViewRootImpl.java
Add Window to WMS

    @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);
    }
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 parentWindow = null;
        long origId;
        final int callingUid = Binder.getCallingUid();
        final int type = attrs.type;

        synchronized(mWindowMap) {
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }

           //Processing window level
           .......

            win.attach(); //Associated graphics engine, win is WindowState type
            
            mWindowMap.put(client.asBinder(), win);
            win.mToken.addWindow(win);
            ........
            }

           ......

        return res;
    }

frameworks\base\services\core\java\com\android\server\wm\WindowState.java

    void attach() {
        if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
        mSession.windowAddedLocked(mAttrs.packageName); //Window add
    }

frameworks\base\services\core\java\com\android\server\wm\Session.java

 void windowAddedLocked(String packageName) {
        mPackageName = packageName;
        mRelayoutTag = "relayoutWindow: " + mPackageName;
        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++;
    }

frameworks\base\core\java\android\view\SurfaceSession.java

  /** Create a new connection with the surface flinger. */
    public SurfaceSession() {
        mNativeClient = nativeCreate();
    }

frameworks\base\core\jni\android_view_SurfaceSession.cpp
Create SurfaceComposerClient

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient(); //finally, if you remember this class, it's a medium to connect to the graphics engine
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}

frameworks\native\libs\gui\SurfaceComposerClient.cpp
SurfaceComposerClient automatically connects to SurfaceFlinger when it is created

void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        auto rootProducer = mParent.promote();
        sp<ISurfaceComposerClient> conn;
        conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) :
                sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

5. Surface creation

frameworks\base\core\java\android\view\ViewRootImpl.java — performTraversals()

 try {
        ......
        //Layout window
        relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
       ......
    }            

frameworks\base\core\java\android\view\ViewRootImpl.java

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {

        float appScale = mAttachInfo.mApplicationScale;
        boolean restore = false;
        if (params != null && mTranslator != null) {
            restore = true;
            params.backup();
            mTranslator.translateWindowLayout(params);
        }
        ......
        //layout of Session
        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,
                mPendingMergedConfiguration, mSurface);
         .....
        return relayoutResult;
    }

frameworks\base\services\core\java\com\android\server\wm\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,
            MergedConfiguration mergedConfiguration, Surface outSurface) {
        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                + Binder.getCallingPid());
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
        int res = mService.relayoutWindow(this, window, seq, attrs,
                requestedWidth, requestedHeight, viewFlags, flags,
                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                + Binder.getCallingPid());
        return res;
    }

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

    public 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,
            MergedConfiguration mergedConfiguration, Surface outSurface) {
      
            if (viewVisibility == View.VISIBLE &&
                    (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                            || !win.mAppToken.isClientHidden())) {
                ......
                try {
                //Create Surface
                result = createSurfaceControl(outSurface, result, win, winAnimator);
                } catch (Exception e) {
                    mInputMonitor.updateInputWindowsLw(true /*force*/);

                    Slog.w(TAG_WM, "Exception thrown when creating surface for client "
                             + client + " (" + win.mAttrs.getTitle() + ")",
                             e);
                    Binder.restoreCallingIdentity(origId);
                    return 0;
                }
               ......
            }
          }
        Binder.restoreCallingIdentity(origId);
        return result;
    }

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

 private int createSurfaceControl(Surface outSurface, int result, WindowState win,
            WindowStateAnimator winAnimator) {
        if (!win.mHasSurface) {
            result |= RELAYOUT_RES_SURFACE_CHANGED;
        }

        WindowSurfaceController surfaceController;
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
            surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        if (surfaceController != null) {
            surfaceController.getSurface(outSurface);
            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurface + ": copied");
        } else {
            // For some reason there isn't a surface.  Clear the
            // caller's object so they see the same state.
            Slog.w(TAG_WM, "Failed to create surface control for " + win);
            outSurface.release();
        }

        return result;
    }

frameworks\base\services\core\java\com\android\server\wm\WindowStateAnimator.java

WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
        final WindowState w = mWin;
        if (w.restoreSavedSurface()) {
            if (DEBUG_ANIM) Slog.i(TAG,
                    "createSurface: " + this + ": called when we had a saved surface");
            return mSurfaceController;
        }

        if (mSurfaceController != null) {
            return mSurfaceController;
        }

        w.setHasSurface(false);
        try {
           ......
           //Create WindowSurfaceController
            mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
                    attrs.getTitle().toString(),
                    width, height, format, flags, this, windowType, ownerUid);
            mSurfaceFormat = format;

            w.setHasSurface(true);

       
        } catch (OutOfResourcesException e) {
            Slog.w(TAG, "OutOfResourcesException creating surface");
            mService.mRoot.reclaimSomeSurfaceMemory(this, "create", true);
            mDrawState = NO_SURFACE;
            return null;
        } 
       ......
        mLastHidden = true;

        if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
        return mSurfaceController;
    }

frameworks\base\services\core\java\com\android\server\wm\WindowSurfaceController.java

 public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
            int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
        ......

        if (DEBUG_SURFACE_TRACE) {
            mSurfaceControl = new SurfaceTrace(
                    s, name, w, h, format, flags, windowType, ownerUid);
        } else {
            //Create SurfaceControl
            mSurfaceControl = new SurfaceControl(
                    s, name, w, h, format, flags, windowType, ownerUid);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
      ......
    }

frameworks\base\core\java\android\view\SurfaceControl.java
Continue to call the nativeCreate method of JNI layer

 public SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, int windowType, int ownerUid)
                    throws OutOfResourcesException {
        ......
        mNativeObject = nativeCreate(session, name, w, h, format, flags,
            parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
       ......
    }

frameworks\base\core\jni\android_view_SurfaceControl.cpp
JNI layer creates a local SurfaceControl. SurfaceControl has the function of creating Surface, which we mentioned in the previous article

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jint windowType, jint ownerUid) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    //Familiar taste
    sp<SurfaceControl> surface = client->createSurface(
            String8(name.c_str()), w, h, format, flags, parent, windowType, ownerUid);
    if (surface == NULL) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return 0;
    }
    surface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(surface.get());
}

6. True and false Surface

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
In the createSurfaceControl function of WindowManagerService, after the SurfaceController is created, the following methods continue to be called

  void getSurface(Surface outSurface) {
        outSurface.copyFrom(mSurfaceControl);
    }

frameworks\base\core\java\android\view\Surface.java
The famous copyFrom method, the way of changing civet for prince, is brilliant

 public void copyFrom(SurfaceControl other) {
        ......
        long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
        .....
    }

frameworks\base\core\jni\android_view_Surface.cpp
Retrieve Surface from SurfaceControl

static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz,
        jlong surfaceControlNativeObj) {
    ......
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
    sp<Surface> surface(ctrl->getSurface()); //The Surface object returned to the java layer is created
    if (surface != NULL) {
        surface->incStrong(&sRefBaseOwner);
    }
    return reinterpret_cast<jlong>(surface.get());
}

OK, that's it today!

Posted by countdrac on Sun, 15 Dec 2019 08:35:24 -0800