Android Q入力イベント関連表示装置


イベント関連表示デバイスの入力
inputeventのdisplayIdはどうやって来ましたか?この記事ではdisplayidとInputeventの関係を紹介します.DisplayはDisplayManagerServiceが管理しています.DMSから始めます.
管理サービスの表示(DisplayManagerService)
  • 画面が追加されるとDMSはMSGを送信します.REQUEST_TRAVERSALのHandleメッセージ.このメッセージは、DMSが保有するWMSのローカルサービスを介して、WMSのrequestTraversal()を呼び出すことを意味する.
  • WMSウィンドウを巡回するとDMSのperformTraversalInternalメソッドが呼び出され、WMSのapplySurfaceChangesTransaction()メソッドによって呼び出されます.
  • DMSは、viewportを含む各デバイスの情報を構成する.詳しくはconfigureDisplayLocked()、populateViewportLocked()を参照してください.
  •  // Update the corresponding viewport.
    if ((info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
        viewportType = VIEWPORT_INTERNAL;
    } else if (info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
        viewportType = VIEWPORT_EXTERNAL;
    } else if (info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL
            && !TextUtils.isEmpty(info.uniqueId)) {
        viewportType = VIEWPORT_VIRTUAL;
    } else {
        Slog.i(TAG, "Display " + info + " does not support input device matching.");
        return;
    }
    
    //    ViewPort    device   uniqueId,   event    displayID。
    private void populateViewportLocked(int viewportType, int displayId, DisplayDevice device, String uniqueId) {
            final DisplayViewport viewport = getViewportLocked(viewportType, uniqueId);
            device.populateViewportLocked(viewport);
            viewport.valid = true;
            viewport.displayId = displayId;//  Displayid.
        }
        
    public final void populateViewportLocked(DisplayViewport viewport) {
            viewport.orientation = mCurrentOrientation;
    
            if (mCurrentLayerStackRect != null) {
                viewport.logicalFrame.set(mCurrentLayerStackRect);
            } else {
                viewport.logicalFrame.setEmpty();
            }
    
            if (mCurrentDisplayRect != null) {
                viewport.physicalFrame.set(mCurrentDisplayRect);
            } else {
                viewport.physicalFrame.setEmpty();
            }
    
            boolean isRotated = (mCurrentOrientation == Surface.ROTATION_90
                    || mCurrentOrientation == Surface.ROTATION_270);
            DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
            viewport.deviceWidth = isRotated ? info.height : info.width;
            viewport.deviceHeight = isRotated ? info.width : info.height;
    
            viewport.uniqueId = info.uniqueId;
    
            if (info.address instanceof DisplayAddress.Physical) {
                viewport.physicalPort = ((DisplayAddress.Physical) info.address).getPort();
            } else {
                viewport.physicalPort = null;
            }
        }
    
  • DMSはMSGを送信します.UPDATE_VIEWPORTメッセージはviewportを設定し、performTraversalLocked()を参照してください.
  • IMSのローカルサービスは、これらのviewport情報をJNI層に伝達する.
  • 最終nativeレイヤは、viewport情報をグローバルInputReader Configurationに保存する構成をリフレッシュします.詳細はrequestRefreshConfiguration()を参照してください.

  • 初期化時のプロファイルの解析
    このプロファイルは、idcの下に配置され、デバイス名で命名されたidcファイルです.
    オフィシャルゲート
  • プロファイルを解析するタイミング.
  • // frameworks/native/services/inputflinger/EventHub.cpp
    status_t EventHub::openDeviceLocked(const char* devicePath) {
    
        ... ...
        Device* device = new Device(fd, deviceId, devicePath, identifier);
        // Load the configuration file for the device.
        loadConfigurationLocked(device);
        
        // Determine whether the device is external or internal.
        if (isExternalDeviceLocked(device)) {
            device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
        }
        ... ...
    }
    
  • プロファイルを具体的に解析する機能関数
  • void EventHub::loadConfigurationLocked(Device* device) {
        //     
        device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
                device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
        if (device->configurationFile.empty()) {
            ALOGD("No input device configuration file found for device '%s'.",
                    device->identifier.name.c_str());
        } else {
            //        configuration。
            status_t status = PropertyMap::load(String8(device->configurationFile.c_str()),
                    &device->configuration);
            if (status) {
                ALOGE("Error loading input device configuration file for device '%s'.  "
                        "Using default configuration.",
                        device->identifier.name.c_str());
            }
        }
    }
    
  • odm、vendor、Systemからファイルが保存されているかどうかを検索します.
  • std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
            const InputDeviceIdentifier& deviceIdentifier,
            InputDeviceConfigurationFileType type) {
        if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
            if (deviceIdentifier.version != 0) {
                // Try vendor product version.
                std::string versionPath = getInputDeviceConfigurationFilePathByName(
                        StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
                                deviceIdentifier.vendor, deviceIdentifier.product,
                                deviceIdentifier.version),
                        type);
                if (!versionPath.empty()) {
                    return versionPath;
                }
            }
    
            // Try vendor product.
            std::string productPath = getInputDeviceConfigurationFilePathByName(
                    StringPrintf("Vendor_%04x_Product_%04x",
                            deviceIdentifier.vendor, deviceIdentifier.product),
                    type);
            if (!productPath.empty()) {
                return productPath;
            }
        }
    
        // Try device name.
        return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
    }
    
    std::string getInputDeviceConfigurationFilePathByName(
            const std::string& name, InputDeviceConfigurationFileType type) {
        // Search system repository.
        std::string path;
    
        // Treblized input device config files will be located /odm/usr or /vendor/usr.
        const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
        for (size_t i = 0; i < size(rootsForPartition); i++) {
            if (rootsForPartition[i] == nullptr) {
                continue;
            }
            path = rootsForPartition[i];
            path += "/usr/";
            appendInputDeviceConfigurationFileRelativePath(path, name, type);
            if (!access(path.c_str(), R_OK)) {
                return path;
            }
        }
    
        // Search user repository.
        // TODO Should only look here if not in safe mode.
        path = "";
        char *androidData = getenv("ANDROID_DATA");
        if (androidData != nullptr) {
            path += androidData;
        }
        path += "/system/devices/";
        appendInputDeviceConfigurationFileRelativePath(path, name, type);
        if (!access(path.c_str(), R_OK)) {
            return path;
        }
    
        // Not found.
        return "";
    }
    

    入力ポートと表示ポートの構成
    構成をリフレッシュすると同時に携帯電話のディレクトリ/etc/input-port-associationsを読み取る.xmlの内容で、このファイルは入力ポートと表示ポートの関連関係を構成します.
    コードの詳細はIMSのgetInputPortAssociations()を参照してください.
    // Associations between input ports and display ports
    // The java method packs the information in the following manner:
    // Original data: [{'inputPort1': '1'}, {'inputPort2': '2'}]
    // Received data: ['inputPort1', '1', 'inputPort2', '2']
    
    <ports>
        <port display="0" input="usb-xhci-hcd.0.auto-1.1/input0" />
        <port display="1" input="usb-xhci-hcd.0.auto-1.2/input0" />
    ports>
    

    Googleドキュメントの紹介
    プロファイル解析動作
    // frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
    
    void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
         ... ...
         outConfig->portAssociations.clear();
         //Java    input-port-associations.xml   
        jobjectArray portAssociations = jobjectArray(env->CallStaticObjectMethod(
                gServiceClassInfo.clazz, gServiceClassInfo.getInputPortAssociations));
        if (!checkAndClearExceptionFromCallback(env, "getInputPortAssociations") && portAssociations) {
            jsize length = env->GetArrayLength(portAssociations);
            for (jsize i = 0; i < length / 2; i++) {
                std::string inputPort = getStringElementFromJavaArray(env, portAssociations, 2 * i);
                std::string displayPortStr =
                        getStringElementFromJavaArray(env, portAssociations, 2 * i + 1);
                uint8_t displayPort;
                // Should already have been validated earlier, but do it here for safety.
                bool success = ParseUint(displayPortStr, &displayPort);
                if (!success) {
                    ALOGE("Could not parse entry in port configuration file, received: %s",
                        displayPortStr.c_str());
                    continue;
                }
                outConfig->portAssociations.insert({inputPort, displayPort});//  。
            }
            env->DeleteLocalRef(portAssociations);
        }
        ... ...
    }
    

    表示ポートの割り当て
    void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
         ... ...
         if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
                 // In most situations, no port will be specified.
                mAssociatedDisplayPort = std::nullopt;
                // Find the display port that corresponds to the current input port.
                const std::string& inputPort = mIdentifier.location;
                if (!inputPort.empty()) {
                    const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations;
                    const auto& displayPort = ports.find(inputPort);
                    if (displayPort != ports.end()) {
                        mAssociatedDisplayPort = std::make_optional(displayPort->second);
                    }
                }
            }
         ... ...
    }
    

    ViewPort検索
    ビューポートの検索は、表示ポート、一意の表示ID、表示ポートタイプの3つの側面から検索されます.これらが見つからない場合、displayidは-1、viewtypeはVIEWPORT_を作成します.INTERNALのnewViewポート.
    /**
     * Determine which DisplayViewport to use.
     * 1. If display port is specified, return the matching viewport. If matching viewport not
     * found, then return.
     * 2. If a device has associated display, get the matching viewport by either unique id or by
     * the display type (internal or external).
     * 3. Otherwise, use a non-display viewport.
     */
    std::optional<DisplayViewport> TouchInputMapper::findViewport() {
        if (mParameters.hasAssociatedDisplay) {
            const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
            if (displayPort) {
                // Find the viewport that contains the same port
                std::optional<DisplayViewport> v = mConfig.getDisplayViewportByPort(*displayPort);
                if (!v) {
                    ALOGW("Input device %s should be associated with display on port %" PRIu8 ", "
                            "but the corresponding viewport is not found.",
                            getDeviceName().c_str(), *displayPort);
                }
                return v;
            }
    
            if (!mParameters.uniqueDisplayId.empty()) {
                return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId);
            }
    
            ViewportType viewportTypeToUse;
            if (mParameters.associatedDisplayIsExternal) {
                viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
            } else {
                viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
            }
    
            std::optional<DisplayViewport> viewport =
                    mConfig.getDisplayViewportByType(viewportTypeToUse);
            if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) {
                ALOGW("Input device %s should be associated with external display, "
                        "fallback to internal one for the external viewport is not found.",
                            getDeviceName().c_str());
                viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
            }
    
            return viewport;
        }
    
        DisplayViewport newViewport;
        // Raw width and height in the natural orientation.
        int32_t rawWidth = mRawPointerAxes.getRawWidth();
        int32_t rawHeight = mRawPointerAxes.getRawHeight();
        newViewport.setNonDisplayViewport(rawWidth, rawHeight);
        return std::make_optional(newViewport);
    }