blog

SurfaceFlinger起動プロセス解析

上記からわかるように、所属するクラスはmainで、zygoteと同じレベルです。しかし、これはパラメータで始める必要はありません。同時に、サービスであるため、独立した実行可能ファイルであり、プログラム...

Apr 7, 2020 · 8 min. read
シェア

surfaceFlingerはinit.rcにサービスとして存在し、次のように宣言されています。

service surfaceflinger /system/bin/surfaceflinger
 class main
 user system
 group graphics drmrpc
 onrestart restart zygote

上記からわかるように、surfaceflingerはzygoteと同じクラスmainに属しています。しかし、パラメータをつけて起動する必要はありません。同時に、surfaceflingerはサービスであるため、別の実行ファイルであり、プログラムパスは/system/bin/surfaceflingerで、別のプロセスで実行されます。

int main(int argc, char** argv) {
 // When SF is launched in its own process, limit the number of
 // binder threads to 4.
 ProcessState::self()->setThreadPoolMaxThreadCount(4);//バインダースレッドの数を4
 // start the thread pool
 sp<ProcessState> ps(ProcessState::self());
 ps->startThreadPool();//バインダースレッドを起動する
 // instantiate surfaceflinger
 sp<SurfaceFlinger> flinger = new SurfaceFlinger();//SFオブジェクトを作る
#if defined(HAVE_PTHREADS)
 setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
#endif
 set_sched_policy(0, SP_FOREGROUND);
 // initialize before clients can connect
 flinger->init();//SFレイヤーの初期化は 
 // publish surface flinger
 sp<IServiceManager> sm(defaultServiceManager());
 sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);//SMに追加する
 // run in this thread
 flinger->run();//sf実行する。
 return 0;
}

1.バインダーの実行環境の初期化 2.Sfオブジェクトの生成と初期化 3.他のプロセスにサービスを提供するために、ServiceMangerにSfサービスを追加 4.Sfは自身のスレッドで実行開始 5.

サービスプロセスであるSurfaceFlingerは、必然的にBinderを介したIPC通信を必要とするため、最初にBinder環境を初期化する必要があります。次にSurfaceFlingerオブジェクトが生成されます。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
SurfaceFlinger::SurfaceFlinger()
 : BnSurfaceComposer(),
 mTransactionFlags(0),
 mTransactionPending(false),
 mAnimTransactionPending(false),
 mLayersRemoved(false),
 mRepaintEverything(0),
 mRenderEngine(NULL),
 mBootTime(systemTime()),
 mVisibleRegionsDirty(false),
 mHwWorkListDirty(false),
 mAnimCompositionPending(false),
 mDebugRegion(0),
 mDebugDDMS(0),
 mDebugDisableHWC(0),
 mDebugDisableTransformHint(0),
 mDebugInSwapBuffers(0),
 mLastSwapBufferTime(0),
 mDebugInTransaction(0),
 mLastTransactionTime(0),
 mBootFinished(false),
 mPrimaryHWVsyncEnabled(false),
 mHWVsyncAvailable(false),
 mDaltonize(false)
{
 // debugging stuff...
 char value[PROPERTY_VALUE_MAX];
 property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
 mGpuToCpuSupported = !atoi(value);
 property_get("debug.sf.showupdates", value, "0");
 mDebugRegion = atoi(value);
 property_get("debug.sf.ddms", value, "0");
 mDebugDDMS = atoi(value);
 if (mDebugDDMS) {
 if (!startDdmConnection()) {
 // start failed, and DDMS debugging not enabled
 mDebugDDMS = 0;
 }
 }
}

