Análisis del proceso del complemento del auricular Android Framework Audio Subsystem (09)

Esta serie de artículos enlace Maestro: sub-directorio temático Android Framework Subsistema de audio


Resumen y descripción de puntos clave en este capítulo:

Este capítulo se centra principalmente en ➕ la conexión y desconexión de los auriculares en la esquina superior izquierda del mapa mental anterior. Este capítulo analiza principalmente el proceso de enchufar y desenchufar los auriculares. Después de enchufar y desenchufar los auriculares, cómo se maneja Android en la capa de marco. Al mismo tiempo, este capítulo hace referencia al subsistema de entrada que es relativamente sencillo de escribir. Para obtener más información, consulte el enlace del tema del subsistema de entrada: directorio de subcategoría de temas Subsistema de entrada del Marco de Android

Para conectar y desconectar los auriculares, Android tiene dos modos: puede usar el subsistema de entrada o el estado dev (uevent) para informar sobre las operaciones de conexión y desconexión. Las instrucciones son las siguientes:

  • Subsistema de entrada: puede informar eventos clave o cambiar eventos (EV_SW). Los tipos de eventos incluyen auriculares, auriculares y lineOut. Para los dispositivos de entrada, debe especificar el EV_SYN que puede generar eventos de sincronización. Para los eventos clave, el subsistema de entrada también necesita establecer el rango de valores clave, pero no es necesario configurarlo para los eventos del interruptor.
  • Cambiar el subsistema de clase: envíe datos al espacio del usuario a través de uevent. Hay un hilo en Android que escucha tales eventos. Cuando se usa el subsistema dev de switch, el nombre debe establecerse en "h2w", y el sistema Android escucha el dispositivo virtual / sys / class / switch / h2w.

La operación específica depende del valor de configuración config_useDevInputEventForAudioJack, que se define en el archivo config.xml de la siguiente manera:

...  
    <!-- 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. -->
    <bool name="config_useDevInputEventForAudioJack">false</bool>
...

Cuando el valor es verdadero, se usa el subsistema de entrada, y cuando es falso, se usa el mecanismo de evento. Este valor se define en el siguiente archivo, y este último sobrescribirá el anterior:

frameworks/base/core/res/res/values/config.xml
device/"平台厂商"/frameworks/base/core/res/res/values/config.xml

A continuación, analizaremos los dos modos: la primera mitad de los dos modos son inconsistentes y la segunda mitad es la misma. El proceso principal es analizar dicho proceso: cómo el complemento de auriculares subyacente informa el evento capa por capa y finalmente transmite el mensaje a través de ActivityManagerService.


1 La primera mitad del análisis (dos modos para el método updateLocked en WiredAccessoryManager)

1.1 El proceso de usar el subsistema de entrada (desde el subsistema de entrada al método updateLocked en WiredAccessoryManager)

El subsistema de entrada comienza a leer eventos y procesarlos a través de InputReader. El código es el siguiente:

void InputReader::loopOnce() {
    //...
    //获取事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    { // acquire lock
        //...
        //处理事件
        processEventsLocked(mEventBuffer, count);
        //...
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }
    mQueuedListener->flush();
}

El hilo InputReader usa el método getEvent en EventHub para obtener el evento del controlador y luego usa processEventsLocked para iniciar el procesamiento. ProcessEventsLocked se implementa de la siguiente manera:

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
    for (const RawEvent* rawEvent = rawEvents; count;) {
        int32_t type = rawEvent->type;
        size_t batchSize = 1;
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
            //...
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else {
            //...
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

Continúe analizando la implementación de processEventsForDeviceLocked aquí, el código es el siguiente:

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    //...
    InputDevice* device = mDevices.valueAt(deviceIndex);
    //...
    device->process(rawEvents, count);
}

Continúe analizando el método de proceso InputDevice, el código es el siguiente:

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        if (mDropUntilNextSync) {
            //...
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            //...
        } else {
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

Para el evento swicth, el mapa aquí es SwitchInputMapper, y su función de proceso se implementa de la siguiente manera:

void SwitchInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_SW:
        processSwitch(rawEvent->code, rawEvent->value);
        break;

    case EV_SYN:
        if (rawEvent->code == SYN_REPORT) {
            sync(rawEvent->when);
        }
    }
}

Continúe analizando processSwitch, el código es el siguiente:

