안드로이드 Framework 단계에서 Surface 생성과정

안드로이드/프레임워크 2015. 4. 30. 19:12

 안드로이드 기기에 있어 가장 중요한 부분이라 할 수 있는 것 중 하나가 바로 기기의 화면에 나오는 View들을 제대로 처리하는 것이라 생각합니다. 특히 역동적인 안드로이드 화면을 출력하기 위해서는 SurfaceView를 사용하게 됩니다. 이번 포스팅에서는 안드로이드 Framework 단계에서 Surface가 생성돠는 과정에 대해 살펴보도록 하겠습니다.


※본 예제는 Android의 Camera 동작 과정을 토대로 Surface가 동작하는 과정에 대해 다루었습니다.


/frameworks/base/core/java/android/hardware/Camera.java

1
2
3
4
5
6
7
    public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
        if (holder != null) {
            setPreviewDisplay(holder.getSurface());
        } else {
            setPreviewDisplay((Surface)null);
        }
    }
cs


 안드로이드의 카메라 Preview를 설정하는 과정에서 setPreviewDisplay() 함수를 통해 SurfaceView 클래스가 적용되고 있는 상황을 나타내고 있습니다. holder 내의 SurfaceView 클래스는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class SurfaceView extends View {
    static private final String TAG = "SurfaceView";
    static private final boolean DEBUG = false;
 
    final ArrayList<SurfaceHolder.Callback> mCallbacks
            = new ArrayList<SurfaceHolder.Callback>();
 
    final int[] mLocation = new int[2];
 
    final ReentrantLock mSurfaceLock = new ReentrantLock();
    final Surface mSurface = new Surface();       // Current surface in use
    final Surface mNewSurface = new Surface();    // New surface we are switching to
....
    /**
     * Return the SurfaceHolder providing access and control over this
     * SurfaceView's underlying surface.
     *
     * @return SurfaceHolder The holder of the surface.
     */
    public SurfaceHolder getHolder() {
        return mSurfaceHolder;
    }
....
 
    private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
 
        private static final String LOG_TAG = "SurfaceHolder";
....
        @Override
        public Surface getSurface() {
            return mSurface;
        }
 
        @Override
        public Rect getSurfaceFrame() {
            return mSurfaceFrame;
        }
    };
}
cs


 위의 소스코드를 통해 holder가 mSurface를 return 하고 있고 mSurface는 new Surface()를 통해 클래스를 생성하고 있는 것을 확인하실 수 있습니다. 그렇다면 이번에는 Surface 클래스가 생성되는 과정을 살펴보도록 합시다.


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Surface implements Parcelable {
    private static final String TAG = "Surface";
....
    // Guarded state.
    final Object mLock = new Object(); // protects the native state
    private String mName;
    int mNativeObject; // package scope only for SurfaceControl access
....
    /**
     * Create an empty surface, which will later be filled in by readFromParcel().
     * @hide
     */
    public 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.
            mName = source.readString();
            setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
        }
    }
....
    private void setNativeObjectLocked(int ptr) {
        if (mNativeObject != ptr) {
            if (mNativeObject == 0 && ptr != 0) {
                mCloseGuard.open("release");
            } else if (mNativeObject != 0 && ptr == 0) {
                mCloseGuard.close();
            }
            mNativeObject = ptr;
            mGenerationId += 1;
        }
    }
....
}
 
cs


 맨 처음에 surface가 생성될 때에는 빈 Class 하나가 생성됩니다. 이후 readFromParcel()을 통하여 Surface 클래스 내에 mNativeObject의 값이 채워지게 되며 nativeReadFromParcel() 함수는 다음과 같다.


/frameworks/base/core/jni/android_view_Surface.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
static jint nativeReadFromParcel(JNIEnv* env, jclass clazz,
        jint nativeObject, jobject parcelObj) {
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    if (parcel == NULL) {
        doThrowNPE(env);
        return 0;
    }
 
    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
    sp<IBinder> binder(parcel->readStrongBinder());
 
    // update the Surface only if the underlying IGraphicBufferProducer
    // has changed.
    if (self != NULL
            && (self->getIGraphicBufferProducer()->asBinder() == binder)) {
        // same IGraphicBufferProducer, return ourselves
        return int(self.get());
    }
 
    sp<Surface> sur;
    sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
    if (gbp != NULL) {
        // we have a new IGraphicBufferProducer, create a new Surface for it
        sur = new Surface(gbp, true);
        // and keep a reference before passing to java
        sur->incStrong(&sRefBaseOwner);
    }
 
    if (self != NULL) {
        // and loose the java reference to ourselves
        self->decStrong(&sRefBaseOwner);
    }
 
    return int(sur.get());
}
cs


 일단 지금은 이러한 방식으로 Surface가 생성되고 있구나 라고 감을 잡으시고 이해를 하고 넘어가셨으면 합니다. 위 코드를 확인해보고 예상컨데 Surface로 Parcel을 보내는 주체는 IGraphicBufferProduce를 넘겨주고 있는 듯 하다는 생각으로 진행하면 될 것으로 보입니다.



300x250