コンストラクタのメソッドはシンプルで、メンバを初期化し、DDMS デバッグが有効かどうかなどの設定情報を読み込むだけです。次に init メソッドでオブジェクトを初期化します。この初期化処理は多くの重要な仕事をします。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
//sfの初期化メソッドは
void SurfaceFlinger::init() {
 status_t err;
 Mutex::Autolock _l(mStateLock);
 // initialize EGL for the default display
 mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);//デフォルトの表示デバイスを取得する
 eglInitialize(mEGLDisplay, NULL, NULL);//デフォルト・ディスプレイ・デバイスの初期EGL環境
 // Initialize the H/W composer object. There may or may not be an
 // actual hardware composer underneath.
 mHwc = new HWComposer(this,
 *static_cast<HWComposer::EventHandler *>(this));//複合オブジェクトを作る
 // First try to get an ES2 config
 err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES2_BIT,
 &mEGLConfig);
 if (err != NO_ERROR) {
 // If ES2 fails, try ES1
 err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(),
 EGL_OPENGL_ES_BIT, &mEGLConfig);
 }
  
 EGLint r,g,b,a;
 eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_RED_SIZE, &r);
 eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_GREEN_SIZE, &g);
 eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_BLUE_SIZE, &b);
 eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_ALPHA_SIZE, &a);
 // get a RenderEngine for the given display / config (can't fail)
 mRenderEngine = RenderEngine::create(mEGLDisplay, mEGLConfig);//与えられたデバイスからレンダリング・エンジンを作る
 // retrieve the EGL context that was selected/created
 mEGLContext = mRenderEngine->getEGLContext();// EGL context
 // figure out which format we got
 eglGetConfigAttrib(mEGLDisplay, mEGLConfig,
 EGL_NATIVE_VISUAL_ID, &mEGLNativeVisualId);
 LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
 "couldn't create EGLContext");
 // initialize our non-virtual displays
 //全ての非仮想ディスプレイデバイスを初期化する。
 for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
 DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
 // set-up the displays that are already connected
 if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
 // All non-virtual displays are currently considered secure.
 bool isSecure = true;
 createBuiltinDisplayLocked(type);
 wp<IBinder> token = mBuiltinDisplays[i];
 //ディスプレイ・デバイスのフレーム・バッファを管理するためにBufferQueueを作り、FramebufferSurfaceを通して管理する。
 sp<BufferQueue> bq = new BufferQueue(new GraphicBufferAlloc());
 sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, bq);
 sp<DisplayDevice> hw = new DisplayDevice(this,
 type, allocateHwcDisplayId(type), isSecure, token,
 fbs, bq,
 mEGLConfig);//物理デバイスごとにディスプレイ・デバイス・オブジェクトを作る
 if (i > DisplayDevice::DISPLAY_PRIMARY) {
 // FIXME: currently we don't get blank/unblank requests
 // for displays other than the main display, so we always
 // assume a connected display is unblanked.
 ALOGD("marking display %d as acquired/unblanked", i);
 hw->acquireScreen();
 }
 mDisplays.add(token, hw);
 }
 }
 // make the GLContext current so that we can create textures when creating Layers
 // (which may happens before we render something)
 getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);//EGLコンテキストをデフォルト・ディスプレイ・デバイスに関連付ける
 // start the EventThread
 sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
 vsyncPhaseOffsetNs, true);//描画遅延オブジェクトを作る
 mEventThread = new EventThread(vsyncSrc);//描画遅延Vsyncシグナルの管理を担当する。
 sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
 sfVsyncPhaseOffsetNs, false);//合成遅延オブジェクトを作る
 mSFEventThread = new EventThread(sfVsyncSrc);//合成遅延Vsyncシグナルの管理を担当する。
 mEventQueue.setEventThread(mSFEventThread);
 mEventControlThread = new EventControlThread(this);
 mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
  
}

init メソッドで sf は次のことを行います: 1. デフォルトのディスプレイデバイスの EGL 環境を初期化します 2. 合成オブジェクトを作成します 3. すべての非仮想ディスプレイデバイスを初期化します 4. 描画遅延 Vysnc ソースと合成遅延 Vysnc ソースを作成します。

void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
 mEventThread = eventThread;
 mEvents = eventThread->createEventConnection();
 mEventTube = mEvents->getDataChannel();
 mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
 MessageQueue::cb_eventReceiver, this);//sfのvsyncシグナル用のイベントコールバックを登録する。
}

mainメソッドで生成されたSurfaceFlingerは強い参照オブジェクトなので、最初の呼び出しはonFirstRefメソッドもトリガーし、SFのmEventQueueメンバを初期化することに注意してください。これはSFのメッセージ管理を担うMessageQueueオブジェクトです。

void SurfaceFlinger::onFirstRef()
{
 mEventQueue.init(this);
}
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
{
 mFlinger = flinger;//への参照を保持する。
 mLooper = new Looper(true);//Looperオブジェクトを作る。
 mHandler = new Handler(*this);// Handler
}

最後に、sfのrunメソッドが呼び出され、メッセージが到着するのを常に待ち、それらを処理するループに入ります。

void SurfaceFlinger::run() {
 do {
 waitForEvent();
 } while (true);
}
void SurfaceFlinger::waitForEvent() {
 mEventQueue.waitMessage();
}
frameworks/native/services/surfaceflinger/MessageQueue.cpp
void MessageQueue::waitMessage() {
 do {
 IPCThreadState::self()->flushCommands();
 int32_t ret = mLooper->pollOnce(-1);//メッセージはMessageQueueのhandleMessageメソッドを呼び出すことで内部的に処理される。
 switch (ret) {
 case ALOOPER_POLL_WAKE:
 case ALOOPER_POLL_CALLBACK:
 continue;
 case ALOOPER_POLL_ERROR:
 ALOGE("ALOOPER_POLL_ERROR");
 case ALOOPER_POLL_TIMEOUT:
 // timeout (should not happen)
 continue;
 default:
 // should not happen
 ALOGE("Looper::pollOnce() returned unknown status %d", ret);
 continue;
 }
 } while (true);
}
//メッセージはメッセージハンドラ
void MessageBase::handleMessage(const Message&) {
 this->handler();
 barrier.open();
};

一つはVsyncシグナルで、これは登録されたcb_eventReceiverイベント・コールバックを通して処理されます。もう一つはアプリケーション・プロセスやクライアントからのメッセージで、例えばレイヤーの作成要求などです。

frameworks/native/services/surfaceflinger/Client.cpp
status_t Client::createSurface(
 const String8& name,
 uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
 sp<IBinder>* handle,
 sp<IGraphicBufferProducer>* gbp)
{
 class MessageCreateLayer : public MessageBase {// messagbase
 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),
 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();
}
Read next

プロキシ - オブジェクトにインターセプトのレイヤーを追加する

プロキシはブローカーとして動作し、外部からのオブジェクトへのアクセスは、まずこのブローカーによってインターセプトされなければなりません。 つまり、プロキシを動作させるには、対象のオブジェクトではなく、 プロキシのインスタンスに対して操作しなければなりません。 さて、プロキシについて少し.

Apr 7, 2020 · 4 min read