current position:Home>Creation and startup of inputmanagerservice

Creation and startup of inputmanagerservice

2022-01-27 03:44:51 Big stomach porridge

The power of analysis

Recently, I'm making face recognition products , A permanent screen rotation function is realized , This function includes the conversion of touch coordinates . so what , Another customer took a touch screen with abnormal coordinate system , Let me adjust . The adjustment of this coordinate system , In fact, I did a mapping of the coordinate system , In the driver layer, I feel very good. It can be realized , But I didn't choose to implement it in the driver layer , Instead, I want to input native Layer implementation .

In order to meet various needs in the future , I decided to start analyzing the input system . Of course , The whole input system is very complex , I must stand on the shoulders of giants , So I studied teacher Deng Fanping's << In depth understanding of Android volume 3>> Analysis of input system in . Okay , Gossip , Let's get down to business .

This analysis is based on Android 11 Code for , The path of the class used is as follows

frameworks/base/services/java/com/android/server/SystemServer.java frameworks/base/services/core/java/com/android/server/input/InputManagerService.java frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp frameworks/native/services/inputflinger/InputManager.cpp

InputManagerService It's a system Binder service , It's in system_server Start in progress

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
            // ..
            
            // 1.  establish InputManagerService service 
            inputManager = new InputManagerService(context);
            
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            
            // 2.  start-up InputManagerService service 
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            inputManager.start();    
            
            // ...
    }
 Copy code 

Here is just a brief list InputManagerService Create and start code , Actually InputManagerService Also with WindowManagerService and DisplayManagerService There is interaction , But this is another long topic , This series of articles is not intended to analyze this interaction process .

This article will be IMS abbreviation InputManagerService.

establish IMS

So first of all IMS The creation process of

    public InputManagerService(Context context) {
        this.mContext = context;
        //  A background thread Handler
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        //  Read  /vendor/etc/input-port-associations.xml  The contents of the document 
        //  This is a unique function of the platform , Generally, there is no such file 
        mStaticAssociations = loadStaticInputPortAssociations();

        /** When true use the linux /dev/input/event subsystem to detect the switch changes on the headphone/microphone jack. When false use the older uevent framework. */
        //  The acquiescence value is  false
        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);

        //  initialization JNI layer ,mPtr  Point to  JNI  Layer of  NativeInputManager  object 
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        // File used to enable the double touch gesture.
        //  The default value is null 
        String doubleTouchGestureEnablePath = context.getResources().getString(
                R.string.config_doubleTouchGestureEnableFile);
        // null
        mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
            new File(doubleTouchGestureEnablePath);

        //  Provide system_server Interface is used inside the process 
        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
 Copy code 

IMS Constructors , The main thing is to call nativeInit() To initialize the JNI layer , Then register the local interface , For other services to call .

Be careful ,nativeInit() There is a return value , What it returns is a pointer , So what does this pointer point to ?

static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    //  Get the bottom MessageQueue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == nullptr) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    //  establish  NativeInputManager
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);

    //  Return to point  NativeInputManager  Object pointer 
    return reinterpret_cast<jlong>(im);
}
 Copy code 

From the final return value, we can see ,nativeInit() Function returns a pointer , This pointer points to JNI Created by layer NativeInputManager object . therefore , Upper layer InputManagerService Member variables of long mPtr In fact, it points to JNI Layer of NativeInputManager object .

NativeInputManager The declaration and implementation of are placed in com_android_server_input_InputManagerService.cpp in , It also reminds us NativeInputManager It's a JNI Stratoid .

establish NativeInputManager

Now let's look at NativeInputManager The creation process of

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    // 1. Save the upper layer InputManagerService object 
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        // 2.  Initialize some parameters 
        // mLocked  The type is  struct Locked, What's the use of initializing some parameters here ?
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerCapture = false;
        // ADISPLAY_ID_DEFAULT The value is 0, Indicates the default screen 
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;
    // 2. Create and register the underlying services  InputManager
    mInputManager = new InputManager(this, this);
    defaultServiceManager()->addService(String16("inputflinger"),
            mInputManager, false);
}
 Copy code 

establish NativeInputManager The process is divided into three steps .

First step , Through member variables mServiceObj Pointing to the top InputManagerService object . And just , Has been used InputManagerService Member variables of mPrt Yes NativeInputManager. In this way , Upper and JNI The layers pay attention to each other , Can communicate with each other .

The second step , For a type of struct Locked The object of mLocked, Some member variables are initialized .

This struct Locked The design of the structure looks chaotic , So what role does it play ?

The third step , Created the underlying Binder service InputManager, And registered to Service Manager in . We noticed the creation of InputManager Two are used this Parameters , Let's look at the relationship diagram of these two classes

«interface» InputReaderPolicyInterface NativeInputManager -sp<InputManager> mInputManager -jobject mServiceObj «interface» InputDispatcherPolicyInterface «interface» PointerControllerPolicyInterface
«interface» InputManagerInterface InputManager InputManager(const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) «interface» BnInputFlinger

NativeInputManager Realized InputReaderPolicyInterface and InputDispatcherPolicyInterface Two interfaces , and InputManager The constructor just needs these two interfaces .

