In the previous article, we briefly introduced the surfaceflinger service in the surface mechanism of the Android system. The surfaceflinger service is started in the system process and is responsible for unified management of the device's frame buffer. When the surfaceflinger service is started, two threads are created. One thread is used to monitor console events, and the other thread is used to render the system UI. In this article, we will analyze the surfaceflinger service startup process in detail.
We can see from the source code analysis of the previous android process zygote startup process that the system process was started by the zygote process, the main function is the static member function of the systemserver class at the Java layer. Therefore, we will start from the static member function main of the systemserver class to analyze the Startup Process of the surfaceflinger service, as shown in figure 1.
Figure 1 surfaceflinger Service Startup Process
The START process of surfaceflinger service can be divided into eight steps. Next we will analyze each step in detail.
Step 1. systemserver. Main
public class SystemServer{ ...... native public static void init1(String[] args); public static void main(String[] args) { ...... System.loadLibrary("android_servers"); init1(args); } ......}
This function is defined in the file frameworks/base/services/Java/COM/Android/Server/systemserver. java.
The static member function main of the systemserver class first loads the android_servers library into the system process, and then calls another static member function init1 to start system services implemented in C ++.
The static member function init1 of the systemserver class is a JNI method, which is implemented by the C ++ layer function android_server_systemserver_init1. Next we will continue to analyze its implementation.
Step 2. systemserver. init1
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz){ system_init();}
This function is defined in the file frameworks/base/services/JNI/com_android_server_systemserver.cpp.
The static member function init1 of the systemserver class calls another function system_init to start system services implemented in the C ++ language, its implementation is in the file frameworks/base/cmds/system_server/library/system_init.cpp, as shown below:
extern "C" status_t system_init(){ LOGI("Entered system_init()"); sp<ProcessState> proc(ProcessState::self()); ...... char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsurfaceflinger", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { // Start the SurfaceFlinger SurfaceFlinger::instantiate(); } ...... if (proc->supportsProcesses()) { LOGI("System server: entering thread pool.\n"); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOGI("System server: exiting thread pool.\n"); } return NO_ERROR;}
The function first obtains a processstate Singleton in the system process and stores it in the variable Proc. It will call its member function supportsprocesses to determine whether the system supports the inter-process communication mechanism of the binder. We know that in the Android system, every process that requires the binder inter-process communication mechanism has a processstate Singleton, which is used to establish a connection with the binder driver, for details, refer to the source code analysis of the server startup process in the binder of the Process Communication (IPC) mechanism of the Android system.
The function then checks whether there is an attribute named "system_init.startsurfaceflinger" in the system. If it exists, obtain the value and save it in the probuf buffer. If it does not exist, the property_get function sets the value of probuf in the buffer zone to "1 ". When the probuf value in the buffer zone is equal to "1", it indicates that the surfaceflinger service needs to be started in the system process. This is achieved by calling the static member function instantiate of the surfaceflinger class.
The function finally checks whether the system supports the binder inter-process communication mechanism. If yes, the startthreadpool function of the processstate Singleton in the current process will be called to start a binder thread pool, the ipcthreadstate Singleton in the current thread is called to add the current thread to the binder thread pool started earlier. We can see from two articles: source code analysis of the previous Android system process zygote Startup Process and source code analysis of the Android Application Process startup process. Before the system process initializes the Runtime library, the member function startthreadpool of the processstate Singleton in the current process has been called to start the binder thread pool. Therefore, the current thread is actually added to the binder thread pool. With this binder thread pool, the surfaceflinger service can provide services for other components or processes in the system after it is started.
Assuming that the system has an attribute named "system_init.startsurfaceflinger" and its value is equal to "1", we will continue to analyze the implementation of instantiate, a static member function of the surfaceflinger class, this helps you understand the Startup Process of surfaceflinger. Because the static member function instantiate of the surfaceflinger class inherits from the binderservice of the parent class, what we need to analyze next is the implementation of the static member function instantiate of the binderservice class.
Step 3. binderservice. instantiate
template<typename SERVICE>class BinderService{public: ...... static void instantiate() { publish(); } ......};
This function is defined in the file frameworks/base/include/binder/binderservice. h.
The implementation of the static member function instantiate of the binderservice class is very simple. It only calls another static member function publish of the binderservice class to continue to start the surfaceflinger service.
Step 4. binderservice. Publish
template<typename SERVICE>class BinderService{public: static status_t publish() { sp<IServiceManager> sm(defaultServiceManager()); return sm->addService(String16(SERVICE::getServiceName()), new SERVICE()); } ......};
This function is defined in the file frameworks/base/include/binder/binderservice. h.
Binderservice is a template class, which has a template parameter service. When the binderservice class is inherited by the surfaceflinger class, the value of the template parameter service is equal to that of surfaceflinger. Therefore, the static member function publish of the binderservice class is used to create a surfaceflinger instance to serve as the surfaceflinger service of the system and register the service to the Service Manager, in this way, other components or processes in the system can use service manager to obtain the binder proxy object of the surfaceflinger service and then use the services it provides. For the registration process of service objects in the binder inter-process communication mechanism, refer to the source code analysis of the server startup process in the Android system inter-process communication (IPC) mechanism.
Next, we will continue to analyze the surfaceflinger service creation process.
Step 5. New surfaceflinger
SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), ......{ init();}
This function is defined in the file frameworks/base/services/surfaceflinger. cpp.
The surfaceflinger class inherits the bnsurfacecomposer class, which is a local binder class that implements the isurfacecomposer interface. In addition, the surfaceflinger class inherits the Thread class, which is used to create a thread, this thread is the UI rendering thread mentioned in the surfaceflinger service brief introduction and learning plan of the surface mechanism of the Android system. Its thread execution body function is the threadloop member function of the surfaceflinger class. Later, when we analyze the surfaceflinger service rendering UI process, we will analyze the implementation of the member function threadloop of the surfaceflinger class. Note: When the surfaceflinger parent class thread is initialized, the input parameter is false, indicating that the UI rendering thread of surfaceflinger service should not be started before it is started.
During the creation process, the surfaceflinger service calls the surfaceflinger class member function init to perform initialization. Next, we will continue to analyze its implementation.
Step 6. surfaceflinger. init
void SurfaceFlinger::init(){ LOGI("SurfaceFlinger is starting"); // debugging stuff... char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); property_get("debug.sf.showbackground", value, "0"); mDebugBackground = atoi(value); LOGI_IF(mDebugRegion, "showupdates enabled"); LOGI_IF(mDebugBackground, "showbackground enabled");}
This function is defined in the file frameworks/base/services/surfaceflinger. cpp.
The implementation of the surfaceflinger class member function init is very simple. It obtains the two names in the system as "debug. SF. showupdates and debug. SF. showbackground "attribute values are stored in the member variables mdebugregion and mdebugbackground of surfaceflinger class respectively. These two member variables are related to debugging, and we don't care about them.
After this step is completed, return to the previous step 4, that is, the static member function publish of the binderservice class, at this time, a surfaceflinger instance created in step 5 in the previous step will be registered in Service Manager, which is implemented by calling the addservice member function of the binder proxy object of Service Manager. Because the second parameter of addservice, a member function of the binder proxy object of Service Manager, is a strongly pointer reference of ibinder type. According to the analysis of the implementation principle of the smart pointer (lightweight pointer, strong pointer, and weak pointer) in the Android system, when an object is referenced by a strong pointer for the first time, the onfirstref function of this object will be called. Therefore, the onfirstref member function of the surfaceflinger instance created earlier will be called to continue initialization.
Step 7. surfaceflinger. onfirstref
void SurfaceFlinger::onFirstRef(){ run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY); // Wait for the main thread to be done with its initialization mReadyToRunBarrier.wait();}
This function is defined in the file frameworks/base/services/surfaceflinger. cpp.
The function first calls the member function run inherited from the parent class to start a thread named "surfaceflinger" in seconds to execute the UI rendering operation. This is what we call the UI rendering thread. After this UI rendering thread is created, it will first call the surfaceflinger class member function readytorun to execute some initialization operations, and then recycle and call the surfaceflinger class member function threadloop as the thread's execution body.
Mreadytorunbarrier is a member variable of the surfaceflinger class. Its type is barrier. It is used to describe a barrier and is implemented through conditional variables. We can regard it as a thread synchronization tool, that is, blocking the current thread until the UI rendering thread of the surfaceflinger service completes initialization.
Next, we will continue to analyze the implementation of the surfaceflinger class member function readytorun to understand the initialization process of the surfaceflinger service UI rendering thread.
Step 8. surfaceflinger. oreadytorun
This function is defined in the frameworks/base/services/surfaceflinger. cpp file to initialize the UI rendering thread of the surfaceflinger service. We will read it in segments:
status_t SurfaceFlinger::readyToRun(){ LOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); // we only support one display currently int dpy = 0; { // initialize the main display GraphicPlane& plane(graphicPlane(dpy)); DisplayHardware* const hw = new DisplayHardware(this, dpy); plane.setDisplayHardware(hw); }
This code first creates a displayhardware object HW to describe the display of the device, and uses this displayhardware object to initialize the first element of a graphicplane array described by mgraphicplanes, a member variable of the surfaceflinger class. When the displayhardware object HW is created, another thread is created to monitor console events, that is, to monitor the sleep and wakeup events in the hardware frame buffer. In the next article, we will see how the surfaceflinger Service manages the hardware frame buffer.
Next we will read the code:
// create the shared control-block mServerHeap = new MemoryHeapBase(4096, MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap"); LOGE_IF(mServerHeap==0, "can't create shared memory dealer"); mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); LOGE_IF(mServerCblk==0, "can't get to shared control block's address"); new(mServerCblk) surface_flinger_cblk_t;
This code first creates a 4096-kb anonymous shared memory, and then structured this anonymous shared memory into a surface_flinger_cblk_t object for access. The surface_flinger_cblk_t object is stored in the member variable mservercblk of the surfaceflinger class.
This anonymous shared memory is used to save the property information of the device display, such as the width, height, density, and the number of frames per second. Later we will see the initialization process of this anonymous shared memory. Why does the anonymous shared memory be used to save the property information of the device display screen? This is to facilitate the transfer of this information to other processes in the system for access. Other processes in the system can obtain the anonymous shared memory content by calling the member function getcblk of the proxy object of surfaceflinger service.
Next we will read the code:
// initialize primary screen // (other display should be initialized in the same manner, but // asynchronously, as they could come and go. None of this is supported // yet). const GraphicPlane& plane(graphicPlane(dpy)); const DisplayHardware& hw = plane.displayHardware(); const uint32_t w = hw.getWidth(); const uint32_t h = hw.getHeight(); const uint32_t f = hw.getFormat(); hw.makeCurrent();
This code first obtains the first element of a graphicplane array described by the surfaceflinger class member variable mgraphicplanes, and then sets its width, length, and pixel format, finally, call the member function makecurrent of the displayhardware object HW in it to use it as the main display screen of the system. This displayhardware object HW was created in the first code. During the creation process, it will perform some initialization operations. After setting it as the main display of the system, then you can render the system UI on it. In the next article, we will introduce how the surfaceflinger Service manages the hardware frame buffer, and then analyze the implementation of the member function makecurrent of the displayhardware class.
Continue to read the code:
// initialize the shared control block mServerCblk->connected |= 1<<dpy; display_cblk_t* dcblk = mServerCblk->displays + dpy; memset(dcblk, 0, sizeof(display_cblk_t)); dcblk->w = plane.getWidth(); dcblk->h = plane.getHeight(); dcblk->format = f; dcblk->orientation = ISurfaceComposer::eOrientationDefault; dcblk->xdpi = hw.getDpiX(); dcblk->ydpi = hw.getDpiY(); dcblk->fps = hw.getRefreshRate(); dcblk->density = hw.getDensity();
This code saves the attribute information of the system primary display in an anonymous shared memory created earlier, so that the attribute information of the system primary display can be returned to other processes in the system for access.
Let's continue to read the code:
// Initialize OpenGL|ES glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_SCISSOR_TEST); glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_CULL_FACE); const uint16_t g0 = pack565(0x0F,0x1F,0x0F); const uint16_t g1 = pack565(0x17,0x2f,0x17); const uint16_t textureData[4] = { g0, g1, g1, g0 }; glGenTextures(1, &mWormholeTexName); glBindTexture(GL_TEXTURE_2D, mWormholeTexName); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, w, h, 0, 0, 1);
This code is used to initialize the OpenGL library, because the surfaceflinger service renders the system UI through the APIS provided by the OpenGL library. Here we will not detail the initialization process of the OpenGL library. If you are interested, refer to the official website: http://cn.kh?s.org /.
Let's continue to read the last code:
LayerDim::initDimmer(this, w, h); mReadyToRunBarrier.open(); /* * We're now ready to accept clients... */ // start boot animation property_set("ctl.start", "bootanim"); return NO_ERROR;}
This Code does three things.
The first thing is to call the static member function initdimmer of the layerdim class to initialize the layerdim class. The layerdim class is used to describe a surface with a color gradient function. This type of surface is different from that of a normal surface. The former is created and rendered based on the latter.
The second thing is to call the member variable mreadytorunbarrier of the surfaceflinger class to tell the main thread of the system process, that is, the thread waiting in the previous step 7, the UI rendering thread of surfaceflinger service has been created and initialized. At this time, the main thread of the system process can continue to execute other operations.
The third thing is to call the property_set function to set the system attribute called "CTL. Start" and set its value to "bootanim ". The following is an analysis of the boot screen display process of the Android system. start is a control attribute of the Android system. When its value is "bootanim", it indicates that the boot animation of the Android system is to be started. From this we can see that when we see the boot animation of the Android system, it means that the surfaceflinger service of the Android system has been started.
So far, we have analyzed the process of starting the surfaceflinger service. There are two important points in the analysis process: the first is the creation and initialization of the system's main display, and the second is the execution process of the UI rendering thread. In the next article, we will analyze the first knowledge point in detail. In the process of analyzing the first knowledge point, it involves the creation process of the console event monitoring thread of the surfaceflinger service. Therefore, combined with the binder thread mentioned in step 2, as well as the UI rendering thread mentioned in Step 7, we will comprehensively describe the thread collaboration model of surfaceflinger service in the second article. With the basic knowledge above, we will analyze the second knowledge point in the next article. Stay tuned!
Lao Luo's Sina Weibo: http://weibo.com/shengyangluo. welcome to the attention!