void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
    if (switchCode >= 0 && switchCode < 32) {
        if (switchValue) {
            mSwitchValues |= 1 << switchCode;
        } else {
            mSwitchValues &= ~(1 << switchCode);
        }
        mUpdatedSwitchMask |= 1 << switchCode;
    }
}

Aquí es principalmente para almacenar el estado a través del valor de mSwitchValues, continuamos analizando la implementación de la sincronización, el código es el siguiente:

void SwitchInputMapper::sync(nsecs_t when) {
    if (mUpdatedSwitchMask) {
        uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
        NotifySwitchArgs args(when, 0, updatedSwitchValues, mUpdatedSwitchMask);
        getListener()->notifySwitch(&args);
        mUpdatedSwitchMask = 0;
    }
}

El getListener () -> notifySwitch (& args) aquí es en realidad el método notifySwitch de InputDispatcher. La implementación del código es la siguiente:

void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;
    mPolicy->notifySwitch(args->eventTime,
            args->switchValues, args->switchMask, policyFlags);
}

El mPolicy-> notifySwitch aquí eventualmente llamará al método notifySwitch en InputManagerService de la capa Java después de la devolución de llamada de JNI. El código es el siguiente:

// Native callback.
private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
    if ((switchMask & SW_LID_BIT) != 0) {
        final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
        mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
    }

    if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
        final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
        mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
    }
    //mUseDevInputEventForAudioJack在这里被配置成true,会走该分支
    if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
        mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
                switchMask);
    }
}

Continúe analizando notifyWiredAccessoryChanged aquí, la implementación del código es la siguiente:

@Override
public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) {
    synchronized (mLock) {
        int headset;
        mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
        switch (mSwitchValues &
            (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT)) {
            case 0:
                headset = 0;
                break;

            case SW_HEADPHONE_INSERT_BIT:
                headset = BIT_HEADSET_NO_MIC;
                break;

            case SW_LINEOUT_INSERT_BIT:
                headset = BIT_LINEOUT;
                break;

            case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
                headset = BIT_HEADSET;
                break;

            case SW_MICROPHONE_INSERT_BIT:
                headset = BIT_HEADSET;
                break;

            default:
                headset = 0;
                break;
        }
        updateLocked(NAME_H2W,
            (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);
    }
}

El método updateLocked se llama aquí. El siguiente análisis continuará en la segunda mitad del análisis.

1.2 El proceso de usar el mecanismo uevent (desde uevent hasta el método updateLocked en WiredAccessoryManager)

La creación y el uso de WiredAccessoryManager en startOtherServices en systemserver son los siguientes:

private void startOtherServices() {
    final Context context = mSystemContext;
	//...
        if (!disableMedia) {
            try {
                //关键点1
                inputManager.setWiredAccessoryCallbacks(
                        new WiredAccessoryManager(context, inputManager));
            } catch (Throwable e) {
                reportWtf("starting WiredAccessoryManager", e);
            }
        }
	//...
	final InputManagerService inputManagerF = inputManager;
	//...
	try {
		//关键点2
		if (inputManagerF != null) inputManagerF.systemRunning();
	} catch (Throwable e) {
		reportWtf("Notifying InputManagerService running", e);
	}
	//...
}

@ 1 WiredAccessoryManager creado

El código de constructor de WiredAccessoryManager se implementa de la siguiente manera:

public WiredAccessoryManager(Context context, InputManagerService inputManager) {
    //这里涉及三个服务:电源子系统、输入输出子系统、音频子系统
    PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");
    mWakeLock.setReferenceCounted(false);
    mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    mInputManager = inputManager;
    mUseDevInputEventForAudioJack =
            context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
    mObserver = new WiredAccessoryObserver();
}

El WiredAccessoryObserver hereda la clase UEventObserver, UEventObserver está vacío y el código del constructor del WiredAccessoryObserver es el siguiente:

public WiredAccessoryObserver() {
    mUEventInfo = makeObservedUEventList();
}

Aquí el código de makeObservedUEventList se implementa de la siguiente manera:

private List<UEventInfo> makeObservedUEventList() {
    List<UEventInfo> retVal = new ArrayList<UEventInfo>();
    UEventInfo uei;

    //这里只监听这三个UEventInfo对应的事件,驱动程序通过uevent上报事件也只能上报这三个事件之一
    // Monitor h2w
    if (!mUseDevInputEventForAudioJack) {
                    //用于监听名为"h2w"这个Switch class驱动中创建的虚拟文件                                     
                    //./devices/virtual/switch/h2w
                    //./class/switch/h2w
        uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC, BIT_LINEOUT);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        }
    }

    // Monitor USB
    uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL, 0);
    if (uei.checkSwitchExists()) {
        retVal.add(uei);
    } 
    uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0, 0);
    if (uei.checkSwitchExists()) {
        retVal.add(uei);
    } else {
        uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0, 0);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        }
    }
    return retVal;
}