From the current analysis , We can conclude that the input system Java Layer to JNI Layer to Native Communication diagram of layer

mPtr
mInputManager
mServiceObj
InputManagerService
NativeInputManager
InputManager

JNI Layer of NativeInputManager It's actually a bridge , It's connected Java Layer and the Native layer .

However, this figure does not show InputManager How to communicate up , This is because this function is implemented by its sub modules , Let's look down InputManager The creation process of .

establish InputManager service

From the above code we can see that , establish InputManager The code for the object is as follows

mInputManager = new InputManager(this, this);
 Copy code 

Now let's look at creating InputManager Constructor for

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    // 1.  establish InputDispatcher object , Use  InputDispatcherPolicyInterface  Interface 
    mDispatcher = createInputDispatcher(dispatcherPolicy);


    // 2.  establish InputClassifier object , Use  InputListenerInterface
    mClassifier = new InputClassifier(mDispatcher);

    // 3.  establish InputReader object , Use  InputReaderPolicyInterface  and  InputListenerInterface
    mReader = createInputReader(readerPolicy, mClassifier);
}

sp<InputDispatcherInterface> createInputDispatcher( const sp<InputDispatcherPolicyInterface>& policy) {
    return new android::inputdispatcher::InputDispatcher(policy);
}

sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) {
    return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
 Copy code 

Be careful , From the above analysis, we can see ,InputManager The implementation classes of the two interfaces used by the constructor are NativeInputManager. These two interfaces are not directly InputManager Used by the ,InputDispatcherPolicyInterface By InputDispatcher Used by the , and InputReaderPolicyInterface By InputReader Used by the . therefore InputReader The ability to communicate upward is determined by InputDispatcher and InputReader Realized .

InputManager Created three modules ,InputReader、InputClassifier、InputDispatcher. InputReader In charge of from EventHub Get events in , Then process the event , Send to InputClassfier.InputClassifer Will send the event to InputDispatcher, But it classifies touch events . Last InputDispatcher Distribute events to .

So now we can roughly calculate the relationship diagram of the input system , as follows

EventHub
InputReader
NativeInputManager
InputClassifer
InputDispatcher
InputManagerService

This diagram well reflects the single responsibility principle of design pattern .

EventHub In fact, it only belongs to InputReader, So to dissect the whole input system , We have to dissect them one by one InputReader、InputClassifier、InputDispatcher. The following series of articles will analyze one by one .

start-up IMS

Now I know something about the whole input system , But there seems to be something else ? The system doesn't seem to have started ? The starting point is system_server process .

//  Create input system 
inputManager = new InputManagerService(context);

//  Start the input system 
inputManager.start();
 Copy code 

Now let's see how the whole input system starts !

    public void start() {
        Slog.i(TAG, "Starting input manager");
        // 1. start-up native layer 
        nativeStart(mPtr);

        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);

        // 2. Monitor the database , When the value changes , adopt  native  layer 
        //  monitor Settings.System.POINTER_SPEED, This represents the speed of the finger 
        registerPointerSpeedSettingObserver();
        //  monitor Settings.System.SHOW_TOUCHES, This indicates whether the touch coordinates are displayed on the screen 
        registerShowTouchesSettingObserver();
        //  monitor Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON
        registerAccessibilityLargePointerSettingObserver();
        //  monitor Settings.Secure.LONG_PRESS_TIMEOUT, How many milliseconds does this trigger a long press event 
        registerLongPressTimeoutObserver();
        //  Monitor user switching 
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updatePointerSpeedFromSettings();
                updateShowTouchesFromSettings();
                updateAccessibilityLargePointerFromSettings();
                updateDeepPressStatusFromSettings("user switched");
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

        // 3.  Get value from database , And pass it on to  native  layer 
        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
        updateAccessibilityLargePointerFromSettings();
        updateDeepPressStatusFromSettings("just booted");
    }
 Copy code 

InputManagerService Startup time , Will pass first nativeStart() start-up native layer , Then read some values from the database , Pass to native layer .

Read the value from the database and pass it to native, This process is not analyzed . If you analyze the code later , Encountered these values , I'll mention it again .

Now focus your analysis on native On the start of

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    //  call InputManager::start()
    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}
 Copy code 

adopt JNI Layer of NativeInputMangaer This bridge to start InputManager.

The previous picture shows NativeInputManager The bridge function of , Do you feel it now ?

status_t InputManager::start() {
    //  start-up  Dispatcher
    status_t result = mDispatcher->start();
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    //  start-up  InputReader
    result = mReader->start();
    if (result) {
        ALOGE("Could not start InputReader due to error %d.", result);

        mDispatcher->stop();
        return result;
    }

    return OK;
}
 Copy code 

because InputReader Will eventually pass the processed event to InputDispatcher, So start InputManager when , It will start first InputDisapcher, Restart InputReader.

that InputReader and InputDispatcher What did you do after startup ? Let's analyze later .

end

This paper makes a preliminary description of the creation and startup of the input system , But the function of this input system is huge , Fortunately, this function is subdivided in the source code , In this way, we can analyze the functions of each sub module one by one , So as to dissect the whole input system .

copyright notice
author[Big stomach porridge],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/01/202201270344446819.html

Random recommended