@ 2 análisis de la función systemRunning () de inputManagerF

El código inputManagerF.systemRunning () se implementa de la siguiente manera:

public void systemRunning() {
    //...
    if (mWiredAccessoryCallbacks != null) {
        mWiredAccessoryCallbacks.systemReady();
    }
}

Aquí el código systemReady se implementa de la siguiente manera:

@Override
public void systemReady() {
    synchronized (mLock) {
        mWakeLock.acquire();
        Message msg = mHandler.obtainMessage(MSG_SYSTEM_READY, 0, 0, null);
        mHandler.sendMessage(msg);
    }
}

El código del controlador para procesar el mensaje MSG_SYSTEM_READY es el siguiente:

private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_NEW_DEVICE_STATE:
                setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
                mWakeLock.release();
                break;
            case MSG_SYSTEM_READY:
                onSystemReady();
                mWakeLock.release();
                break;
        }
    }
};

Aquí llamaremos a onSystemReady, la implementación del código es la siguiente:

private void onSystemReady() {
    if (mUseDevInputEventForAudioJack) {
        int switchValues = 0;
        if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
            switchValues |= SW_HEADPHONE_INSERT_BIT;
        }
        if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {
            switchValues |= SW_MICROPHONE_INSERT_BIT;
        }
        if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LINEOUT_INSERT) == 1) {
            switchValues |= SW_LINEOUT_INSERT_BIT;
        }
        notifyWiredAccessoryChanged(0, switchValues,
                SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT);
    }
    mObserver.init();
}

Continúe analizando el método init () de mObserver, el código se implementa de la siguiente manera:

void init() {
    //...
    for (int i = 0; i < mUEventInfo.size(); ++i) {
        UEventInfo uei = mUEventInfo.get(i);
        startObserving("DEVPATH="+uei.getDevPath());
    }
}

Continúe analizando startObservando aquí, la implementación del código es la siguiente:

public final void startObserving(String match) {
    final UEventThread t = getThread();
    t.addObserver(match, this);
}

Continúe observando la implementación de getThread, el código es el siguiente:

private static UEventThread getThread() {
    synchronized (UEventObserver.class) {
        if (sThread == null) {
            sThread = new UEventThread();
            sThread.start();
        }
        return sThread;
    }
}

Cuando se ejecuta start aquí, se llamará al método de ejecución de UEventThread, y la implementación del código es la siguiente:

public void run() {
    nativeSetup();
    while (true) {
        //...
        //等待事件,native层实现,从系统底层接收消息
        String message = nativeWaitForNextEvent();
        if (message != null) {
            //发送消息
            sendEvent(message);
        }
    }
}

El envío de mensajes se implementa de la siguiente manera:

private void sendEvent(String message) {
    //...
    if (!mTempObserversToSignal.isEmpty()) {
        final UEvent event = new UEvent(message);
        final int N = mTempObserversToSignal.size();
        for (int i = 0; i < N; i++) {
            final UEventObserver observer = mTempObserversToSignal.get(i);
            observer.onUEvent(event);
        }
        mTempObserversToSignal.clear();
    }
}

Continúe analizando la implementación del método onUEvent (...) del observador, que está vacío. La implementación de la subclase WiredAccessoryObserver se llamará aquí. El código es el siguiente:

@Override
public void onUEvent(UEventObserver.UEvent event) {
    try {
        String devPath = event.get("DEVPATH");
        String name = event.get("SWITCH_NAME");
        int state = Integer.parseInt(event.get("SWITCH_STATE"));
        synchronized (mLock) {
            updateStateLocked(devPath, name, state);
        }
    } catch (NumberFormatException e) {
        Slog.e(TAG, "Could not parse switch state from event " + event);
    }
}

Continúe analizando updateStateLocked, la implementación del código es la siguiente:

private void updateStateLocked(String devPath, String name, int state) {
    for (int i = 0; i < mUEventInfo.size(); ++i) {
        UEventInfo uei = mUEventInfo.get(i);
        if (devPath.equals(uei.getDevPath())) {
            updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));
            return;
        }
    }
}

El método updateLocked se llama aquí. El siguiente análisis continuará en la segunda mitad del análisis.


2 La segunda mitad del análisis (desde el método updateLocked en WiredAccessoryManager hasta el ActivityManagerService superior para enviar transmisiones)

El código de actualización de WiredAccessoryManager se implementa de la siguiente manera:

private void updateLocked(String newName, int newState) {
    //...
    mWakeLock.acquire();
	//获得并发送message
    Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,
            mHeadsetState, newName);
    mHandler.sendMessage(msg);
    mHeadsetState = headsetState;
}

El controlador aquí maneja el mensaje MSG_NEW_DEVICE_STATE de la siguiente manera:

private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case MSG_NEW_DEVICE_STATE:
            setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
            mWakeLock.release();
            break;
        case MSG_SYSTEM_READY:
            onSystemReady();
            mWakeLock.release();
            break;
    }
}

Enfóquese en la implementación de setDevicesState aquí, el código es el siguiente:

private void setDevicesState(
        int headsetState, int prevHeadsetState, String headsetName) {
    synchronized (mLock) {
        int allHeadsets = SUPPORTED_HEADSETS;
        for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
            if ((curHeadset & allHeadsets) != 0) {
                setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
                allHeadsets &= ~curHeadset;
            }
        }
    }
}

Aquí le preocupa la implementación de setDeviceStateLocked, el código es el siguiente:

private void setDeviceStateLocked(int headset,
        int headsetState, int prevHeadsetState, String headsetName) {
    if ((headsetState & headset) != (prevHeadsetState & headset)) {
        int outDevice = 0;
        int inDevice = 0;
        int state;

        if ((headsetState & headset) != 0) {
            state = 1;
        } else {
            state = 0;
        }

        if (headset == BIT_HEADSET) {
            outDevice = AudioManager.DEVICE_OUT_WIRED_HEADSET;
            inDevice = AudioManager.DEVICE_IN_WIRED_HEADSET;
        } else if (headset == BIT_HEADSET_NO_MIC){
            outDevice = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
        } else if (headset == BIT_LINEOUT){
            outDevice = AudioManager.DEVICE_OUT_LINE;
        } else if (headset == BIT_USB_HEADSET_ANLG) {
            outDevice = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
        } else if (headset == BIT_USB_HEADSET_DGTL) {
            outDevice = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
        } else if (headset == BIT_HDMI_AUDIO) {
            outDevice = AudioManager.DEVICE_OUT_HDMI;
        } else {
            Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
            return;
        }
        if (outDevice != 0) {
          //进入了Audio系统,设置有线设备的连接状态
          mAudioManager.setWiredDeviceConnectionState(outDevice, state, headsetName);
        }
        if (inDevice != 0) {
          mAudioManager.setWiredDeviceConnectionState(inDevice, state, headsetName);
        }
    }
}

Aquí preste atención a la implementación del método setWiredDeviceConnectionState de mAudioManager, el código es el siguiente:

public void setWiredDeviceConnectionState(int device, int state, String name) {
    IAudioService service = getService();
    try {
        service.setWiredDeviceConnectionState(device, state, name);
    } catch (RemoteException e) {
        Log.e(TAG, "Dead object in setWiredDeviceConnectionState "+e);
    }
}

Continúe analizando setWiredDeviceConnectionState, la implementación del código es la siguiente:

public void setWiredDeviceConnectionState(int device, int state, String name) {
    synchronized (mConnectedDevices) {
        int delay = checkSendBecomingNoisyIntent(device, state);
        queueMsgUnderWakeLock(mAudioHandler,
                MSG_SET_WIRED_DEVICE_CONNECTION_STATE,device,state,name,delay);
    }
}

El código queueMsgUnderWakeLock aquí se implementa de la siguiente manera:

private void queueMsgUnderWakeLock(Handler handler, int msg,
        int arg1, int arg2, Object obj, int delay) {
    final long ident = Binder.clearCallingIdentity();
    mAudioEventWakeLock.acquire();
    Binder.restoreCallingIdentity(ident);
    sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
}

El controlador procesa el mensaje MSG_SET_WIRED_DEVICE_CONNECTION_STATE, el código es el siguiente:

@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case MSG_SET_DEVICE_VOLUME:
            setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
            break;
        //...
        case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
            onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
            mAudioEventWakeLock.release();
            break;
        //...
    }
}

La implementación del código de onSetWiredDeviceConnectionState es la siguiente:

private void onSetWiredDeviceConnectionState(int device, int state, String name)
{
    synchronized (mConnectedDevices) {
        //...
        //关键点1:声道切换入口
        handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
        if (state != 0) {
            //...
            if ((device & mSafeMediaVolumeDevices) != 0) {
                sendMsg(mAudioHandler,MSG_CHECK_MUSIC_ACTIVE,SENDMSG_REPLACE,0,0,null,MUSIC_ACTIVE_POLL_PERIOD_MS);
            }
            //...
        } else {
            //...
        }
        if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
            //关键点2:通过AMS上报intent
            sendDeviceConnectionIntent(device, state, name);
        }
    }
}

Desde aquí tenemos dos puntos clave a los que prestar atención, la entrada de cambio de canal handleDeviceConnection y sendDeviceConnectionIntent que informa la intención al AMS. 

@ 1 Continúe analizando handleDeviceConnection, la implementación del código es la siguiente:

private boolean handleDeviceConnection(boolean connected, int device, String params) {
    synchronized (mConnectedDevices) {
        boolean isConnected = (mConnectedDevices.containsKey(device) &&
                (params.isEmpty() || mConnectedDevices.get(device).equals(params)));

        if (isConnected && !connected) {
            AudioSystem.setDeviceConnectionState(device,
                                          AudioSystem.DEVICE_STATE_UNAVAILABLE,
                                          mConnectedDevices.get(device));
             mConnectedDevices.remove(device);
             return true;
        } else if (!isConnected && connected) {
             AudioSystem.setDeviceConnectionState(device,
                                                  AudioSystem.DEVICE_STATE_AVAILABLE,
                                                  params);
             mConnectedDevices.put(new Integer(device), params);
             return true;
        }
    }
    return false;
}

Aquí se llama al método setDeviceConnectionState de AudioSystem, y su relación de mapeo JNI es:

{"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState}

Continúe analizando la implementación de android_media_AudioSystem_setDeviceConnectionState, el código es el siguiente:

static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
{
    const char *c_address = env->GetStringUTFChars(device_address, NULL);
    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
                                          static_cast <audio_policy_dev_state_t>(state),
                                          c_address));
    env->ReleaseStringUTFChars(device_address, c_address);
    return (jint) status;
}

Aquí nos centramos en analizar el setDeviceConnectionState del AudioSystem en la capa Native. La implementación del código es la siguiente:

status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    const char *address = "";
    //...
    if (device_address != NULL) {
        address = device_address;
    }
    return aps->setDeviceConnectionState(device, state, address);
}

Aquí se devuelve el método setDeviceConnectionState de AudioPolicyManager. La implementación del código es la siguiente:

status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
                                                          audio_policy_dev_state_t state,
                                                  const char *device_address)
{
    return setDeviceConnectionStateInt(device, state, device_address);
}

Aquí solo necesitamos saber que el método handleDeviceConnection del AudioService en la capa Java finalmente se puede llamar directamente al setDeviceConnectionStateInt del AudioPolicyManager en la capa Native. Más adelante, interpretaremos específicamente la parte setDeviceConnectionStateInt del código.

@ 2 Continúe analizando sendDeviceConnectionIntent, la implementación del código es la siguiente:

private void sendDeviceConnectionIntent(int device, int state, String name)
{
    //构建一个Intent结构,然后向应用程序广播它,注册对这个Intent感兴趣的App就会收到它
    Intent intent = new Intent();
    intent.putExtra("state", state);
    intent.putExtra("name", name);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    //...
    //intent其他处理
    //...
    try {
        
        ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
    } finally {
        //...
    }
}

En este punto, al construir una estructura de intención y luego transmitirla a la aplicación, la aplicación que esté interesada en la intención la recibirá y se le dará el control a la aplicación. Más tarde, la intención será recibida y procesada en forma de caso.

 

Publicado 289 artículos originales · elogiados 47 · 30,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/vviccc/article/details/105394043
Recomendado
Clasificación